Remove ComponentData, convert two components

- The new way of replacing configs doesn't actually support having ConfigData fields as they can become obsolete
- Fixed KDoc formatting (new lines)
This commit is contained in:
Norbi Peti 2023-05-05 02:48:06 +02:00
parent e610dbc0f6
commit aabc2cd48c
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
14 changed files with 247 additions and 295 deletions

View file

@ -21,7 +21,8 @@ open class Channel
/** /**
* Creates a channel. * Creates a channel.
* *
* @param filterAndErrorMSG Checks all senders against the criteria provided here and sends the message if the index matches the sender's - if no score at all, displays the error.<br></br> * @param filterAndErrorMSG Checks all senders against the criteria provided here and sends the message if the index matches the sender's - if no score at all, displays the error.
*
* May be null to send to everyone. * May be null to send to everyone.
*/( */(
/** /**
@ -86,8 +87,7 @@ open class Channel
} }
/** /**
* Note: Errors are sent to the sender automatically<br></br> * Note: Errors are sent to the sender automatically
*
* *
* Null means don't send * Null means don't send
*/ */

View file

@ -1,115 +1,101 @@
package buttondevteam.core.component.members; package buttondevteam.core.component.members
import buttondevteam.core.MainPlugin; import buttondevteam.core.MainPlugin
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component
import buttondevteam.lib.architecture.ComponentMetadata; import buttondevteam.lib.architecture.ComponentMetadata
import buttondevteam.lib.architecture.ConfigData; import org.bukkit.Statistic
import org.bukkit.Statistic; import org.bukkit.entity.Player
import org.bukkit.entity.Player; import org.bukkit.event.EventHandler
import org.bukkit.event.EventHandler; import org.bukkit.event.Listener
import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.player.PlayerJoinEvent; import java.time.Instant
import java.time.temporal.ChronoUnit
import java.time.Instant; import java.util.*
import java.time.temporal.ChronoUnit;
import java.util.AbstractMap;
import java.util.Date;
import static buttondevteam.core.MainPlugin.permission;
/** /**
* Allows giving a 'member' group over some time elapsed OR played. * Allows giving a 'member' group over some time elapsed OR played.
*/ */
@ComponentMetadata(enabledByDefault = false) @ComponentMetadata(enabledByDefault = false)
public class MemberComponent extends Component<MainPlugin> implements Listener { class MemberComponent : Component<MainPlugin>(), Listener {
/** /**
* The permission group to give to the player * The permission group to give to the player
*/ */
final ConfigData<String> memberGroup = getConfig().getData("memberGroup", "member"); val memberGroup get() = config.getData("memberGroup", "member")
/** /**
* The amount of hours needed to play before promotion * The amount of hours needed to play before promotion
*/ */
private final ConfigData<Integer> playedHours = getConfig().getData("playedHours", 12); private val playedHours get() = config.getData("playedHours", 12)
/** /**
* The amount of days passed since first login * The amount of days passed since first login
*/ */
private final ConfigData<Integer> registeredForDays = getConfig().getData("registeredForDays", 7); private val registeredForDays get() = config.getData("registeredForDays", 7)
private var playtime: Pair<Statistic, Int>? = null
override fun enable() {
registerListener(this)
registerCommand(MemberCommand())
playtime = try {
Pair(Statistic.valueOf("PLAY_ONE_MINUTE"), 60) //1.14
} catch (e: IllegalArgumentException) {
Pair(Statistic.valueOf("PLAY_ONE_TICK"), 20 * 3600) //1.12
}
}
private AbstractMap.SimpleEntry<Statistic, Integer> playtime; override fun disable() {}
@Override @EventHandler
protected void enable() { fun onPlayerJoin(event: PlayerJoinEvent) {
registerListener(this); if (checkNotMember(event.player) && (checkRegTime(event.player) || checkPlayTime(event.player))) {
registerCommand(new MemberCommand()); addPlayerAsMember(event.player)
try { }
playtime = new AbstractMap.SimpleEntry<>(Statistic.valueOf("PLAY_ONE_MINUTE"), 60); //1.14 }
} catch (IllegalArgumentException e) {
playtime = new AbstractMap.SimpleEntry<>(Statistic.valueOf("PLAY_ONE_TICK"), 20 * 3600); //1.12
}
}
@Override fun addPlayerAsMember(player: Player): Boolean? {
protected void disable() { return try {
} if (MainPlugin.permission.playerAddGroup(null, player, memberGroup.get())) {
player.sendMessage("\${ChatColor.AQUA}You are a member now!")
log("Added " + player.name + " as a member.")
true
} else {
logWarn("Failed to assign the member role! Please make sure the member group exists or disable the component if it's unused.")
false
}
} catch (e: UnsupportedOperationException) {
logWarn("Failed to assign the member role! Groups are not supported by the permissions implementation.")
null
}
}
@EventHandler fun checkNotMember(player: Player?): Boolean {
public void onPlayerJoin(PlayerJoinEvent event) { return !MainPlugin.permission.playerInGroup(player, memberGroup.get())
if (checkNotMember(event.getPlayer()) && (checkRegTime(event.getPlayer()) || checkPlayTime(event.getPlayer()))) { }
addPlayerAsMember(event.getPlayer());
}
}
public Boolean addPlayerAsMember(Player player) { fun checkRegTime(player: Player): Boolean {
try { return getRegTime(player) == -1L
if (permission.playerAddGroup(null, player, memberGroup.get())) { }
player.sendMessage("${ChatColor.AQUA}You are a member now!");
log("Added " + player.getName() + " as a member.");
return true;
} else {
logWarn("Failed to assign the member role! Please make sure the member group exists or disable the component if it's unused.");
return false;
}
} catch (UnsupportedOperationException e) {
logWarn("Failed to assign the member role! Groups are not supported by the permissions implementation.");
return null;
}
}
public boolean checkNotMember(Player player) { fun checkPlayTime(player: Player): Boolean {
return permission != null && !permission.playerInGroup(player, memberGroup.get()); return getPlayTime(player) > playtime!!.second * playedHours.get()
} }
public boolean checkRegTime(Player player) { /**
return getRegTime(player) == -1; * Returns milliseconds
} */
fun getRegTime(player: Player): Long {
val date = Date(player.firstPlayed).toInstant().plus(registeredForDays.get().toLong(), ChronoUnit.DAYS)
return if (date.isAfter(Instant.now())) date.toEpochMilli() - Instant.now().toEpochMilli() else -1
}
public boolean checkPlayTime(Player player) { fun getPlayTimeTotal(player: Player): Int {
return getPlayTime(player) > playtime.getValue() * playedHours.get(); return player.getStatistic(playtime!!.first)
} }
/**
* Returns milliseconds
*/
public long getRegTime(Player player) {
Instant date = new Date(player.getFirstPlayed()).toInstant().plus(registeredForDays.get(), ChronoUnit.DAYS);
if (date.isAfter(Instant.now()))
return date.toEpochMilli() - Instant.now().toEpochMilli();
return -1;
}
public int getPlayTimeTotal(Player player) {
return player.getStatistic(playtime.getKey());
}
/**
* Returns hours
*/
public double getPlayTime(Player player) {
double pt = playedHours.get() - (double) getPlayTimeTotal(player) / playtime.getValue();
if (pt < 0) return -1;
return pt;
}
/**
* Returns hours
*/
fun getPlayTime(player: Player): Double {
val pt = playedHours.get() - getPlayTimeTotal(player).toDouble() / playtime!!.second
return if (pt < 0) (-1).toDouble() else pt
}
} }

View file

@ -48,7 +48,7 @@ class RestartComponent : Component<MainPlugin>(), Listener {
/** /**
* Specifies the hour of day when the server should be restarted. Set to -1 to disable. * Specifies the hour of day when the server should be restarted. Set to -1 to disable.
*/ */
private val restartAt = config.getData("restartAt", 12) private val restartAt get() = config.getData("restartAt", 12)
private var lasttime: Long = 0 private var lasttime: Long = 0
var isPlsrestart = false var isPlsrestart = false

View file

@ -1,133 +1,110 @@
package buttondevteam.core.component.spawn; package buttondevteam.core.component.spawn
import buttondevteam.core.MainPlugin; import buttondevteam.core.MainPlugin
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component
import buttondevteam.lib.architecture.ComponentMetadata; import buttondevteam.lib.architecture.ComponentMetadata
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.chat.Command2.Subcommand
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.ICommand2MC
import buttondevteam.lib.chat.ICommand2MC; import com.earth2me.essentials.Trade
import com.earth2me.essentials.Trade; import com.google.common.io.ByteStreams
import com.google.common.io.ByteArrayDataInput; import com.onarandombox.MultiverseCore.MultiverseCore
import com.google.common.io.ByteArrayDataOutput; import org.bukkit.Bukkit
import com.google.common.io.ByteStreams; import org.bukkit.Location
import com.onarandombox.MultiverseCore.MultiverseCore; import org.bukkit.entity.Player
import org.bukkit.Bukkit; import org.bukkit.event.player.PlayerTeleportEvent
import org.bukkit.Location; import org.bukkit.plugin.messaging.PluginMessageListener
import org.bukkit.entity.Player; import java.io.*
import org.bukkit.event.player.PlayerTeleportEvent; import java.math.BigDecimal
import org.bukkit.plugin.messaging.PluginMessageListener;
import java.io.*;
import java.math.BigDecimal;
/** /**
* Provides a /spawn command that works with BungeeCord. Make sure to set up on each server. * Provides a /spawn command that works with BungeeCord. Make sure to set up on each server.
* Requires Multiverse-Core.
*/ */
@ComponentMetadata(enabledByDefault = false) @ComponentMetadata(enabledByDefault = false)
public class SpawnComponent extends Component<MainPlugin> implements PluginMessageListener { class SpawnComponent : Component<MainPlugin>(), PluginMessageListener {
@Override override fun enable() {
protected void enable() { registerCommand(SpawnCommand())
registerCommand(new SpawnCommand()); if (targetServer.get().isEmpty()) {
if (targetServer.get().length() == 0) { spawnloc = MultiverseCore.getPlugin(MultiverseCore::class.java).mvWorldManager.firstSpawnWorld.spawnLocation
spawnloc = MultiverseCore.getPlugin(MultiverseCore.class).getMVWorldManager().getFirstSpawnWorld() }
.getSpawnLocation(); Bukkit.getServer().messenger.registerOutgoingPluginChannel(plugin, "BungeeCord")
} Bukkit.getServer().messenger.registerIncomingPluginChannel(plugin, "BungeeCord", this)
}
Bukkit.getServer().getMessenger().registerOutgoingPluginChannel(getPlugin(), "BungeeCord"); override fun disable() {
Bukkit.getServer().getMessenger().registerIncomingPluginChannel(getPlugin(), "BungeeCord", this); Bukkit.getServer().messenger.unregisterIncomingPluginChannel(plugin, "BungeeCord")
} Bukkit.getServer().messenger.unregisterOutgoingPluginChannel(plugin, "BungeeCord")
}
@Override override fun onPluginMessageReceived(channel: String, player: Player, message: ByteArray) {
protected void disable() { if (channel != "BungeeCord") {
Bukkit.getServer().getMessenger().unregisterIncomingPluginChannel(getPlugin(), "BungeeCord"); return
Bukkit.getServer().getMessenger().unregisterOutgoingPluginChannel(getPlugin(), "BungeeCord"); }
} if (targetServer.get().isNotEmpty()) return
val `in` = ByteStreams.newDataInput(message)
val subchannel = `in`.readUTF()
if ("ChromaCore-Spawn" == subchannel) {
// Use the code sample in the 'Response' sections below to read
// the data.
val len = `in`.readShort()
val msgbytes = ByteArray(len.toInt())
`in`.readFully(msgbytes)
try {
val msgin = DataInputStream(ByteArrayInputStream(msgbytes))
val somedata = msgin.readUTF() // Read the data in the same way you wrote it
if ("SendToSpawn" != somedata) {
println("somedata: $somedata")
return
}
player.teleport(spawnloc!!)
} catch (e: IOException) {
e.printStackTrace()
}
} else println("Subchannel: $subchannel")
}
@Override /**
public void onPluginMessageReceived(String channel, Player player, byte[] message) { * The BungeeCord server that has the spawn. Set to empty if this server is the target.
if (!channel.equals("BungeeCord")) { */
return; private val targetServer get() = config.getData("targetServer", "")
} private var spawnloc: Location? = null
if (targetServer.get().length() != 0)
return;
ByteArrayDataInput in = ByteStreams.newDataInput(message);
String subchannel = in.readUTF();
if ("ChromaCore-Spawn".equals(subchannel)) {
// Use the code sample in the 'Response' sections below to read
// the data.
short len = in.readShort();
byte[] msgbytes = new byte[len];
in.readFully(msgbytes);
try { @CommandClass(helpText = ["Spawn", "Teleport to spawn."])
DataInputStream msgin = new DataInputStream(new ByteArrayInputStream(msgbytes)); inner class SpawnCommand : ICommand2MC() {
String somedata = msgin.readUTF(); // Read the data in the same way you wrote it @Subcommand
if (!"SendToSpawn".equals(somedata)) { fun def(player: Player) {
System.out.println("somedata: " + somedata); if (targetServer.get().isEmpty()) {
return; player.sendMessage("\${ChatColor.AQUA}Teleporting to spawn...")
} try {
player.teleport(spawnloc); if (MainPlugin.ess != null) MainPlugin.ess!!.getUser(player).teleport
} catch (IOException e) { .teleport(spawnloc, Trade(BigDecimal.ZERO, MainPlugin.ess), PlayerTeleportEvent.TeleportCause.COMMAND) else player.teleport(spawnloc!!)
e.printStackTrace(); } catch (e: Exception) {
} player.sendMessage("\${ChatColor.RED}Failed to teleport: $e")
} else }
System.out.println("Subchannel: " + subchannel); return
} }
val out = ByteStreams.newDataOutput()
/** out.writeUTF("Connect")
* The BungeeCord server that has the spawn. Set to empty if this server is the target. out.writeUTF(targetServer.get())
*/ player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray())
private final ConfigData<String> targetServer = getConfig().getData("targetServer", ""); Bukkit.getScheduler().runTask(plugin, Runnable {
//Delay it a bit
private Location spawnloc; val outt = ByteStreams.newDataOutput()
outt.writeUTF("ForwardToPlayer") // So BungeeCord knows to forward it
@CommandClass(helpText = { outt.writeUTF(player.name)
"Spawn", outt.writeUTF("ChromaCore-Spawn") // The channel name to check if this your data
"Teleport to spawn." val msgbytes = ByteArrayOutputStream()
}) val msgout = DataOutputStream(msgbytes)
public class SpawnCommand extends ICommand2MC { try {
@SuppressWarnings("UnstableApiUsage") msgout.writeUTF("SendToSpawn") // You can do anything you want with msgout
@Command2.Subcommand } catch (exception: IOException) {
public void def(Player player) { exception.printStackTrace()
if (targetServer.get().length() == 0) { }
player.sendMessage("${ChatColor.AQUA}Teleporting to spawn..."); outt.writeShort(msgbytes.toByteArray().size)
try { outt.write(msgbytes.toByteArray())
if (MainPlugin.ess != null) player.sendPluginMessage(plugin, "BungeeCord", outt.toByteArray())
MainPlugin.ess.getUser(player).getTeleport() })
.teleport(spawnloc, new Trade(BigDecimal.ZERO, MainPlugin.ess), PlayerTeleportEvent.TeleportCause.COMMAND); }
else }
player.teleport(spawnloc);
} catch (Exception e) {
player.sendMessage("${ChatColor.RED}Failed to teleport: " + e);
}
return;
}
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Connect");
out.writeUTF(targetServer.get());
player.sendPluginMessage(getPlugin(), "BungeeCord", out.toByteArray());
Bukkit.getScheduler().runTask(getPlugin(), () -> { //Delay it a bit
ByteArrayDataOutput outt = ByteStreams.newDataOutput();
outt.writeUTF("ForwardToPlayer"); // So BungeeCord knows to forward it
outt.writeUTF(player.getName());
outt.writeUTF("ChromaCore-Spawn"); // The channel name to check if this your data
ByteArrayOutputStream msgbytes = new ByteArrayOutputStream();
DataOutputStream msgout = new DataOutputStream(msgbytes);
try {
msgout.writeUTF("SendToSpawn"); // You can do anything you want with msgout
} catch (IOException exception) {
exception.printStackTrace();
}
outt.writeShort(msgbytes.toByteArray().length);
outt.write(msgbytes.toByteArray());
player.sendPluginMessage(getPlugin(), "BungeeCord", outt.toByteArray());
});
}
}
} }

View file

@ -35,7 +35,7 @@ abstract class TBMCChatEventBase(
} }
/** /**
* Note: Errors are sent to the sender automatically<br></br> * Note: Errors are sent to the sender automatically
* *
* Null means don't send * Null means don't send
*/ */

View file

@ -83,7 +83,7 @@ abstract class ButtonPlugin : JavaPlugin() {
fun tryReloadConfig(): Boolean { fun tryReloadConfig(): Boolean {
if (!justReload()) return false if (!justReload()) return false
reloadIConfig() reloadIConfig()
componentStack.forEach(Consumer { c -> c.updateComponentData() }) componentStack.forEach(Consumer { c -> c.updateConfig() })
return true return true
} }

View file

@ -18,18 +18,17 @@ import java.util.stream.Collectors
@HasConfig(global = false) //Used for obtaining javadoc @HasConfig(global = false) //Used for obtaining javadoc
abstract class Component<TP : JavaPlugin> { abstract class Component<TP : JavaPlugin> {
var isEnabled = false var isEnabled = false
internal var componentData: ComponentData<TP>? = null
val config get() = componentData!!.config lateinit var config: IHaveConfig
val plugin get() = componentData!!.plugin private set
lateinit var plugin: TP
private set
private val data //TODO private val data //TODO
: IHaveConfig? = null : IHaveConfig? = null
@JvmField val shouldBeEnabled: ConfigData<Boolean>
val shouldBeEnabled: ConfigData<Boolean> = config.getData("enabled", get() = config.getData("enabled", javaClass.getAnnotation(ComponentMetadata::class.java)?.enabledByDefault ?: true)
Optional.ofNullable(javaClass.getAnnotation(ComponentMetadata::class.java)).map { it.enabledByDefault }
.orElse(true))
fun log(message: String) { fun log(message: String) {
plugin.logger.info("[$className] $message") plugin.logger.info("[$className] $message")
@ -58,7 +57,8 @@ abstract class Component<TP : JavaPlugin> {
/** /**
* Enables the module, when called by the JavaPlugin class. Call * Enables the module, when called by the JavaPlugin class. Call
* registerCommand() and registerListener() within this method.<br></br> * registerCommand() and registerListener() within this method.
*
* To access the plugin, use [.getPlugin]. * To access the plugin, use [.getPlugin].
*/ */
protected abstract fun enable() protected abstract fun enable()
@ -121,8 +121,8 @@ abstract class Component<TP : JavaPlugin> {
private val className: String get() = javaClass.simpleName private val className: String get() = javaClass.simpleName
internal fun updateComponentData(plugin: TP = this.plugin) { internal fun updateConfig() {
componentData = ComponentData(plugin, { plugin.saveConfig() }, this.getConfigSection(plugin)) this.config = IHaveConfig(plugin::saveConfig, getConfigSection(plugin))
} }
private fun getConfigSection(plugin: JavaPlugin): ConfigurationSection { private fun getConfigSection(plugin: JavaPlugin): ConfigurationSection {
@ -138,7 +138,7 @@ abstract class Component<TP : JavaPlugin> {
private val _components = HashMap<Class<out Component<*>>, Component<out JavaPlugin>>() private val _components = HashMap<Class<out Component<*>>, Component<out JavaPlugin>>()
/** /**
* Returns the currently registered components<br></br> * Returns the currently registered components
* *
* @return The currently registered components * @return The currently registered components
*/ */
@ -149,9 +149,12 @@ abstract class Component<TP : JavaPlugin> {
} }
/** /**
* Registers a component checking it's dependencies and calling [.register].<br></br> * Registers a component checking it's dependencies and calling [.register].
* Make sure to register the dependencies first.<br></br> *
* The component will be enabled automatically, regardless of when it was registered.<br></br> * Make sure to register the dependencies first.
*
* The component will be enabled automatically, regardless of when it was registered.
*
* **If not using [ButtonPlugin], call [ComponentManager.unregComponents] on plugin disable.** * **If not using [ButtonPlugin], call [ComponentManager.unregComponents] on plugin disable.**
* *
* @param component The component to register * @param component The component to register
@ -163,8 +166,10 @@ abstract class Component<TP : JavaPlugin> {
} }
/** /**
* Unregisters a component by calling [.unregister].<br></br> * Unregisters a component by calling [.unregister].
* Make sure to unregister the dependencies last.<br></br> *
* Make sure to unregister the dependencies last.
*
* **Components will be unregistered in opposite order of registering by default by [ButtonPlugin] or [ComponentManager.unregComponents].** * **Components will be unregistered in opposite order of registering by default by [ButtonPlugin] or [ComponentManager.unregComponents].**
* *
* @param component The component to unregister * @param component The component to unregister
@ -186,7 +191,7 @@ abstract class Component<TP : JavaPlugin> {
val dependencies = metaAnn.depends val dependencies = metaAnn.depends
for (dep in dependencies) { //TODO: Support dependencies at enable/disable as well for (dep in dependencies) { //TODO: Support dependencies at enable/disable as well
if (!components.containsKey(dep.java)) { if (!components.containsKey(dep.java)) {
plugin.logger.warning("Failed to " + (if (register) "" else "un") + "register component " + component.className + " as a required dependency is missing/disabled: " + dep.simpleName) plugin.logger.warning("Failed to ${if (register) "" else "un"}register component ${component.className} as a required dependency is missing/disabled: ${dep.simpleName}")
return false return false
} }
} }
@ -201,8 +206,8 @@ abstract class Component<TP : JavaPlugin> {
return false return false
} }
component.register(plugin) component.register(plugin)
// The plugin is saved with this call, so it must be specified component.plugin = plugin
component.updateComponentData(plugin) component.updateConfig()
_components[component.javaClass] = component _components[component.javaClass] = component
if (plugin is ButtonPlugin) plugin.componentStack.push(component) if (plugin is ButtonPlugin) plugin.componentStack.push(component)
if (ComponentManager.areComponentsEnabled() && component.shouldBeEnabled.get()) { if (ComponentManager.areComponentsEnabled() && component.shouldBeEnabled.get()) {
@ -227,18 +232,10 @@ abstract class Component<TP : JavaPlugin> {
try { try {
setComponentEnabled(component, false) setComponentEnabled(component, false)
} catch (e: Exception) { } catch (e: Exception) {
TBMCCoreAPI.SendException( TBMCCoreAPI.SendException("Failed to disable component ${component.className}!", e, component)
"Failed to disable component " + component.className + "!",
e,
component
)
return false //If failed to disable, won't unregister either return false //If failed to disable, won't unregister either
} catch (e: NoClassDefFoundError) { } catch (e: NoClassDefFoundError) {
TBMCCoreAPI.SendException( TBMCCoreAPI.SendException("Failed to disable component ${component.className}!", e, component)
"Failed to disable component " + component.className + "!",
e,
component
)
return false return false
} }
} }
@ -247,7 +244,7 @@ abstract class Component<TP : JavaPlugin> {
} }
true true
} catch (e: Exception) { } catch (e: Exception) {
TBMCCoreAPI.SendException("Failed to " + (if (register) "" else "un") + "register component " + component.className + "!", e, plugin) TBMCCoreAPI.SendException("Failed to ${if (register) "" else "un"}register component ${component.className}!", e, plugin)
false false
} }
} }

View file

@ -1,15 +0,0 @@
package buttondevteam.lib.architecture
import org.bukkit.configuration.ConfigurationSection
import org.bukkit.plugin.java.JavaPlugin
/**
* A wrapper for plugin components. This is used internally.
*/
class ComponentData<TP : JavaPlugin>(
val plugin: TP,
saveAction: Runnable,
config: ConfigurationSection
) {
val config = IHaveConfig(saveAction, config) // TODO: Use lateinit instead of this class
}

View file

@ -9,8 +9,11 @@ import org.bukkit.scheduler.BukkitTask
import java.util.function.Function import java.util.function.Function
/** /**
* Use the getter/setter constructor if [T] isn't a primitive type or String.<br></br> * Use the getter/setter constructor if [T] isn't a primitive type or String.
* Use [Component.config] or [ButtonPlugin.iConfig] then [IHaveConfig.getData] to get an instance. *
* Use [Component.config] or [ButtonPlugin.iConfig] then [IHaveConfig.getData] to get an instance.
*
* **Note:** The instance can become outdated if the config is reloaded.
* @param config May be null for testing * @param config May be null for testing
* @param getter The parameter is of a primitive type as returned by [Configuration.get] * @param getter The parameter is of a primitive type as returned by [Configuration.get]
* @param setter The result should be a primitive type or string that can be retrieved correctly later * @param setter The result should be a primitive type or string that can be retrieved correctly later

View file

@ -26,7 +26,8 @@ class ChatMessage internal constructor(
*/ */
val permCheck: CommandSender, val permCheck: CommandSender,
/** /**
* The origin of the message, "Minecraft" or "Discord" for example. May be displayed to the user.<br></br> * The origin of the message, "Minecraft" or "Discord" for example. May be displayed to the user.
*
* **This is the user class capitalized folder name by default.** * **This is the user class capitalized folder name by default.**
*/ */
val origin: String val origin: String

View file

@ -39,7 +39,8 @@ abstract class ICommand2<TP : Command2Sender>(val manager: Command2<*, TP>) {
} }
/** /**
* Return null to not add any help text, return an empty array to only print subcommands.<br></br> * Return null to not add any help text, return an empty array to only print subcommands.
*
* By default, returns null if the Subcommand annotation is not present and returns an empty array if no help text can be found. * By default, returns null if the Subcommand annotation is not present and returns an empty array if no help text can be found.
* *
* @param method The method of the subcommand * @param method The method of the subcommand
@ -51,10 +52,13 @@ abstract class ICommand2<TP : Command2Sender>(val manager: Command2<*, TP>) {
} }
/** /**
* The command's path, or name if top-level command.<br></br> * The command's path, or name if top-level command.
* For example:<br></br> *
* "u admin updateplugin" or "u" for the top level one<br></br> * For example:
* <u>The path must be lowercase!</u><br></br> *
* "u admin updateplugin" or "u" for the top level one
*
* __The path must be lowercase!__
* *
* @return The command path, *which is the command class name by default* (removing any "command" from it) - Change via the [CommandClass] annotation * @return The command path, *which is the command class name by default* (removing any "command" from it) - Change via the [CommandClass] annotation
*/ */

View file

@ -17,7 +17,8 @@ import java.util.function.Supplier
object TBMCChatAPI { object TBMCChatAPI {
/** /**
* Sends a chat message to Minecraft. Make sure that the channel is registered with [.RegisterChatChannel].<br></br> * Sends a chat message to Minecraft. Make sure that the channel is registered with [.RegisterChatChannel].
*
* This will also send the error message to the sender, if they can't send the message. * This will also send the error message to the sender, if they can't send the message.
* *
* @param cm The message to send * @param cm The message to send

View file

@ -21,12 +21,10 @@ abstract class ChromaGamerBase {
protected set protected set
protected lateinit var commonUserData: CommonUserData<out ChromaGamerBase> protected lateinit var commonUserData: CommonUserData<out ChromaGamerBase>
protected open fun init() { protected open fun initConfig() {
config = IHaveConfig({ save() }, commonUserData.playerData) config = IHaveConfig({ save() }, commonUserData.playerData)
} }
protected fun updateUserConfig() {} // TODO: Use this instead of reset()
/** /**
* Saves the player. It'll handle all exceptions that may happen. Called automatically. * Saves the player. It'll handle all exceptions that may happen. Called automatically.
*/ */
@ -114,7 +112,8 @@ abstract class ChromaGamerBase {
} }
/** /**
* Returns a player instance of the given type that represents the same player. This will return a new instance unless the player is cached.<br></br> * 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. * 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 * @param cl The target player class
@ -130,7 +129,8 @@ abstract class ChromaGamerBase {
} }
/** /**
* Returns the filename for this player data. For example, for Minecraft-related data, MC UUIDs, for Discord data, Discord IDs, etc.<br></br> * 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** * **Does not include .yml**
*/ */
val fileName: String by lazy { val fileName: String by lazy {
@ -159,12 +159,12 @@ abstract class ChromaGamerBase {
} }
//----------------------------------------------------------------- //-----------------------------------------------------------------
@JvmField val channel: ConfigData<Channel>
val channel: ConfigData<Channel> = config.getData("channel", Channel.globalChat, get() = config.getData("channel", Channel.globalChat,
{ id -> { id ->
getChannels().filter { ch: Channel -> ch.identifier.equals(id as String, ignoreCase = true) } getChannels().filter { it.identifier.equals(id as String, ignoreCase = true) }
.findAny().orElseThrow { RuntimeException("Channel $id not found!") } .findAny().orElseThrow { RuntimeException("Channel $id not found!") }
}, { ch -> ch.identifier }) }, { ch -> ch.identifier })
companion object { companion object {
private const val TBMC_PLAYERS_DIR = "TBMC/players/" private const val TBMC_PLAYERS_DIR = "TBMC/players/"
@ -258,10 +258,8 @@ abstract class ChromaGamerBase {
@JvmStatic @JvmStatic
@Synchronized @Synchronized
fun <T : S, S : ChromaGamerBase> getUser(fname: String, cl: Class<T>): T { fun <T : S, S : ChromaGamerBase> getUser(fname: String, cl: Class<T>): T {
@Suppress("UNCHECKED_CAST")
val staticUserData: StaticUserData<S> = getStaticData(cl) val staticUserData: StaticUserData<S> = getStaticData(cl)
@Suppress("UNCHECKED_CAST")
val commonUserData: CommonUserData<S> = staticUserData.userDataMap[fname] val commonUserData: CommonUserData<S> = staticUserData.userDataMap[fname]
?: run { ?: run {
val folder = staticUserData.folder val folder = staticUserData.folder
@ -293,7 +291,7 @@ abstract class ChromaGamerBase {
} }
} }
obj.commonUserData = commonUserData obj.commonUserData = commonUserData
obj.init() obj.initConfig()
obj.scheduleUncache() obj.scheduleUncache()
return obj return obj
} }

View file

@ -11,8 +11,8 @@ abstract class TBMCPlayerBase : ChromaGamerBase() {
@JvmField @JvmField
val playerName = super.config.getData("PlayerName", "") val playerName = super.config.getData("PlayerName", "")
public override fun init() { public override fun initConfig() {
super.init() super.initConfig()
val pluginName = if (javaClass.isAnnotationPresent(PlayerClass::class.java)) val pluginName = if (javaClass.isAnnotationPresent(PlayerClass::class.java))
javaClass.getAnnotation(PlayerClass::class.java).pluginname javaClass.getAnnotation(PlayerClass::class.java).pluginname
else else