diff --git a/Chroma-Core/src/main/java/buttondevteam/core/ChromaCommand.java b/Chroma-Core/src/main/java/buttondevteam/core/ChromaCommand.java index a9d8699..bc5bb02 100644 --- a/Chroma-Core/src/main/java/buttondevteam/core/ChromaCommand.java +++ b/Chroma-Core/src/main/java/buttondevteam/core/ChromaCommand.java @@ -24,7 +24,7 @@ public class ChromaCommand extends ICommand2MC { @Command2.Subcommand public void reload(CommandSender sender, @Command2.OptionalArg ButtonPlugin plugin) { if (plugin == null) - plugin = MainPlugin.Instance; + plugin = getPlugin(); if (plugin.tryReloadConfig()) sender.sendMessage("§b" + plugin.getName() + " config reloaded."); else diff --git a/Chroma-Core/src/main/java/buttondevteam/core/ComponentManager.kt b/Chroma-Core/src/main/java/buttondevteam/core/ComponentManager.kt index e69f0b9..94d8971 100644 --- a/Chroma-Core/src/main/java/buttondevteam/core/ComponentManager.kt +++ b/Chroma-Core/src/main/java/buttondevteam/core/ComponentManager.kt @@ -1,66 +1,81 @@ -package buttondevteam.core; +package buttondevteam.core -import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.architecture.ButtonPlugin; -import buttondevteam.lib.architecture.Component; -import lombok.val; +import buttondevteam.lib.TBMCCoreAPI +import buttondevteam.lib.architecture.ButtonPlugin +import buttondevteam.lib.architecture.Component +import buttondevteam.lib.architecture.Component.Companion.components +import buttondevteam.lib.architecture.Component.Companion.setComponentEnabled +import buttondevteam.lib.architecture.Component.Companion.unregisterComponent +import org.bukkit.plugin.java.JavaPlugin -public final class ComponentManager { - private ComponentManager() {} +object ComponentManager { + private var componentsEnabled = false - private static boolean componentsEnabled = false; + /** + * This flag is used to enable components registered after the others were enabled. + * @return Whether already registered components have been enabled + */ + fun areComponentsEnabled(): Boolean { + return componentsEnabled + } - /** - * This flag is used to enable components registered after the others were enabled. - * @return Whether already registered components have been enabled - */ - public static boolean areComponentsEnabled() { return componentsEnabled; } + /** + * Enables components based on a configuration - any component registered afterwards will be also enabled + */ + fun enableComponents() { + components.values.stream().filter { c: Component -> c.shouldBeEnabled.get() } + .forEach { c -> + try { + setComponentEnabled(c, true) + } catch (e: Exception) { + TBMCCoreAPI.SendException("Failed to enable one of the components: " + c.javaClass.simpleName, e, c) + } catch (e: NoClassDefFoundError) { + TBMCCoreAPI.SendException("Failed to enable one of the components: " + c.javaClass.simpleName, e, c) + } + } + componentsEnabled = true + } - /** - * Enables components based on a configuration - any component registered afterwards will be also enabled - */ - public static void enableComponents() { - //Component.getComponents().values().stream().filter(c->cs.getConfigurationSection(c.getClass().getSimpleName()).getBoolean("enabled")).forEach(c-> { - Component.getComponents().values().stream().filter(c -> c.shouldBeEnabled.get()).forEach(c -> { - try { - Component.setComponentEnabled(c, true); - } catch (Exception | NoClassDefFoundError e) { - TBMCCoreAPI.SendException("Failed to enable one of the components: " + c.getClass().getSimpleName(), e, c); - } - }); - componentsEnabled = true; - } + /** + * Unregister all components of a plugin that are enabled - called on [ButtonPlugin] disable + */ + @Suppress("UNCHECKED_CAST") + fun unregComponents(plugin: T) { + while (!plugin.componentStack.empty()) //Unregister in reverse order + unregisterComponent(plugin, plugin.componentStack.pop() as Component) //Components are pushed on register + } - /** - * Unregister all components of a plugin that are enabled - called on {@link ButtonPlugin} disable - */ - @SuppressWarnings("unchecked") - public static void unregComponents(T plugin) { - while (!plugin.getComponentStack().empty()) //Unregister in reverse order - Component.unregisterComponent(plugin, (Component) plugin.getComponentStack().pop()); //Components are pushed on register - //componentsEnabled = false; - continue enabling new components after a plugin gets disabled - } + /** + * Will also return false if the component is not registered. + * + * @param cl The component class + * @return Whether the component is registered and enabled + */ + @JvmStatic + fun isEnabled(cl: Class?>?): Boolean { + val c = components[cl] + return c != null && c.isEnabled + } - /** - * Will also return false if the component is not registered. - * - * @param cl The component class - * @return Whether the component is registered and enabled - */ - public static boolean isEnabled(Class cl) { - val c = Component.getComponents().get(cl); - return c != null && c.isEnabled(); - } + /** + * Will also return null if the component is not registered. + * + * @param cl The component class + * @return The component if it's registered and enabled + */ + @JvmStatic + @Suppress("UNCHECKED_CAST") + fun > getIfEnabled(cl: Class): T? { + val c = components[cl] + return if (c != null && c.isEnabled) c as T else null + } - /** - * Will also return null if the component is not registered. - * - * @param cl The component class - * @return The component if it's registered and enabled - */ - @SuppressWarnings("unchecked") - public static T getIfEnabled(Class cl) { - val c = Component.getComponents().get(cl); - return c != null && c.isEnabled() ? (T) c : null; - } -} + /** + * It will return null if the component is not registered. Use this method if you don't want to check if the component is enabled. + */ + @JvmStatic + @Suppress("UNCHECKED_CAST") + fun > get(cl: Class): T? { + return components[cl] as T? + } +} \ No newline at end of file diff --git a/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.kt b/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.kt index 376e148..a830b9f 100755 --- a/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.kt +++ b/Chroma-Core/src/main/java/buttondevteam/core/MainPlugin.kt @@ -1,173 +1,194 @@ -package buttondevteam.core; +package buttondevteam.core -import buttondevteam.core.component.channel.Channel; -import buttondevteam.core.component.channel.ChannelComponent; -import buttondevteam.core.component.channel.ChatRoom; -import buttondevteam.core.component.members.MemberComponent; -import buttondevteam.core.component.randomtp.RandomTPComponent; -import buttondevteam.core.component.restart.RestartComponent; -import buttondevteam.core.component.spawn.SpawnComponent; -import buttondevteam.core.component.towny.TownyComponent; -import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.architecture.ButtonPlugin; -import buttondevteam.lib.architecture.Component; -import buttondevteam.lib.architecture.ConfigData; -import buttondevteam.lib.chat.Color; -import buttondevteam.lib.chat.TBMCChatAPI; -import buttondevteam.lib.player.ChromaGamerBase; -import buttondevteam.lib.player.TBMCPlayer; -import buttondevteam.lib.player.TBMCPlayerBase; -import com.earth2me.essentials.Essentials; -import lombok.Getter; -import lombok.Setter; -import net.milkbowl.vault.economy.Economy; -import net.milkbowl.vault.permission.Permission; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.BlockCommandSender; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.ConsoleCommandSender; -import org.bukkit.entity.HumanEntity; -import org.bukkit.entity.Player; -import org.bukkit.plugin.PluginDescriptionFile; -import org.bukkit.plugin.RegisteredServiceProvider; +import buttondevteam.core.component.channel.Channel +import buttondevteam.core.component.channel.ChannelComponent +import buttondevteam.core.component.channel.ChatRoom +import buttondevteam.core.component.members.MemberComponent +import buttondevteam.core.component.randomtp.RandomTPComponent +import buttondevteam.core.component.restart.RestartComponent +import buttondevteam.core.component.spawn.SpawnComponent +import buttondevteam.core.component.towny.TownyComponent +import buttondevteam.lib.TBMCCoreAPI +import buttondevteam.lib.architecture.ButtonPlugin +import buttondevteam.lib.architecture.Component.Companion.registerComponent +import buttondevteam.lib.chat.Color +import buttondevteam.lib.chat.TBMCChatAPI +import buttondevteam.lib.player.ChromaGamerBase +import buttondevteam.lib.player.TBMCPlayer +import buttondevteam.lib.player.TBMCPlayerBase +import com.earth2me.essentials.Essentials +import net.milkbowl.vault.economy.Economy +import net.milkbowl.vault.permission.Permission +import org.bukkit.Bukkit +import org.bukkit.OfflinePlayer +import org.bukkit.command.BlockCommandSender +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 -import javax.annotation.Nullable; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.Arrays; -import java.util.Optional; -import java.util.UUID; -import java.util.function.Supplier; -import java.util.logging.Logger; +class MainPlugin : ButtonPlugin() { + private var logger: Logger? = null + private var economy: Economy? = null -public class MainPlugin extends ButtonPlugin { - public static MainPlugin Instance; - public static Permission permission; - @Nullable - public static Essentials ess; + /** + * Whether the Core's chat handler should be enabled. + * Other chat plugins handling messages from other platforms should set this to false. + */ + var isChatHandlerEnabled = true - private Logger logger; - @Nullable - private Economy economy; - /** - * Whether the Core's chat handler should be enabled. - * Other chat plugins handling messages from other platforms should set this to false. - */ - @Getter - @Setter - private boolean chatHandlerEnabled = 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) - /** - * 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 final ConfigData writePluginList = getIConfig().getData("writePluginList", false); + /** + * The chat format to use for messages from other platforms if Chroma-Chat is not installed. + */ + @JvmField + var chatFormat = iConfig.getData("chatFormat", "[{origin}|{channel}] <{name}> {message}") - /** - * The chat format to use for messages from other platforms if Chroma-Chat is not installed. - */ - ConfigData chatFormat = getIConfig().getData("chatFormat", "[{origin}|" + - "{channel}] <{name}> {message}"); + /** + * Print some debug information. + */ + @JvmField + val test = iConfig.getData("test", false) - /** - * Print some debug information. - */ - public final ConfigData test = getIConfig().getData("test", false); - - /** - * If a Chroma command clashes with another plugin's command, this setting determines whether the Chroma command should be executed or the other plugin's. - */ - public final ConfigData prioritizeCustomCommands = getIConfig().getData("prioritizeCustomCommands", false); - - @Override - public void pluginEnable() { - Instance = this; - PluginDescriptionFile pdf = getDescription(); - logger = getLogger(); - if (!setupPermissions()) - throw new 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."); - saveConfig(); - Component.registerComponent(this, new RestartComponent()); - Component.registerComponent(this, new ChannelComponent()); - Component.registerComponent(this, new RandomTPComponent()); - Component.registerComponent(this, new MemberComponent()); - if (Bukkit.getPluginManager().isPluginEnabled("Multiverse-Core")) - Component.registerComponent(this, new SpawnComponent()); - if (Bukkit.getPluginManager().isPluginEnabled("Towny")) //It fails to load the component class otherwise - Component.registerComponent(this, new TownyComponent()); - /*if (Bukkit.getPluginManager().isPluginEnabled("Votifier") && economy != null) + /** + * If a Chroma command clashes with another plugin's command, this setting determines whether the Chroma command should be executed or the other plugin's. + */ + val prioritizeCustomCommands = iConfig.getData("prioritizeCustomCommands", false) + public override fun pluginEnable() { + 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.") + saveConfig() + registerComponent(this, RestartComponent()) + registerComponent(this, ChannelComponent()) + registerComponent(this, RandomTPComponent()) + registerComponent(this, MemberComponent()) + if (Bukkit.getPluginManager().isPluginEnabled("Multiverse-Core")) + registerComponent(this, SpawnComponent()) + if (Bukkit.getPluginManager().isPluginEnabled("Towny")) //It fails to load the component class otherwise + registerComponent(this, TownyComponent()) + /*if (Bukkit.getPluginManager().isPluginEnabled("Votifier") && economy != null) Component.registerComponent(this, new VotifierComponent(economy));*/ - ComponentManager.enableComponents(); - registerCommand(new ComponentCommand()); - registerCommand(new ChromaCommand()); - TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this); - TBMCCoreAPI.RegisterEventsForExceptions(Companion.getCommand2MC(), this); - ChromaGamerBase.addConverter(commandSender -> Optional.ofNullable(commandSender instanceof ConsoleCommandSender || commandSender instanceof BlockCommandSender - ? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks - ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof Player - ? TBMCPlayer.getPlayer(((Player) sender).getUniqueId(), TBMCPlayer.class) : null)); //Players, has higher priority - TBMCCoreAPI.RegisterUserClass(TBMCPlayerBase.class, TBMCPlayer::new); - TBMCChatAPI.RegisterChatChannel(Channel.GlobalChat = new Channel("§fg§f", Color.White, "g", null)); //The /ooc ID has moved to the config - TBMCChatAPI.RegisterChatChannel( - Channel.AdminChat = new Channel("§cADMIN§f", Color.Red, "a", Channel.inGroupFilter(null))); - TBMCChatAPI.RegisterChatChannel( - Channel.ModChat = new Channel("§9MOD§f", Color.Blue, "mod", Channel.inGroupFilter("mod"))); - TBMCChatAPI.RegisterChatChannel(new Channel("§6DEV§f", Color.Gold, "dev", Channel.inGroupFilter("developer"))); - TBMCChatAPI.RegisterChatChannel(new ChatRoom("§cRED§f", Color.DarkRed, "red")); - TBMCChatAPI.RegisterChatChannel(new ChatRoom("§6ORANGE§f", Color.Gold, "orange")); - TBMCChatAPI.RegisterChatChannel(new ChatRoom("§eYELLOW§f", Color.Yellow, "yellow")); - TBMCChatAPI.RegisterChatChannel(new ChatRoom("§aGREEN§f", Color.Green, "green")); - TBMCChatAPI.RegisterChatChannel(new ChatRoom("§bBLUE§f", Color.Blue, "blue")); - TBMCChatAPI.RegisterChatChannel(new ChatRoom("§5PURPLE§f", Color.DarkPurple, "purple")); - Supplier> playerSupplier = () -> Bukkit.getOnlinePlayers().stream().map(HumanEntity::getName)::iterator; - Companion.getCommand2MC().addParamConverter(OfflinePlayer.class, Bukkit::getOfflinePlayer, "Player not found!", playerSupplier); - Companion.getCommand2MC().addParamConverter(Player.class, Bukkit::getPlayer, "Online player not found!", playerSupplier); - if (writePluginList.get()) { - try { - Files.write(new File("plugins", "plugins.txt").toPath(), Arrays.stream(Bukkit.getPluginManager().getPlugins()).map(p -> (CharSequence) p.getDataFolder().getName())::iterator); - } catch (IOException e) { - TBMCCoreAPI.SendException("Failed to write plugin list!", e, this); - } - } - if (getServer().getPluginManager().isPluginEnabled("Essentials")) - ess = Essentials.getPlugin(Essentials.class); - logger.info(pdf.getName() + " has been Enabled (V." + pdf.getVersion() + ") Test: " + test.get() + "."); - } + ComponentManager.enableComponents() + registerCommand(ComponentCommand()) + registerCommand(ChromaCommand()) + TBMCCoreAPI.RegisterEventsForExceptions(PlayerListener(this), this) + TBMCCoreAPI.RegisterEventsForExceptions(command2MC, this) + //Console & cmdblocks + ChromaGamerBase.addConverter { commandSender: CommandSender -> + Optional.ofNullable( + if (commandSender is ConsoleCommandSender || commandSender is BlockCommandSender) + TBMCPlayer.getPlayer(UUID(0, 0), TBMCPlayer::class.java) + else null + ) + } + //Players, has higher priority + ChromaGamerBase.addConverter { sender: CommandSender -> + Optional.ofNullable( + if (sender is Player) TBMCPlayer.getPlayer(sender.uniqueId, TBMCPlayer::class.java) else null + ) + } + TBMCCoreAPI.RegisterUserClass(TBMCPlayerBase::class.java) { TBMCPlayer() } + TBMCChatAPI.RegisterChatChannel(Channel("§fg§f", Color.White, "g", null) + .also { Channel.GlobalChat = it }) //The /ooc ID has moved to the config + TBMCChatAPI.RegisterChatChannel(Channel("§cADMIN§f", Color.Red, "a", Channel.inGroupFilter(null)) + .also { Channel.AdminChat = it }) + TBMCChatAPI.RegisterChatChannel(Channel("§9MOD§f", Color.Blue, "mod", Channel.inGroupFilter("mod")) + .also { Channel.ModChat = it }) + TBMCChatAPI.RegisterChatChannel( + Channel( + "§6DEV§f", + Color.Gold, + "dev", + Channel.inGroupFilter("developer") + ) + ) // TODO: Make groups configurable + TBMCChatAPI.RegisterChatChannel(ChatRoom("§cRED§f", Color.DarkRed, "red")) + TBMCChatAPI.RegisterChatChannel(ChatRoom("§6ORANGE§f", Color.Gold, "orange")) + TBMCChatAPI.RegisterChatChannel(ChatRoom("§eYELLOW§f", Color.Yellow, "yellow")) + 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 + ) + 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 + ) + logger!!.info(pdf.name + " has been Enabled (V." + pdf.version + ") Test: " + test.get() + ".") + } - @Override - public void pluginDisable() { - logger.info("Saving player data..."); - ChromaGamerBase.saveUsers(); - logger.info("Player data saved."); - } + public override fun pluginDisable() { + logger!!.info("Saving player data...") + ChromaGamerBase.saveUsers() + logger!!.info("Player data saved.") + } - private boolean setupPermissions() { - permission = setupProvider(Permission.class); - return (permission != null); - } + private fun setupPermissions(): Boolean { + permission = setupProvider(Permission::class.java) + return permission != null + } - private boolean setupEconomy() { - economy = setupProvider(Economy.class); - return (economy != null); - } + private fun setupEconomy(): Boolean { + economy = setupProvider(Economy::class.java) + return economy != null + } - private T setupProvider(Class cl) { - RegisteredServiceProvider provider = getServer().getServicesManager() - .getRegistration(cl); - if (provider != null) - return provider.getProvider(); - return null; - } + private fun setupProvider(cl: Class): T? { + val provider = server.servicesManager + .getRegistration(cl) + return provider?.provider + } - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (command.getName().equals("dontrunthiscmd")) return true; //Used in chat preprocess for console - sender.sendMessage("§cThis command isn't available."); //In theory, unregistered commands use this method - return true; - } -} + override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean { + if (command.name == "dontrunthiscmd") return true //Used in chat preprocess for console + sender.sendMessage("§cThis command isn't available.") //In theory, unregistered commands use this method + return true + } + + companion object { + @JvmField + var Instance: MainPlugin = null + + @JvmField + var permission: Permission? = null + + @JvmField + var ess: Essentials? = null + } +} \ No newline at end of file diff --git a/Chroma-Core/src/main/java/buttondevteam/core/PlayerListener.kt b/Chroma-Core/src/main/java/buttondevteam/core/PlayerListener.kt index d75d34f..ef37744 100755 --- a/Chroma-Core/src/main/java/buttondevteam/core/PlayerListener.kt +++ b/Chroma-Core/src/main/java/buttondevteam/core/PlayerListener.kt @@ -1,116 +1,110 @@ -package buttondevteam.core; +package buttondevteam.core -import buttondevteam.lib.*; -import buttondevteam.lib.architecture.ButtonPlugin; -import buttondevteam.lib.chat.ChatMessage; -import buttondevteam.lib.chat.Command2MCSender; -import buttondevteam.lib.chat.TBMCChatAPI; -import buttondevteam.lib.player.ChromaGamerBase; -import buttondevteam.lib.player.TBMCPlayer; -import buttondevteam.lib.player.TBMCPlayerBase; -import lombok.val; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.event.Cancellable; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.server.ServerCommandEvent; +import buttondevteam.lib.* +import buttondevteam.lib.architecture.ButtonPlugin +import buttondevteam.lib.chat.ChatMessage +import buttondevteam.lib.chat.Command2MCSender +import buttondevteam.lib.chat.TBMCChatAPI +import buttondevteam.lib.player.ChromaGamerBase +import buttondevteam.lib.player.TBMCPlayer +import buttondevteam.lib.player.TBMCPlayerBase +import org.bukkit.Bukkit +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player +import org.bukkit.event.Cancellable +import org.bukkit.event.EventHandler +import org.bukkit.event.EventPriority +import org.bukkit.event.Listener +import org.bukkit.event.player.AsyncPlayerChatEvent +import org.bukkit.event.player.PlayerCommandPreprocessEvent +import org.bukkit.event.player.PlayerJoinEvent +import org.bukkit.event.player.PlayerQuitEvent +import org.bukkit.event.server.ServerCommandEvent -import java.util.Arrays; +class PlayerListener(val plugin: MainPlugin) : Listener { + @EventHandler(priority = EventPriority.NORMAL) + fun onPlayerJoin(event: PlayerJoinEvent) { + val p = event.player + val player = TBMCPlayerBase.getPlayer(p.uniqueId, TBMCPlayer::class.java) + val pname = player.PlayerName.get() + if (pname.isEmpty()) { + player.PlayerName.set(p.name) + plugin.logger.info("Player name saved: " + player.PlayerName.get()) + } else if (p.name != pname) { + plugin.logger.info(pname + " renamed to " + p.name) + player.PlayerName.set(p.name) + } + } -public class PlayerListener implements Listener { + @EventHandler(priority = EventPriority.NORMAL) + fun onPlayerLeave(event: PlayerQuitEvent) { + TBMCPlayerBase.getPlayer(event.player.uniqueId, TBMCPlayer::class.java).uncache() + } - @EventHandler(priority = EventPriority.NORMAL) - public void OnPlayerJoin(PlayerJoinEvent event) { - var p = event.getPlayer(); - TBMCPlayer player = TBMCPlayerBase.getPlayer(p.getUniqueId(), TBMCPlayer.class); - String pname = player.PlayerName.get(); - if (pname.length() == 0) { - player.PlayerName.set(p.getName()); - MainPlugin.Instance.getLogger().info("Player name saved: " + player.PlayerName.get()); - } else if (!p.getName().equals(pname)) { - MainPlugin.Instance.getLogger().info(pname + " renamed to " + p.getName()); - player.PlayerName.set(p.getName()); - } - } + @EventHandler(priority = EventPriority.HIGHEST) + fun onSystemChat(event: TBMCSystemChatEvent) { + if (event.isHandled) return + if (event.exceptions.any { "Minecraft".equals(it, ignoreCase = true) }) return + Bukkit.getOnlinePlayers().stream().filter { sender: CommandSender -> event.shouldSendTo(sender) } + .forEach { p: Player -> p.sendMessage(event.channel.displayName.get().substring(0, 2) + event.message) } + } - @EventHandler(priority = EventPriority.NORMAL) - public void OnPlayerLeave(PlayerQuitEvent event) { - TBMCPlayerBase.getPlayer(event.getPlayer().getUniqueId(), TBMCPlayer.class).uncache(); - } + @EventHandler + fun onPlayerChatPreprocess(event: PlayerCommandPreprocessEvent) { + handlePreprocess(event.player, event.message, event) + } - @EventHandler(priority = EventPriority.HIGHEST) - public void onSystemChat(TBMCSystemChatEvent event) { - if (event.isHandled()) - return; // Only handle here if ButtonChat couldn't - ButtonChat doesn't even handle this - if (Arrays.stream(event.getExceptions()).anyMatch("Minecraft"::equalsIgnoreCase)) - return; - Bukkit.getOnlinePlayers().stream().filter(event::shouldSendTo) - .forEach(p -> p.sendMessage(event.getChannel().DisplayName.get().substring(0, 2) + event.getMessage())); - } + @EventHandler + fun onSystemChatPreprocess(event: ServerCommandEvent) { + handlePreprocess(event.sender, "/" + event.command, event) + if (event.isCancelled) event.command = "dontrunthiscmd" //Bugfix + } - @EventHandler - public void onPlayerChatPreprocess(PlayerCommandPreprocessEvent event) { - handlePreprocess(event.getPlayer(), event.getMessage(), event); - } + private fun handlePreprocess(sender: CommandSender, message: String, event: Cancellable) { + if (event.isCancelled) return + val cg = ChromaGamerBase.getFromSender(sender) + ?: throw RuntimeException("Couldn't get user from sender for " + sender.name + "!") + val ev = TBMCCommandPreprocessEvent(sender, cg.channel.get(), message, sender) + Bukkit.getPluginManager().callEvent(ev) + if (ev.isCancelled) event.isCancelled = true //Cancel the original event + } - @EventHandler - public void onSystemChatPreprocess(ServerCommandEvent event) { - handlePreprocess(event.getSender(), "/" + event.getCommand(), event); - if (event.isCancelled()) event.setCommand("dontrunthiscmd"); //Bugfix - } + @EventHandler + fun onTBMCPreprocess(event: TBMCCommandPreprocessEvent) { + if (event.isCancelled) return + try { + val sender = Command2MCSender(event.sender, event.channel, event.permCheck) + event.isCancelled = ButtonPlugin.command2MC.handleCommand(sender, event.message) + } catch (e: Exception) { + TBMCCoreAPI.SendException( + "Command processing failed for sender '${event.sender}' and message '${event.message}'", + e, + plugin + ) + } + } - private void handlePreprocess(CommandSender sender, String message, Cancellable event) { - if (event.isCancelled()) return; - val cg = ChromaGamerBase.getFromSender(sender); - if (cg == null) throw new RuntimeException("Couldn't get user from sender for " + sender.getName() + "!"); - val ev = new TBMCCommandPreprocessEvent(sender, cg.channel.get(), message, sender); - Bukkit.getPluginManager().callEvent(ev); - if (ev.isCancelled()) - event.setCancelled(true); //Cancel the original event - } + @EventHandler(priority = EventPriority.HIGH) //The one in the chat plugin is set to highest + fun onPlayerChat(event: AsyncPlayerChatEvent) { + if (event.isCancelled) return //The chat plugin should cancel it after this handler + val cp = TBMCPlayer.getPlayer(event.player.uniqueId, TBMCPlayer::class.java) + TBMCChatAPI.SendChatMessage(ChatMessage.builder(event.player, cp, event.message).build()) + //Not cancelling the original event here, it's cancelled in the chat plugin + //This way other plugins can deal with the MC formatting if the chat plugin isn't present, but other platforms still get the message + } - @EventHandler - public void onTBMCPreprocess(TBMCCommandPreprocessEvent event) { - if (event.isCancelled()) return; - try { - event.setCancelled(ButtonPlugin.getCommand2MC().handleCommand(new Command2MCSender(event.getSender(), event.getChannel(), event.getPermCheck()), event.getMessage())); - } catch (Exception e) { - TBMCCoreAPI.SendException("Command processing failed for sender '" + event.getSender() + "' and message '" + event.getMessage() + "'", e, MainPlugin.Instance); - } - } - - @EventHandler(priority = EventPriority.HIGH) //The one in the chat plugin is set to highest - public void onPlayerChat(AsyncPlayerChatEvent event) { - if (event.isCancelled()) - return; //The chat plugin should cancel it after this handler - val cp = TBMCPlayer.getPlayer(event.getPlayer().getUniqueId(), TBMCPlayer.class); - TBMCChatAPI.SendChatMessage(ChatMessage.builder(event.getPlayer(), cp, event.getMessage()).build()); - //Not cancelling the original event here, it's cancelled in the chat plugin - //This way other plugins can deal with the MC formatting if the chat plugin isn't present, but other platforms still get the message - } - - @EventHandler(priority = EventPriority.HIGH) //The one in the chat plugin is set to highest - public void onPlayerChat(TBMCChatEvent event) { - if (event.isCancelled()) - return; - if (!MainPlugin.Instance.isChatHandlerEnabled()) return; - if (event.getOrigin().equals("Minecraft")) return; //Let other plugins handle MC messages - var channel = event.getChannel(); - String msg = MainPlugin.Instance.chatFormat.get() - .replace("{channel}", channel.DisplayName.get()) - .replace("{origin}", event.getOrigin().substring(0, 1)) - .replace("{name}", ChromaUtils.getDisplayName(event.getSender())) - .replace("{message}", String.format("§%x%s", channel.Color.get().ordinal(), event.getMessage())); - for (Player player : Bukkit.getOnlinePlayers()) - if (event.shouldSendTo(player)) - player.sendMessage(msg); - Bukkit.getConsoleSender().sendMessage(msg); - } + @EventHandler(priority = EventPriority.HIGH) //The one in the chat plugin is set to highest + fun onPlayerChat(event: TBMCChatEvent) { + if (event.isCancelled) return + if (!plugin.isChatHandlerEnabled) return + if (event.origin == "Minecraft") return //Let other plugins handle MC messages + val channel = event.channel + val msg = plugin.chatFormat.get() + .replace("{channel}", channel.displayName.get()) + .replace("{origin}", event.origin.substring(0, 1)) + .replace("{name}", ChromaUtils.getDisplayName(event.sender)) + .replace("{message}", String.format("§%x%s", channel.color.get().ordinal, event.message)) + for (player in Bukkit.getOnlinePlayers()) if (event.shouldSendTo(player)) player.sendMessage(msg) + Bukkit.getConsoleSender().sendMessage(msg) + } } \ No newline at end of file diff --git a/Chroma-Core/src/main/java/buttondevteam/core/component/channel/Channel.kt b/Chroma-Core/src/main/java/buttondevteam/core/component/channel/Channel.kt index 7d6824c..ee0dcdf 100755 --- a/Chroma-Core/src/main/java/buttondevteam/core/component/channel/Channel.kt +++ b/Chroma-Core/src/main/java/buttondevteam/core/component/channel/Channel.kt @@ -1,237 +1,231 @@ -package buttondevteam.core.component.channel; +package buttondevteam.core.component.channel -import buttondevteam.core.ComponentManager; -import buttondevteam.core.MainPlugin; -import buttondevteam.lib.architecture.Component; -import buttondevteam.lib.architecture.ConfigData; -import buttondevteam.lib.architecture.IHaveConfig; -import buttondevteam.lib.chat.Color; -import com.google.common.collect.Lists; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Stream; +import buttondevteam.core.ComponentManager.get +import buttondevteam.core.MainPlugin +import buttondevteam.lib.architecture.ConfigData +import buttondevteam.lib.architecture.IHaveConfig +import buttondevteam.lib.architecture.ListConfigData +import buttondevteam.lib.chat.Color +import org.bukkit.Bukkit +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player +import java.util.* +import java.util.function.Function +import java.util.function.Predicate +import java.util.stream.Stream /** * Represents a chat channel. May only be instantiated after the channel component is registered. */ -public class Channel { - /** - * Specifies a score that means it's OK to send - but it does not define any groups, only send or not send. See {@link #GROUP_EVERYONE} - */ - public static final int SCORE_SEND_OK = 0; - /** - * Specifies a score that means the user doesn't have permission to see or send the message. Any negative value has the same effect. - */ - public static final int SCORE_SEND_NOPE = -1; - /** - * Send the message to everyone who has access to the channel - this does not necessarily mean all players - */ - public static final String GROUP_EVERYONE = "everyone"; +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.

+ * May be null to send to everyone. + */( + /** + * The name that should appear at the start of the message. **A chat color is expected at the beginning (§9).** + */ + private val defDisplayName: String, + /** + * The default color of the messages sent in the channel + */ + private val defColor: Color, + /** + * The channel identifier. It's the same as the command to be used for the channel *without / *. For example "mod". + * It's also used for scoreboard objective names. + */ + val identifier: String, + /** + * A function that determines who has permission to see the channel. + * If the sender doesn't have access, they cannot send the message. + * Only those with access can see the messages. + * If null, everyone has access. + */ + private val filterAndErrorMSG: Function? +) { + private val config: IHaveConfig? = null // TODO: Use this - private static ChannelComponent component; + @JvmField + val isEnabled = component.config.getData("${this.identifier}.enabled", true) - private String defDisplayName; - private Color defColor; + /** + * Must start with a color code + */ + @JvmField + val displayName: ConfigData = + component.config.getData("${this.identifier}.displayName", this.defDisplayName) - private IHaveConfig config; + @JvmField + val color: ConfigData = component.config.getData("${this.identifier}.color", + this.defColor, { c -> Color.valueOf((c as String)) }, Color::toString + ) - public final ConfigData Enabled; + @JvmField + val extraIdentifiers: ListConfigData = component.config.getListData("${this.identifier}.IDs", listOf()) - /** - * Must start with a color code - */ - public final ConfigData DisplayName; + val isGlobal: Boolean + get() = filterAndErrorMSG == null - public final ConfigData Color; - public final String ID; + /** + * Note: Errors are sent to the sender automatically + * + * @param sender The user we're sending to + * @param score The (source) score to compare with the user's + */ + fun shouldSendTo(sender: CommandSender, score: Int): Boolean { + return score == getMCScore(sender) //If there's any error, the score won't be equal + } - public ConfigData IDs; + /** + * Note: Errors are sent to the sender automatically + */ + fun getMCScore(sender: CommandSender): Int { + return getRTR(sender).score //No need to check if there was an error + } - /** - * Filters both the sender and the targets - */ - private final Function filteranderrormsg; + /** + * Note: Errors are sent to the sender automatically

+ * + * + * Null means don't send + */ + fun getGroupID(sender: CommandSender): String? { + return getRTR(sender).groupID //No need to check if there was an error + } - private static final List channels = new ArrayList<>(); + fun getRTR(sender: CommandSender): RecipientTestResult { + return filterAndErrorMSG?.apply(sender) ?: RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE) + } - /** - * Creates a channel. - * - * @param displayname The name that should appear at the start of the message. A chat color is expected at the beginning (§9). - * @param color The default color of the messages sent in the channel - * @param command The command to be used for the channel without /. For example "mod". It's also used for scoreboard objective names. - * @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. - */ - public Channel(String displayname, Color color, String command, - Function filteranderrormsg) { - defDisplayName = displayname; - defColor = color; - ID = command; - this.filteranderrormsg = filteranderrormsg; - init(); - Enabled = component.getConfig().getData(ID + ".enabled", true); - DisplayName = component.getConfig().getData(ID + ".displayName", defDisplayName); - Color = component.getConfig().getData(ID + ".color", defColor, c -> buttondevteam.lib.chat.Color.valueOf((String) c), Enum::toString); - //noinspection unchecked - IDs = component.getConfig().getData(ID + ".IDs", new String[0], l -> ((List) l).toArray(new String[0]), Lists::newArrayList); - } + class RecipientTestResult { + @JvmField + val errormessage: String? - /** - * Must be only called from a subclass - otherwise it'll throw an exception. - * - * @see Channel#Channel(String, Color, String, Function) - */ - @SuppressWarnings("unchecked") - protected Channel(String displayname, Color color, String command, - BiFunction filteranderrormsg) { - defDisplayName = displayname; - defColor = color; - ID = command; - this.filteranderrormsg = s -> filteranderrormsg.apply((T) this, s); - init(); - Enabled = component.getConfig().getData(ID + ".enabled", true); - DisplayName = component.getConfig().getData(ID + ".displayName", defDisplayName); - Color = component.getConfig().getData(ID + ".color", defColor, c -> buttondevteam.lib.chat.Color.valueOf((String) c), Enum::toString); - //noinspection unchecked - IDs = component.getConfig().getData(ID + ".IDs", new String[0], l -> ((List) l).toArray(new String[0]), Lists::newArrayList); - } + @JvmField + val score // Anything below 0 is "never send" + : Int - private static void init() { - if (component == null) - component = (ChannelComponent) Component.getComponents().get(ChannelComponent.class); - if (component == null) - throw new RuntimeException("Attempting to create a channel before the component is registered!"); - } + @JvmField + val groupID: String? - public boolean isGlobal() { - return filteranderrormsg == null; - } + /** + * Creates a result that indicates an **error** + * + * @param errormessage The error message to show the sender if they don't meet the criteria. + */ + constructor(errormessage: String?) { + this.errormessage = errormessage + score = SCORE_SEND_NOPE + groupID = null + } - /** - * Note: Errors are sent to the sender automatically - * - * @param sender The user we're sending to - * @param score The (source) score to compare with the user's - */ - public boolean shouldSendTo(CommandSender sender, int score) { - return score == getMCScore(sender); //If there's any error, the score won't be equal - } + /** + * Creates a result that indicates a **success** + * + * @param score The score that identifies the target group. **Must be non-negative.** For example, the index of the town or nation to send to. + * @param groupID The ID of the target group. + */ + constructor(score: Int, groupID: String?) { + require(score >= 0) { "Score must be non-negative!" } + this.score = score + this.groupID = groupID + errormessage = null + } - /** - * Note: Errors are sent to the sender automatically - */ - public int getMCScore(CommandSender sender) { - return getRTR(sender).score; //No need to check if there was an error - } + companion object { + @JvmField + val ALL = RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE) + } + } - /** - * Note: Errors are sent to the sender automatically
- *

- * Null means don't send - */ - @Nullable - public String getGroupID(CommandSender sender) { - return getRTR(sender).groupID; //No need to check if there was an error - } + companion object { + /** + * Specifies a score that means it's OK to send - but it does not define any groups, only send or not send. See [.GROUP_EVERYONE] + */ + const val SCORE_SEND_OK = 0 - public RecipientTestResult getRTR(CommandSender sender) { - if (filteranderrormsg == null) - return new RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE); - return filteranderrormsg.apply(sender); - } + /** + * Specifies a score that means the user doesn't have permission to see or send the message. Any negative value has the same effect. + */ + const val SCORE_SEND_NOPE = -1 - /** - * Get a stream of the enabled channels - * - * @return Only the enabled channels - */ - public static Stream getChannels() { - return channels.stream().filter(ch -> ch.Enabled.get()); - } + /** + * Send the message to everyone *who has access to the channel* - this does not necessarily mean all players + */ + const val GROUP_EVERYONE = "everyone" + private val component: ChannelComponent by lazy { + get(ChannelComponent::class.java) + ?: throw RuntimeException("Attempting to create a channel before the component is registered!") + } + private val channels: MutableList = ArrayList() - /** - * Return all channels whether they're enabled or not - * - * @return A list of all channels - */ - public static List getChannelList() { - return Collections.unmodifiableList(channels); - } + /** + * Get a stream of the enabled channels + * + * @return Only the enabled channels + */ + @JvmStatic + fun getChannels(): Stream { + return channels.stream().filter { ch: Channel -> ch.isEnabled.get() } + } - /** - * Convenience method for the function parameter of {@link #Channel(String, Color, String, Function)}. It checks if the sender is OP or optionally has the specified group. The error message is - * generated automatically. - * - * @param permgroup The group that can access the channel or null to only allow OPs. - * @return If has access - */ - public static Function inGroupFilter(String permgroup) { - return noScoreResult( - s -> s.isOp() || (permgroup != null && (s instanceof Player && MainPlugin.permission != null && MainPlugin.permission.playerInGroup((Player) s, permgroup))), - "You need to be a(n) " + (permgroup != null ? permgroup : "OP") + " to use this channel."); - } + @JvmStatic + val channelList: List + /** + * Return all channels whether they're enabled or not + * + * @return A list of all channels + */ + get() = Collections.unmodifiableList(channels) - public static Function noScoreResult(Predicate filter, - String errormsg) { - return s -> filter.test(s) ? new RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE) : new RecipientTestResult(errormsg); - } + /** + * Convenience method for the function parameter of [.Channel]. It checks if the sender is OP or optionally has the specified group. The error message is + * generated automatically. + * + * @param permgroup The group that can access the channel or **null** to only allow OPs. + * @return If has access + */ + fun inGroupFilter(permgroup: String?): Function { + return noScoreResult( + { s -> + s.isOp || s is Player && permgroup?.let { pg -> + MainPlugin.permission?.playerInGroup( + s, + pg + ) + } ?: false + }, + "You need to be a(n) " + (permgroup ?: "OP") + " to use this channel." + ) + } - public static BiFunction noScoreResult( - BiPredicate filter, String errormsg) { - return (this_, s) -> filter.test(this_, s) ? new RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE) : new RecipientTestResult(errormsg); - } + fun noScoreResult( + filter: Predicate, + errormsg: String? + ): Function { + return Function { s -> + if (filter.test(s)) RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE) + else RecipientTestResult(errormsg) + } + } - public static Channel GlobalChat; - public static Channel AdminChat; - public static Channel ModChat; + @JvmField + var GlobalChat: Channel? = null + var AdminChat: Channel? = null + var ModChat: Channel? = null - public static void RegisterChannel(Channel channel) { - if (!channel.isGlobal() && !ComponentManager.isEnabled(ChannelComponent.class)) - return; //Allow registering the global chat (and I guess other chats like the RP chat) - channels.add(channel); - component.registerChannelCommand(channel); - Bukkit.getScheduler().runTask(MainPlugin.Instance, () -> Bukkit.getPluginManager().callEvent(new ChatChannelRegisterEvent(channel))); // Wait for server start - } + @JvmStatic + fun registerChannel(channel: Channel) { + if (!channel.isGlobal && !component.isEnabled) return //Allow registering the global chat (and I guess other chats like the RP chat) + channels.add(channel) + component.registerChannelCommand(channel) + Bukkit.getScheduler().runTask(component.plugin, + Runnable { + Bukkit.getPluginManager().callEvent(ChatChannelRegisterEvent(channel)) + }) // Wait for server start + } + } - public static class RecipientTestResult { - public final String errormessage; - public final int score; // Anything below 0 is "never send" - public final String groupID; - public static final RecipientTestResult ALL = new RecipientTestResult(SCORE_SEND_OK, GROUP_EVERYONE); - - /** - * Creates a result that indicates an error - * - * @param errormessage The error message to show the sender if they don't meet the criteria. - */ - public RecipientTestResult(String errormessage) { - this.errormessage = errormessage; - this.score = SCORE_SEND_NOPE; - this.groupID = null; - } - - /** - * Creates a result that indicates a success - * - * @param score The score that identifies the target group. Must be non-negative. For example, the index of the town or nation to send to. - * @param groupID The ID of the target group. - */ - public RecipientTestResult(int score, String groupID) { - if (score < 0) throw new IllegalArgumentException("Score must be non-negative!"); - this.score = score; - this.groupID = groupID; - this.errormessage = null; - } - } -} +} \ No newline at end of file diff --git a/Chroma-Core/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java b/Chroma-Core/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java index 4f580ac..7735410 100644 --- a/Chroma-Core/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java +++ b/Chroma-Core/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java @@ -47,12 +47,12 @@ public class ChannelComponent extends Component { @Override public String getCommandPath() { - return channel.ID; + return channel.identifier; } @Override public String[] getCommandPaths() { - return channel.IDs.get(); + return channel.extraIdentifiers.get(); } @Command2.Subcommand @@ -74,7 +74,7 @@ public class ChannelComponent extends Component { if (channel instanceof ChatRoom) ((ChatRoom) channel).joinRoom(sender); } - sender.sendMessage("§6You are now talking in: §b" + user.channel.get().DisplayName.get()); + sender.sendMessage("§6You are now talking in: §b" + user.channel.get().displayName.get()); } else TBMCChatAPI.SendChatMessage(ChatMessage.builder(sender, user, message).fromCommand(true) .permCheck(senderMC.getPermCheck()).build(), channel); diff --git a/Chroma-Core/src/main/java/buttondevteam/core/component/channel/ChatRoom.kt b/Chroma-Core/src/main/java/buttondevteam/core/component/channel/ChatRoom.kt index 428007a..49cf62e 100755 --- a/Chroma-Core/src/main/java/buttondevteam/core/component/channel/ChatRoom.kt +++ b/Chroma-Core/src/main/java/buttondevteam/core/component/channel/ChatRoom.kt @@ -1,28 +1,35 @@ -package buttondevteam.core.component.channel; +package buttondevteam.core.component.channel -import buttondevteam.lib.TBMCSystemChatEvent; -import buttondevteam.lib.chat.Color; -import buttondevteam.lib.chat.TBMCChatAPI; -import org.bukkit.command.CommandSender; +import buttondevteam.lib.TBMCSystemChatEvent +import buttondevteam.lib.chat.Color +import buttondevteam.lib.chat.TBMCChatAPI +import org.bukkit.command.CommandSender -import java.util.ArrayList; -import java.util.List; +class ChatRoom(displayname: String, color: Color, command: String) : Channel( + displayname, color, command, null // TODO: Custom filter for rooms using abstract method +) { + private val usersInRoom: MutableList = ArrayList() + private fun isInRoom(sender: CommandSender): Boolean { + return usersInRoom.contains(sender) + } -public class ChatRoom extends Channel { - private final List usersInRoom = new ArrayList<>(); + fun joinRoom(sender: CommandSender) { + usersInRoom.add(sender) + TBMCChatAPI.SendSystemMessage( + this, + RecipientTestResult.ALL, + sender.name + " joined the room", + TBMCSystemChatEvent.BroadcastTarget.ALL + ) //Always show message in the same kind of channel + } - public ChatRoom(String displayname, Color color, String command) { - super(displayname, color, command, noScoreResult((this_, s) -> this_.usersInRoom.contains(s), - "Not implemented yet. Please report it to the devs along with which platform you're trying to talk from.")); - } - - public void joinRoom(CommandSender sender) { - usersInRoom.add(sender); - TBMCChatAPI.SendSystemMessage(this, RecipientTestResult.ALL, sender.getName() + " joined the room", TBMCSystemChatEvent.BroadcastTarget.ALL); //Always show message in the same kind of channel - } - - public void leaveRoom(CommandSender sender) { - usersInRoom.remove(sender); - TBMCChatAPI.SendSystemMessage(this, RecipientTestResult.ALL, sender.getName() + " left the room", ChannelComponent.roomJoinLeave); - } -} + fun leaveRoom(sender: CommandSender) { + usersInRoom.remove(sender) + TBMCChatAPI.SendSystemMessage( + this, + RecipientTestResult.ALL, + sender.name + " left the room", + ChannelComponent.roomJoinLeave + ) + } +} \ No newline at end of file diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.kt index 8673bde..9ede9b2 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.kt @@ -3,7 +3,6 @@ package buttondevteam.lib.architecture import buttondevteam.buttonproc.HasConfig import buttondevteam.core.ComponentManager import buttondevteam.lib.TBMCCoreAPI -import buttondevteam.lib.architecture.Component.Companion.updateConfig import buttondevteam.lib.chat.Command2MC import buttondevteam.lib.chat.ICommand2MC import org.bukkit.configuration.InvalidConfigurationException @@ -17,7 +16,8 @@ import java.util.function.Consumer @HasConfig(global = true) abstract class ButtonPlugin : JavaPlugin() { - protected val iConfig = IHaveConfig { saveConfig() } + protected var iConfig = getIConfigInstance() + private set private var yaml: YamlConfiguration? = null protected val data //TODO @@ -52,12 +52,16 @@ abstract class ButtonPlugin : JavaPlugin() { IHaveConfig.pregenConfig(this, null) } + private fun getIConfigInstance(): IHaveConfig { + return IHaveConfig( + ::saveConfig, + this.config.getConfigurationSection("global") ?: this.config.createSection("global") + ) + } + private fun reloadIConfig(): Boolean { - val config = config - var section = config.getConfigurationSection("global") - if (section == null) section = config.createSection("global") - iConfig.reset(section) - return configLoaded // If loading fails, getConfig() returns a temporary instance + iConfig = getIConfigInstance() + return isConfigLoaded // If loading fails, getConfig() returns a temporary instance } override fun onDisable() { @@ -79,7 +83,7 @@ abstract class ButtonPlugin : JavaPlugin() { fun tryReloadConfig(): Boolean { if (!justReload()) return false reloadIConfig() - componentStack.forEach(Consumer { c: Component<*>? -> updateConfig(this, c!!) }) + componentStack.forEach(Consumer { c -> c.updateComponentData() }) return true } @@ -122,10 +126,10 @@ abstract class ButtonPlugin : JavaPlugin() { } override fun saveConfig() { - if (configLoaded) super.saveConfig() + if (isConfigLoaded) super.saveConfig() } - val configLoaded get() = yaml != null + val isConfigLoaded get() = yaml != null /** * Registers command and sets its plugin. @@ -142,6 +146,7 @@ abstract class ButtonPlugin : JavaPlugin() { annotation class ConfigOpts(val disableConfigGen: Boolean = false) companion object { //Needs to be static as we don't know the plugin when a command is handled + @JvmStatic val command2MC = Command2MC() fun configGenAllowed(obj: Any): Boolean { return !Optional.ofNullable(obj.javaClass.getAnnotation(ConfigOpts::class.java)) diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/Component.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/Component.kt index 55fa8b1..d5b0db8 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/Component.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/Component.kt @@ -18,10 +18,10 @@ import java.util.stream.Collectors @HasConfig(global = false) //Used for obtaining javadoc abstract class Component { var isEnabled = false - private var wrapper: ButtonComponent? = null + internal var componentData: ComponentData? = null - val config get() = wrapper!!.config - val plugin get() = wrapper!!.plugin + val config get() = componentData!!.config + val plugin get() = componentData!!.plugin private val data //TODO : IHaveConfig? = null @@ -120,11 +120,34 @@ abstract class Component { return res } - private val className: String - get() = javaClass.simpleName + private val className: String get() = javaClass.simpleName + + internal fun updateComponentData(plugin: TP = this.plugin) { + componentData = ComponentData(plugin, { plugin.saveConfig() }, this.getConfigSection(plugin)) + } + + private fun getConfigSection(plugin: JavaPlugin): ConfigurationSection { + var compconf = plugin.config.getConfigurationSection("components") + if (compconf == null) compconf = plugin.config.createSection("components") + var configSect = compconf.getConfigurationSection(className) + if (configSect == null) configSect = compconf.createSection(className) + return configSect + // TODO: Support tests (provide Bukkit configuration for tests) + } companion object { - private val components = HashMap>, Component>() + private val _components = HashMap>, Component>() + + /** + * Returns the currently registered components

+ * + * @return The currently registered components + */ + @JvmStatic + val components: Map>, Component> + get() { + return Collections.unmodifiableMap(_components) + } /** * Registers a component checking it's dependencies and calling [.register].

@@ -178,10 +201,11 @@ abstract class Component { ) return false } - val wrapper = ButtonComponent(plugin, { plugin.saveConfig() }, getConfigSection(plugin, component)) component.register(plugin) - components[component.javaClass] = component - if (plugin is ButtonPlugin) (plugin as ButtonPlugin).componentStack.push(component) + // The plugin is saved with this call, so it must be specified + component.updateComponentData(plugin) + _components[component.javaClass] = component + if (plugin is ButtonPlugin) plugin.componentStack.push(component) if (ComponentManager.areComponentsEnabled() && component.shouldBeEnabled.get()) { return try { //Enable components registered after the previous ones getting enabled setComponentEnabled(component, true) @@ -220,7 +244,7 @@ abstract class Component { } } component.unregister(plugin) - components.remove(component.javaClass) + _components.remove(component.javaClass) } true } catch (e: Exception) { @@ -242,7 +266,7 @@ abstract class Component { if (component.isEnabled == enabled) return //Don't do anything if (enabled.also { component.isEnabled = it }) { try { - getConfigSection(component.plugin!!, component) + component.getConfigSection(component.plugin) component.enable() if (ButtonPlugin.configGenAllowed(component)) { IHaveConfig.pregenConfig(component, null) @@ -267,24 +291,5 @@ abstract class Component { ButtonPlugin.command2MC.unregisterCommands(component) } } - - private fun getConfigSection(plugin: JavaPlugin, component: Component<*>): ConfigurationSection { - var compconf = plugin.config.getConfigurationSection("components") - if (compconf == null) compconf = plugin.config.createSection("components") - var configSect = compconf.getConfigurationSection(component.className) - if (configSect == null) configSect = compconf.createSection(component.className) - return configSect - // TODO: Support tests (provide Bukkit configuration for tests) - } - - /** - * Returns the currently registered components

- * - * @return The currently registered components - */ - @JvmStatic - fun getComponents(): Map>, Component> { - return Collections.unmodifiableMap(components) - } } } \ No newline at end of file diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonComponent.kt b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ComponentData.kt similarity index 68% rename from Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonComponent.kt rename to Chroma-Core/src/main/java/buttondevteam/lib/architecture/ComponentData.kt index fb239b1..3f740e0 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ButtonComponent.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ComponentData.kt @@ -6,10 +6,10 @@ import org.bukkit.plugin.java.JavaPlugin /** * A wrapper for plugin components. This is used internally. */ -class ButtonComponent( +class ComponentData( val plugin: TP, saveAction: Runnable, config: ConfigurationSection ) { - val config = IHaveConfig(saveAction, config) + val config = IHaveConfig(saveAction, config) // TODO: Use lateinit instead of this class } \ 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 a893dad..b2c3006 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ConfigData.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/ConfigData.kt @@ -82,33 +82,6 @@ class ConfigData internal constructor( private class SaveTask(val task: BukkitTask, val saveAction: Runnable) - class ConfigDataBuilder internal constructor( - private val config: IHaveConfig, - private val path: String, - private val primitiveDef: Any?, - private val getter: Function, - private val setter: Function - ) { - /** - * Builds a modifiable config representation. Use if you want to change the value *in code*. - * - * @return A ConfigData instance. - */ - fun build(readOnly: Boolean = false): ConfigData { - val config = ConfigData(config, path, primitiveDef, getter, setter, readOnly) - this.config.onConfigBuild(config) - return config - } - - fun buildList(readOnly: Boolean = false): ListConfigData { - if (primitiveDef is List<*>) { - val config = ListConfigData(config, path, primitiveDef, getter, setter, readOnly) - this.config.onConfigBuild(config) - return config - } - } - } - companion object { private val saveTasks = HashMap() fun signalChange(config: IHaveConfig) { @@ -147,9 +120,5 @@ class ConfigData internal constructor( } return false } - - fun builder(config: IHaveConfig, path: String, primitiveDef: Any?, getter: Function, setter: Function): ConfigDataBuilder { - return ConfigDataBuilder(config, path, primitiveDef, getter, setter) - } } } \ No newline at end of file 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 be9d78f..7ef3f09 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/architecture/IHaveConfig.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/architecture/IHaveConfig.kt @@ -2,7 +2,6 @@ package buttondevteam.lib.architecture import buttondevteam.core.MainPlugin import buttondevteam.lib.TBMCCoreAPI -import buttondevteam.lib.architecture.ConfigData.ConfigDataBuilder import buttondevteam.lib.architecture.config.IConfigData import org.bukkit.Bukkit import org.bukkit.configuration.ConfigurationSection @@ -11,7 +10,6 @@ import java.lang.reflect.InvocationTargetException import java.util.* import java.util.function.Function import java.util.function.Predicate -import java.util.function.Supplier import java.util.stream.Collectors /** @@ -30,33 +28,6 @@ class IHaveConfig( ) { private val datamap = HashMap>() - /** - * You may use this method with any data type, but always provide getters and setters that convert to primitive types - * if you're not using primitive types directly. - * These primitive types are strings, numbers, characters, booleans and lists of these things. - * - * @param path The path in config to use - * @param def The value to use by default - * @param getter A function that converts a primitive representation to the correct value - * @param setter A function that converts a value to a primitive representation - * @param primDef Whether the default value is a primitive value that needs to be converted to the correct type using the getter - * @param T The type of this variable (can be any class) - * @return The data object that can be used to get or set the value - */ - @Suppress("UNCHECKED_CAST") - fun getConfig( // TODO: Remove - path: String, - def: T, - getter: Function? = null, - setter: Function? = null - ): ConfigDataBuilder { - return ConfigData.builder(this, path, if (setter != null) setter.apply(def) else def, getter ?: Function { it as T }, setter ?: Function { it }) - } - - fun onConfigBuild(config: IConfigData<*>) { - datamap[config.path] = config - } - /** * You may use this method with any data type, but always provide getters and setters that convert to primitive types * if you're not using primitive types directly. @@ -109,30 +80,26 @@ class IHaveConfig( * This method overload should only be used with primitves or String. * * @param path The path in config to use - * @param def The value to use by default * @param The type of this variable (only use primitives or String) * @return The data object that can be used to get or set the value */ - fun getData(path: String, def: Supplier): ConfigData { // TODO: Remove + @Suppress("UNCHECKED_CAST") + fun getListData( + path: String, + def: List, + elementGetter: Function? = null, + elementSetter: Function? = null, + readOnly: Boolean = false + ): ListConfigData { var data = datamap[path] - if (data == null) { - val defval = def.get() - datamap[path] = ConfigData(this, path, defval, defval, null, null).also { data = it } - } - @Suppress("UNCHECKED_CAST") - return data as ConfigData - } - - /** - * This method overload should only be used with primitves or String. - * - * @param path The path in config to use - * @param The type of this variable (only use primitives or String) - * @return The data object that can be used to get or set the value - */ - fun getListData(path: String): ListConfigData { - var data = datamap[path] - if (data == null) datamap[path] = ListConfigData(this, path, ListConfigData.List()).also { data = it } + if (data == null) datamap[path] = ListConfigData( + this, + path, + def, + elementGetter ?: Function { it as T }, + elementSetter ?: Function { it }, + readOnly + ).also { data = it } @Suppress("UNCHECKED_CAST") return data as ListConfigData } 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 a472f3b..91e42ce 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.kt @@ -62,7 +62,11 @@ abstract class Command2, TP : Command2Sender>( @Retention(AnnotationRetention.RUNTIME) annotation class OptionalArg - protected class ParamConverter(val converter: Function, val errormsg: String, val allSupplier: Supplier>) + protected class ParamConverter( + val converter: Function, + val errormsg: String, + val allSupplier: Supplier> + ) protected val paramConverters = HashMap, ParamConverter<*>>() private val commandHelp = ArrayList() //Mainly needed by Discord @@ -70,15 +74,17 @@ abstract class Command2, TP : Command2Sender>( /** * Adds a param converter that obtains a specific object from a string parameter. - * The converter may return null. + * The converter may return null to signal an error. * * @param The type of the result * @param cl The class of the result object * @param converter The converter to use * @param allSupplier The supplier of all possible values (ideally) */ - open fun addParamConverter(cl: Class, converter: Function, errormsg: String, - allSupplier: Supplier>) { + open fun addParamConverter( + cl: Class, converter: Function, errormsg: String, + allSupplier: Supplier> + ) { paramConverters[cl] = ParamConverter(converter, errormsg, allSupplier) } 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 71eb0ca..08289ee 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.kt +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.kt @@ -125,7 +125,12 @@ class Command2MC : Command2('/', true), Listener * Automatically colors the message red. * {@see super#addParamConverter} */ - override fun addParamConverter(cl: Class, converter: Function, errormsg: String, allSupplier: Supplier>) { + override fun addParamConverter( + cl: Class, + converter: Function, + errormsg: String, + allSupplier: Supplier> + ) { super.addParamConverter(cl, converter, "§c$errormsg", allSupplier) } @@ -213,7 +218,7 @@ class Command2MC : Command2('/', true), Listener private class BukkitCommand(name: String?) : Command(name) { override fun execute(sender: CommandSender, commandLabel: String, args: Array): Boolean { - return ButtonPlugin.getCommand2MC().executeCommand(sender, this, commandLabel, args) + return ButtonPlugin.command2MC.executeCommand(sender, this, commandLabel, args) } @Throws(IllegalArgumentException::class) @@ -312,10 +317,9 @@ class Command2MC : Command2('/', true), Listener j++ continue } + //Break if converter is not found or for example, the player provided an invalid plugin name val converter = getParamConverter(params[j].type, command2MC) ?: break - val paramValue = converter.converter.apply(paramValueString) - ?: //For example, the player provided an invalid plugin name - break + val paramValue = converter.converter.apply(paramValueString) ?: break args[j] = paramValue k++ //Only increment if not CommandSender j++ diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java b/Chroma-Core/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java index 89cc684..8461ef5 100755 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java @@ -35,9 +35,9 @@ public class TBMCChatAPI { */ public static boolean SendChatMessage(ChatMessage cm, Channel channel) { if (!Channel.getChannelList().contains(channel)) - throw new RuntimeException("Channel " + channel.DisplayName.get() + " not registered!"); - if (!channel.Enabled.get()) { - cm.getSender().sendMessage("§cThe channel '" + channel.DisplayName.get() + "' is disabled!"); + throw new RuntimeException("Channel " + channel.getDisplayName().get() + " not registered!"); + if (!channel.isEnabled.get()) { + cm.getSender().sendMessage("§cThe channel '" + channel.displayName.get() + "' is disabled!"); return true; //Cancel sending if channel is disabled } Supplier task = () -> { @@ -70,11 +70,11 @@ public class TBMCChatAPI { */ public static boolean SendSystemMessage(Channel channel, RecipientTestResult rtr, String message, TBMCSystemChatEvent.BroadcastTarget target, String... exceptions) { if (!Channel.getChannelList().contains(channel)) - throw new RuntimeException("Channel " + channel.DisplayName.get() + " not registered!"); - if (!channel.Enabled.get()) + throw new RuntimeException("Channel " + channel.displayName.get() + " not registered!"); + if (!channel.enabled.get()) return true; //Cancel sending if (!Arrays.asList(exceptions).contains("Minecraft")) - Bukkit.getConsoleSender().sendMessage("[" + channel.DisplayName.get() + "] " + message); + Bukkit.getConsoleSender().sendMessage("[" + channel.displayName.get() + "] " + message); TBMCSystemChatEvent event = new TBMCSystemChatEvent(channel, message, rtr.score, rtr.groupID, exceptions, target); return ChromaUtils.callEventAsync(event); } @@ -92,6 +92,6 @@ public class TBMCChatAPI { * @param channel A new {@link Channel} to register */ public static void RegisterChatChannel(Channel channel) { - Channel.RegisterChannel(channel); + Channel.registerChannel(channel); } } diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java b/Chroma-Core/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java index 2890407..bb523d0 100755 --- a/Chroma-Core/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java +++ b/Chroma-Core/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java @@ -313,5 +313,5 @@ public abstract class ChromaGamerBase { //----------------------------------------------------------------- public final ConfigData channel = config.getData("channel", Channel.GlobalChat, - id -> Channel.getChannels().filter(ch -> ch.ID.equalsIgnoreCase((String) id)).findAny().orElse(null), ch -> ch.ID); + id -> Channel.getChannels().filter(ch -> ch.identifier.equalsIgnoreCase((String) id)).findAny().orElse(null), ch -> ch.ID); }