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.
*
* @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.
*/(
/**
@ -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
*/

View file

@ -1,115 +1,101 @@
package buttondevteam.core.component.members;
package buttondevteam.core.component.members
import buttondevteam.core.MainPlugin;
import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData;
import org.bukkit.Statistic;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.AbstractMap;
import java.util.Date;
import static buttondevteam.core.MainPlugin.permission;
import buttondevteam.core.MainPlugin
import buttondevteam.lib.architecture.Component
import buttondevteam.lib.architecture.ComponentMetadata
import org.bukkit.Statistic
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerJoinEvent
import java.time.Instant
import java.time.temporal.ChronoUnit
import java.util.*
/**
* Allows giving a 'member' group over some time elapsed OR played.
*/
@ComponentMetadata(enabledByDefault = false)
public class MemberComponent extends Component<MainPlugin> implements Listener {
/**
* The permission group to give to the player
*/
final ConfigData<String> memberGroup = getConfig().getData("memberGroup", "member");
class MemberComponent : Component<MainPlugin>(), Listener {
/**
* The permission group to give to the player
*/
val memberGroup get() = config.getData("memberGroup", "member")
/**
* The amount of hours needed to play before promotion
*/
private final ConfigData<Integer> playedHours = getConfig().getData("playedHours", 12);
/**
* The amount of hours needed to play before promotion
*/
private val playedHours get() = config.getData("playedHours", 12)
/**
* The amount of days passed since first login
*/
private final ConfigData<Integer> registeredForDays = getConfig().getData("registeredForDays", 7);
/**
* The amount of days passed since first login
*/
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
protected void enable() {
registerListener(this);
registerCommand(new MemberCommand());
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
}
}
@EventHandler
fun onPlayerJoin(event: PlayerJoinEvent) {
if (checkNotMember(event.player) && (checkRegTime(event.player) || checkPlayTime(event.player))) {
addPlayerAsMember(event.player)
}
}
@Override
protected void disable() {
}
fun addPlayerAsMember(player: Player): Boolean? {
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
public void onPlayerJoin(PlayerJoinEvent event) {
if (checkNotMember(event.getPlayer()) && (checkRegTime(event.getPlayer()) || checkPlayTime(event.getPlayer()))) {
addPlayerAsMember(event.getPlayer());
}
}
fun checkNotMember(player: Player?): Boolean {
return !MainPlugin.permission.playerInGroup(player, memberGroup.get())
}
public Boolean addPlayerAsMember(Player player) {
try {
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;
}
}
fun checkRegTime(player: Player): Boolean {
return getRegTime(player) == -1L
}
public boolean checkNotMember(Player player) {
return permission != null && !permission.playerInGroup(player, memberGroup.get());
}
fun checkPlayTime(player: Player): Boolean {
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) {
return getPlayTime(player) > playtime.getValue() * playedHours.get();
}
/**
* 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;
}
fun getPlayTimeTotal(player: Player): Int {
return player.getStatistic(playtime!!.first)
}
/**
* 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.
*/
private val restartAt = config.getData("restartAt", 12)
private val restartAt get() = config.getData("restartAt", 12)
private var lasttime: Long = 0
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.lib.architecture.Component;
import buttondevteam.lib.architecture.ComponentMetadata;
import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.ICommand2MC;
import com.earth2me.essentials.Trade;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.onarandombox.MultiverseCore.MultiverseCore;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.plugin.messaging.PluginMessageListener;
import java.io.*;
import java.math.BigDecimal;
import buttondevteam.core.MainPlugin
import buttondevteam.lib.architecture.Component
import buttondevteam.lib.architecture.ComponentMetadata
import buttondevteam.lib.chat.Command2.Subcommand
import buttondevteam.lib.chat.CommandClass
import buttondevteam.lib.chat.ICommand2MC
import com.earth2me.essentials.Trade
import com.google.common.io.ByteStreams
import com.onarandombox.MultiverseCore.MultiverseCore
import org.bukkit.Bukkit
import org.bukkit.Location
import org.bukkit.entity.Player
import org.bukkit.event.player.PlayerTeleportEvent
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.
* Requires Multiverse-Core.
*/
@ComponentMetadata(enabledByDefault = false)
public class SpawnComponent extends Component<MainPlugin> implements PluginMessageListener {
@Override
protected void enable() {
registerCommand(new SpawnCommand());
if (targetServer.get().length() == 0) {
spawnloc = MultiverseCore.getPlugin(MultiverseCore.class).getMVWorldManager().getFirstSpawnWorld()
.getSpawnLocation();
}
class SpawnComponent : Component<MainPlugin>(), PluginMessageListener {
override fun enable() {
registerCommand(SpawnCommand())
if (targetServer.get().isEmpty()) {
spawnloc = MultiverseCore.getPlugin(MultiverseCore::class.java).mvWorldManager.firstSpawnWorld.spawnLocation
}
Bukkit.getServer().messenger.registerOutgoingPluginChannel(plugin, "BungeeCord")
Bukkit.getServer().messenger.registerIncomingPluginChannel(plugin, "BungeeCord", this)
}
Bukkit.getServer().getMessenger().registerOutgoingPluginChannel(getPlugin(), "BungeeCord");
Bukkit.getServer().getMessenger().registerIncomingPluginChannel(getPlugin(), "BungeeCord", this);
}
override fun disable() {
Bukkit.getServer().messenger.unregisterIncomingPluginChannel(plugin, "BungeeCord")
Bukkit.getServer().messenger.unregisterOutgoingPluginChannel(plugin, "BungeeCord")
}
@Override
protected void disable() {
Bukkit.getServer().getMessenger().unregisterIncomingPluginChannel(getPlugin(), "BungeeCord");
Bukkit.getServer().getMessenger().unregisterOutgoingPluginChannel(getPlugin(), "BungeeCord");
}
override fun onPluginMessageReceived(channel: String, player: Player, message: ByteArray) {
if (channel != "BungeeCord") {
return
}
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) {
if (!channel.equals("BungeeCord")) {
return;
}
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);
/**
* The BungeeCord server that has the spawn. Set to empty if this server is the target.
*/
private val targetServer get() = config.getData("targetServer", "")
private var spawnloc: Location? = null
try {
DataInputStream msgin = new DataInputStream(new ByteArrayInputStream(msgbytes));
String somedata = msgin.readUTF(); // Read the data in the same way you wrote it
if (!"SendToSpawn".equals(somedata)) {
System.out.println("somedata: " + somedata);
return;
}
player.teleport(spawnloc);
} catch (IOException e) {
e.printStackTrace();
}
} else
System.out.println("Subchannel: " + subchannel);
}
/**
* The BungeeCord server that has the spawn. Set to empty if this server is the target.
*/
private final ConfigData<String> targetServer = getConfig().getData("targetServer", "");
private Location spawnloc;
@CommandClass(helpText = {
"Spawn",
"Teleport to spawn."
})
public class SpawnCommand extends ICommand2MC {
@SuppressWarnings("UnstableApiUsage")
@Command2.Subcommand
public void def(Player player) {
if (targetServer.get().length() == 0) {
player.sendMessage("${ChatColor.AQUA}Teleporting to spawn...");
try {
if (MainPlugin.ess != null)
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());
});
}
}
@CommandClass(helpText = ["Spawn", "Teleport to spawn."])
inner class SpawnCommand : ICommand2MC() {
@Subcommand
fun def(player: Player) {
if (targetServer.get().isEmpty()) {
player.sendMessage("\${ChatColor.AQUA}Teleporting to spawn...")
try {
if (MainPlugin.ess != null) MainPlugin.ess!!.getUser(player).teleport
.teleport(spawnloc, Trade(BigDecimal.ZERO, MainPlugin.ess), PlayerTeleportEvent.TeleportCause.COMMAND) else player.teleport(spawnloc!!)
} catch (e: Exception) {
player.sendMessage("\${ChatColor.RED}Failed to teleport: $e")
}
return
}
val out = ByteStreams.newDataOutput()
out.writeUTF("Connect")
out.writeUTF(targetServer.get())
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray())
Bukkit.getScheduler().runTask(plugin, Runnable {
//Delay it a bit
val outt = ByteStreams.newDataOutput()
outt.writeUTF("ForwardToPlayer") // So BungeeCord knows to forward it
outt.writeUTF(player.name)
outt.writeUTF("ChromaCore-Spawn") // The channel name to check if this your data
val msgbytes = ByteArrayOutputStream()
val msgout = DataOutputStream(msgbytes)
try {
msgout.writeUTF("SendToSpawn") // You can do anything you want with msgout
} catch (exception: IOException) {
exception.printStackTrace()
}
outt.writeShort(msgbytes.toByteArray().size)
outt.write(msgbytes.toByteArray())
player.sendPluginMessage(plugin, "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
*/

View file

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

View file

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

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
/**
* Use the getter/setter constructor if [T] isn't a primitive type or String.<br></br>
* Use [Component.config] or [ButtonPlugin.iConfig] then [IHaveConfig.getData] to get an instance.
* 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.
*
* **Note:** The instance can become outdated if the config is reloaded.
* @param config May be null for testing
* @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

View file

@ -26,7 +26,8 @@ class ChatMessage internal constructor(
*/
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.**
*/
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.
*
* @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>
* For example:<br></br>
* "u admin updateplugin" or "u" for the top level one<br></br>
* <u>The path must be lowercase!</u><br></br>
* The command's path, or name if top-level command.
*
* For example:
*
* "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
*/

View file

@ -17,7 +17,8 @@ import java.util.function.Supplier
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.
*
* @param cm The message to send

View file

@ -21,12 +21,10 @@ abstract class ChromaGamerBase {
protected set
protected lateinit var commonUserData: CommonUserData<out ChromaGamerBase>
protected open fun init() {
protected open fun initConfig() {
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.
*/
@ -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.
*
* @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**
*/
val fileName: String by lazy {
@ -159,12 +159,12 @@ abstract class ChromaGamerBase {
}
//-----------------------------------------------------------------
@JvmField
val channel: ConfigData<Channel> = config.getData("channel", Channel.globalChat,
{ id ->
getChannels().filter { ch: Channel -> ch.identifier.equals(id as String, ignoreCase = true) }
.findAny().orElseThrow { RuntimeException("Channel $id not found!") }
}, { ch -> ch.identifier })
val channel: ConfigData<Channel>
get() = config.getData("channel", Channel.globalChat,
{ id ->
getChannels().filter { it.identifier.equals(id as String, ignoreCase = true) }
.findAny().orElseThrow { RuntimeException("Channel $id not found!") }
}, { ch -> ch.identifier })
companion object {
private const val TBMC_PLAYERS_DIR = "TBMC/players/"
@ -258,10 +258,8 @@ abstract class ChromaGamerBase {
@JvmStatic
@Synchronized
fun <T : S, S : ChromaGamerBase> getUser(fname: String, cl: Class<T>): T {
@Suppress("UNCHECKED_CAST")
val staticUserData: StaticUserData<S> = getStaticData(cl)
@Suppress("UNCHECKED_CAST")
val commonUserData: CommonUserData<S> = staticUserData.userDataMap[fname]
?: run {
val folder = staticUserData.folder
@ -293,7 +291,7 @@ abstract class ChromaGamerBase {
}
}
obj.commonUserData = commonUserData
obj.init()
obj.initConfig()
obj.scheduleUncache()
return obj
}

View file

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