Reorganize command permissions, add license
This commit is contained in:
1 parent
e58809eed3
commit
7c91d476a8
42 files changed
+2900
-1916
No files matched your search
@@ -0,0 +1,8 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
max_line_length = off
|
||||
+58
-61
@@ -2,80 +2,77 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocatio
|
||||
import org.apache.commons.io.output.ByteArrayOutputStream
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "1.4.21"
|
||||
id("com.github.johnrengelman.shadow") version "6.1.0"
|
||||
id("kr.entree.spigradle") version "2.2.3"
|
||||
kotlin("jvm") version "1.4.30"
|
||||
id("com.github.johnrengelman.shadow") version "6.1.0"
|
||||
id("kr.entree.spigradle") version "2.2.3"
|
||||
id("net.kyori.indra.license-header") version "1.3.1"
|
||||
}
|
||||
|
||||
val projectName = "AnnouncerPlus"
|
||||
group = "xyz.jpenilla"
|
||||
version = "1.2.2.2+${getLastCommitHash()}-SNAPSHOT"
|
||||
version = "1.2.3.1+${getLastCommitHash()}-SNAPSHOT"
|
||||
description = "Announcement plugin with support for permissions. Supports Hex colors and clickable messages/hover text using MiniMessage."
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
maven(url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
|
||||
maven(url = "https://oss.sonatype.org/content/groups/public/")
|
||||
maven(url = "https://repo.spongepowered.org/maven")
|
||||
maven(url = "https://repo.jpenilla.xyz/snapshots")
|
||||
maven(url = "https://ci.ender.zone/plugin/repository/everything/")
|
||||
maven(url = "https://repo.codemc.org/repository/maven-public")
|
||||
maven(url = "https://jitpack.io")
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
|
||||
maven("https://oss.sonatype.org/content/groups/public/")
|
||||
maven("https://repo.spongepowered.org/maven")
|
||||
maven("https://repo.jpenilla.xyz/snapshots")
|
||||
maven("https://ci.ender.zone/plugin/repository/everything/")
|
||||
maven("https://repo.codemc.org/repository/maven-public")
|
||||
maven("https://jitpack.io")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("org.spigotmc", "spigot-api", "1.13.2-R0.1-SNAPSHOT")
|
||||
compileOnly("com.github.MilkBowl", "VaultAPI", "1.7")
|
||||
compileOnly("net.ess3", "EssentialsX", "2.17.2")
|
||||
compileOnly("org.spigotmc", "spigot-api", "1.13.2-R0.1-SNAPSHOT")
|
||||
compileOnly("com.github.MilkBowl", "VaultAPI", "1.7")
|
||||
compileOnly("net.ess3", "EssentialsX", "2.17.2")
|
||||
|
||||
implementation("org.koin", "koin-core", "2.1.6")
|
||||
implementation("xyz.jpenilla", "jmplib", "1.0.1+27-SNAPSHOT")
|
||||
implementation("org.spongepowered", "configurate-hocon", "4.0.0")
|
||||
implementation("org.bstats", "bstats-bukkit", "1.8")
|
||||
implementation("org.koin", "koin-core", "2.1.6")
|
||||
implementation("net.kyori", "adventure-api", "4.5.1")
|
||||
implementation("xyz.jpenilla", "jmplib", "1.0.1+30-SNAPSHOT")
|
||||
implementation("org.spongepowered", "configurate-hocon", "4.1.0-SNAPSHOT")
|
||||
implementation("org.bstats", "bstats-bukkit", "2.2.1")
|
||||
|
||||
val cloudVersion = "1.3.0"
|
||||
implementation("cloud.commandframework", "cloud-paper", cloudVersion)
|
||||
implementation("cloud.commandframework", "cloud-kotlin-extensions", cloudVersion)
|
||||
implementation("cloud.commandframework", "cloud-minecraft-extras", cloudVersion)
|
||||
}
|
||||
|
||||
spigot {
|
||||
name = projectName
|
||||
apiVersion = "1.13"
|
||||
description = "Announcement plugin with support for permissions. Supports Hex colors and clickable messages/hover text using MiniMessage."
|
||||
website = "https://github.com/jmanpenilla/AnnouncerPlus"
|
||||
authors("jmp")
|
||||
depends("Vault")
|
||||
softDepends("PlaceholderAPI", "Prisma", "Essentials")
|
||||
}
|
||||
|
||||
val autoRelocate by tasks.register("configureShadowRelocation", ConfigureShadowRelocation::class) {
|
||||
target = tasks.shadowJar.get()
|
||||
val packageName = "${project.group}.${project.name.toLowerCase()}"
|
||||
prefix = "$packageName.shaded"
|
||||
val cloudVersion = "1.4.0"
|
||||
implementation("cloud.commandframework", "cloud-paper", cloudVersion)
|
||||
implementation("cloud.commandframework", "cloud-kotlin-extensions", cloudVersion)
|
||||
implementation("cloud.commandframework", "cloud-minecraft-extras", cloudVersion)
|
||||
}
|
||||
|
||||
tasks {
|
||||
build {
|
||||
dependsOn(shadowJar)
|
||||
}
|
||||
compileKotlin {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
}
|
||||
shadowJar {
|
||||
minimize()
|
||||
dependsOn(autoRelocate)
|
||||
archiveClassifier.set("")
|
||||
archiveFileName.set("$projectName-${project.version}.jar")
|
||||
}
|
||||
compileKotlin {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
}
|
||||
register<ConfigureShadowRelocation>("autoRelocate") {
|
||||
target = shadowJar.get()
|
||||
val packageName = "${project.group}.${project.name.toLowerCase()}"
|
||||
prefix = "$packageName.lib"
|
||||
}
|
||||
shadowJar {
|
||||
dependsOn(withType<ConfigureShadowRelocation>())
|
||||
minimize()
|
||||
archiveClassifier.set("")
|
||||
archiveFileName.set("${project.name}-${project.version}.jar")
|
||||
}
|
||||
build {
|
||||
dependsOn(shadowJar)
|
||||
}
|
||||
}
|
||||
|
||||
fun getLastCommitHash(): String {
|
||||
val byteOut = ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine = listOf("git", "rev-parse", "--short", "HEAD")
|
||||
standardOutput = byteOut
|
||||
}
|
||||
return byteOut.toString(Charsets.UTF_8).trim()
|
||||
spigot {
|
||||
apiVersion = "1.13"
|
||||
website = "https://github.com/jmanpenilla/AnnouncerPlus"
|
||||
authors("jmp")
|
||||
depends("Vault")
|
||||
softDepends("PlaceholderAPI", "Prisma", "Essentials")
|
||||
}
|
||||
|
||||
fun getLastCommitHash(): String = ByteArrayOutputStream().apply {
|
||||
exec {
|
||||
commandLine = listOf("git", "rev-parse", "--short", "HEAD")
|
||||
standardOutput = this@apply
|
||||
}
|
||||
}.toString(Charsets.UTF_8).trim()
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2021 Jason Penilla
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,21 @@
|
||||
This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
|
||||
Copyright (c) 2020-2021 Jason Penilla
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1 @@
|
||||
rootProject.name = "AnnouncerPlus"
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus
|
||||
|
||||
import com.google.gson.Gson
|
||||
@@ -7,92 +30,94 @@ import kr.entree.spigradle.annotations.PluginMain
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer
|
||||
import net.milkbowl.vault.permission.Permission
|
||||
import org.bstats.bukkit.Metrics
|
||||
import org.bstats.charts.SimplePie
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.context.startKoin
|
||||
import org.koin.core.inject
|
||||
import org.koin.dsl.module
|
||||
import xyz.jpenilla.announcerplus.command.CommandManager
|
||||
import xyz.jpenilla.announcerplus.compatability.EssentialsHook
|
||||
import xyz.jpenilla.announcerplus.compatibility.EssentialsHook
|
||||
import xyz.jpenilla.announcerplus.config.ConfigManager
|
||||
import xyz.jpenilla.announcerplus.config.message.MessageConfig
|
||||
import xyz.jpenilla.announcerplus.task.ToastTask
|
||||
import xyz.jpenilla.announcerplus.util.UpdateChecker
|
||||
import xyz.jpenilla.jmplib.BasePlugin
|
||||
import xyz.jpenilla.jmplib.Environment
|
||||
|
||||
@PluginMain
|
||||
class AnnouncerPlus : BasePlugin(), KoinComponent {
|
||||
val gson: Gson = GsonBuilder().create()
|
||||
val jsonParser = JsonParser()
|
||||
val gsonComponentSerializer = GsonComponentSerializer.gson()
|
||||
val downsamplingGsonComponentSerializer = GsonComponentSerializer.colorDownsamplingGson()
|
||||
val configManager: ConfigManager by inject()
|
||||
val gson: Gson = GsonBuilder().create()
|
||||
val jsonParser = JsonParser()
|
||||
val gsonComponentSerializer = GsonComponentSerializer.gson()
|
||||
val downsamplingGsonComponentSerializer = GsonComponentSerializer.colorDownsamplingGson()
|
||||
val configManager: ConfigManager by inject()
|
||||
|
||||
var perms: Permission? = null
|
||||
var essentials: EssentialsHook? = null
|
||||
var toastTask: ToastTask? = null
|
||||
private lateinit var commandManager: CommandManager
|
||||
var perms: Permission? = null
|
||||
var essentials: EssentialsHook? = null
|
||||
var toastTask: ToastTask? = null
|
||||
private lateinit var commandManager: CommandManager
|
||||
|
||||
override fun onPluginEnable() {
|
||||
if (!setupPermissions()) {
|
||||
logger.warning("Permissions plugin not found. AnnouncerPlus will not work.")
|
||||
isEnabled = false
|
||||
return
|
||||
}
|
||||
if (server.pluginManager.isPluginEnabled("Essentials")) {
|
||||
essentials = EssentialsHook()
|
||||
}
|
||||
|
||||
startKoin {
|
||||
modules(module {
|
||||
single { this@AnnouncerPlus }
|
||||
single { audience }
|
||||
single { miniMessage }
|
||||
single { chat }
|
||||
single { ConfigManager(get()) }
|
||||
single { gson }
|
||||
single { jsonParser }
|
||||
})
|
||||
}
|
||||
|
||||
if (majorMinecraftVersion > 11) {
|
||||
toastTask = ToastTask()
|
||||
} else {
|
||||
logger.info("Sorry, but Toast/Achievement style messages do not work on this version. Update to 1.12 or newer to use this feature.")
|
||||
}
|
||||
commandManager = CommandManager(this)
|
||||
|
||||
server.pluginManager.registerEvents(JoinQuitListener(), this)
|
||||
broadcast()
|
||||
|
||||
UpdateChecker(this, "jmanpenilla/AnnouncerPlus").updateCheck()
|
||||
|
||||
val metrics = Metrics(this, 8067)
|
||||
metrics.addCustomChart(Metrics.SimplePie("join_quit_configs", configManager.joinQuitConfigs.size::toString))
|
||||
metrics.addCustomChart(Metrics.SimplePie("message_configs", configManager.messageConfigs.size::toString))
|
||||
override fun onPluginEnable() {
|
||||
if (!setupPermissions()) {
|
||||
logger.warning("Permissions plugin not found. AnnouncerPlus will not work.")
|
||||
isEnabled = false
|
||||
return
|
||||
}
|
||||
if (server.pluginManager.isPluginEnabled("Essentials")) {
|
||||
essentials = EssentialsHook()
|
||||
}
|
||||
|
||||
private fun broadcast() {
|
||||
if (configManager.mainConfig.enableBroadcasts) configManager.messageConfigs.values.forEach(MessageConfig::broadcast)
|
||||
startKoin {
|
||||
modules(module {
|
||||
single { this@AnnouncerPlus }
|
||||
single { audiences() }
|
||||
single { miniMessage() }
|
||||
single { chat() }
|
||||
single { ConfigManager(get()) }
|
||||
single { gson }
|
||||
single { jsonParser }
|
||||
})
|
||||
}
|
||||
|
||||
fun reload() {
|
||||
if (toastTask != null) {
|
||||
toastTask?.cancel()
|
||||
toastTask = ToastTask()
|
||||
}
|
||||
configManager.reload()
|
||||
broadcast()
|
||||
if (Environment.majorMinecraftVersion() > 11) {
|
||||
toastTask = ToastTask()
|
||||
} else {
|
||||
logger.info("Sorry, but Toast/Achievement style messages do not work on this version. Update to 1.12 or newer to use this feature.")
|
||||
}
|
||||
commandManager = CommandManager(this)
|
||||
|
||||
override fun onDisable() {
|
||||
toastTask?.cancel()
|
||||
}
|
||||
server.pluginManager.registerEvents(JoinQuitListener(), this)
|
||||
broadcast()
|
||||
|
||||
private fun setupPermissions(): Boolean {
|
||||
val rsp = server.servicesManager.getRegistration(Permission::class.java)
|
||||
if (rsp != null) {
|
||||
perms = rsp.provider
|
||||
}
|
||||
return perms != null
|
||||
UpdateChecker(this, "jmanpenilla/AnnouncerPlus").updateCheck()
|
||||
|
||||
val metrics = Metrics(this, 8067)
|
||||
metrics.addCustomChart(SimplePie("join_quit_configs", configManager.joinQuitConfigs.size::toString))
|
||||
metrics.addCustomChart(SimplePie("message_configs", configManager.messageConfigs.size::toString))
|
||||
}
|
||||
|
||||
private fun broadcast() {
|
||||
if (configManager.mainConfig.enableBroadcasts) configManager.messageConfigs.values.forEach(MessageConfig::broadcast)
|
||||
}
|
||||
|
||||
fun reload() {
|
||||
if (toastTask != null) {
|
||||
toastTask?.cancel()
|
||||
toastTask = ToastTask()
|
||||
}
|
||||
configManager.reload()
|
||||
broadcast()
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
toastTask?.cancel()
|
||||
}
|
||||
|
||||
private fun setupPermissions(): Boolean {
|
||||
val rsp = server.servicesManager.getRegistration(Permission::class.java)
|
||||
if (rsp != null) {
|
||||
perms = rsp.provider
|
||||
}
|
||||
return perms != null
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus
|
||||
|
||||
import org.bukkit.event.EventHandler
|
||||
@@ -11,47 +34,47 @@ import xyz.jpenilla.announcerplus.config.ConfigManager
|
||||
import xyz.jpenilla.jmplib.RandomCollection
|
||||
|
||||
class JoinQuitListener : Listener, KoinComponent {
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
fun onJoin(event: PlayerJoinEvent) {
|
||||
if (configManager.mainConfig.joinFeatures) {
|
||||
event.joinMessage = ""
|
||||
if (configManager.mainConfig.firstJoinConfigEnabled && !event.player.hasPlayedBefore()) {
|
||||
configManager.firstJoinConfig.onJoin(event.player)
|
||||
return
|
||||
}
|
||||
for (entry in configManager.mainConfig.randomJoinConfigs.entries) {
|
||||
if (entry.key != "demo" && event.player.hasPermission("announcerplus.randomjoin.${entry.key}")) {
|
||||
val weights = RandomCollection<String>()
|
||||
for (pair in entry.value) {
|
||||
weights.add(pair.weight, pair.configName)
|
||||
}
|
||||
configManager.joinQuitConfigs[weights.next()]?.onJoin(event.player)
|
||||
}
|
||||
}
|
||||
for (config in configManager.joinQuitConfigs.values) {
|
||||
config.onJoin(event.player)
|
||||
}
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
fun onJoin(event: PlayerJoinEvent) {
|
||||
if (configManager.mainConfig.joinFeatures) {
|
||||
event.joinMessage = ""
|
||||
if (configManager.mainConfig.firstJoinConfigEnabled && !event.player.hasPlayedBefore()) {
|
||||
configManager.firstJoinConfig.onJoin(event.player)
|
||||
return
|
||||
}
|
||||
for (entry in configManager.mainConfig.randomJoinConfigs.entries) {
|
||||
if (entry.key != "demo" && event.player.hasPermission("announcerplus.randomjoin.${entry.key}")) {
|
||||
val weights = RandomCollection<String>()
|
||||
for (pair in entry.value) {
|
||||
weights.add(pair.weight, pair.configName)
|
||||
}
|
||||
configManager.joinQuitConfigs[weights.next()]?.onJoin(event.player)
|
||||
}
|
||||
}
|
||||
for (config in configManager.joinQuitConfigs.values) {
|
||||
config.onJoin(event.player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
fun onQuit(event: PlayerQuitEvent) {
|
||||
if (configManager.mainConfig.quitFeatures) {
|
||||
event.quitMessage = ""
|
||||
for (entry in configManager.mainConfig.randomQuitConfigs.entries) {
|
||||
if (entry.key != "demo" && event.player.hasPermission("announcerplus.randomquit.${entry.key}")) {
|
||||
val weights = RandomCollection<String>()
|
||||
for (pair in entry.value) {
|
||||
weights.add(pair.weight, pair.configName)
|
||||
}
|
||||
configManager.joinQuitConfigs[weights.next()]?.onQuit(event.player)
|
||||
}
|
||||
}
|
||||
for (config in configManager.joinQuitConfigs.values) {
|
||||
config.onQuit(event.player)
|
||||
}
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
fun onQuit(event: PlayerQuitEvent) {
|
||||
if (configManager.mainConfig.quitFeatures) {
|
||||
event.quitMessage = ""
|
||||
for (entry in configManager.mainConfig.randomQuitConfigs.entries) {
|
||||
if (entry.key != "demo" && event.player.hasPermission("announcerplus.randomquit.${entry.key}")) {
|
||||
val weights = RandomCollection<String>()
|
||||
for (pair in entry.value) {
|
||||
weights.add(pair.weight, pair.configName)
|
||||
}
|
||||
configManager.joinQuitConfigs[weights.next()]?.onQuit(event.player)
|
||||
}
|
||||
}
|
||||
for (config in configManager.joinQuitConfigs.values) {
|
||||
config.onQuit(event.player)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.command
|
||||
|
||||
import cloud.commandframework.CommandHelpHandler
|
||||
@@ -15,69 +38,74 @@ import xyz.jpenilla.announcerplus.config.ConfigManager
|
||||
import xyz.jpenilla.announcerplus.config.message.MessageConfig
|
||||
|
||||
class ArgumentFactory : KoinComponent {
|
||||
private val commandManager: CommandManager by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val commandManager: CommandManager by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
|
||||
fun helpQuery(name: String): CommandArgument<CommandSender, String> {
|
||||
return StringArgument.newBuilder<CommandSender>(name)
|
||||
.greedy()
|
||||
.asOptional()
|
||||
.withSuggestionsProvider { context, _ ->
|
||||
(commandManager.commandHelpHandler.queryHelp(context.sender, "") as CommandHelpHandler.IndexHelpTopic<CommandSender>)
|
||||
.entries.map { it.syntaxString }
|
||||
}
|
||||
.build()
|
||||
}
|
||||
fun helpQuery(name: String): CommandArgument<CommandSender, String> {
|
||||
return StringArgument.newBuilder<CommandSender>(name)
|
||||
.greedy()
|
||||
.asOptional()
|
||||
.withSuggestionsProvider { context, _ ->
|
||||
(commandManager.commandHelpHandler.queryHelp(
|
||||
context.sender,
|
||||
""
|
||||
) as CommandHelpHandler.IndexHelpTopic<CommandSender>)
|
||||
.entries.map { it.syntaxString }
|
||||
}
|
||||
.build()
|
||||
}
|
||||
|
||||
fun positiveInteger(name: String): IntegerArgument.Builder<CommandSender> {
|
||||
return IntegerArgument.newBuilder<CommandSender>(name)
|
||||
.withMin(1)
|
||||
}
|
||||
fun positiveInteger(name: String): IntegerArgument.Builder<CommandSender> {
|
||||
return IntegerArgument.newBuilder<CommandSender>(name)
|
||||
.withMin(1)
|
||||
}
|
||||
|
||||
fun messageConfig(name: String): CommandArgument<CommandSender, MessageConfig> {
|
||||
return commandManager.argumentBuilder(MessageConfig::class.java, name)
|
||||
.withSuggestionsProvider { _, _ -> configManager.messageConfigs.keys.toList() }
|
||||
.withParser { _, inputQueue ->
|
||||
val input = inputQueue.peek()
|
||||
val config = configManager.messageConfigs[input]
|
||||
?: return@withParser ArgumentParseResult.failure(IllegalArgumentException(
|
||||
"No message config for name '$input'. Must be one of: ${configManager.messageConfigs.keys.joinToString(", ")}"
|
||||
))
|
||||
inputQueue.remove()
|
||||
ArgumentParseResult.success(config)
|
||||
}
|
||||
.build()
|
||||
}
|
||||
fun messageConfig(name: String): CommandArgument<CommandSender, MessageConfig> {
|
||||
return commandManager.argumentBuilder(MessageConfig::class.java, name)
|
||||
.withSuggestionsProvider { _, _ -> configManager.messageConfigs.keys.toList() }
|
||||
.withParser { _, inputQueue ->
|
||||
val input = inputQueue.peek()
|
||||
val config = configManager.messageConfigs[input]
|
||||
?: return@withParser ArgumentParseResult.failure(
|
||||
IllegalArgumentException(
|
||||
"No message config for name '$input'. Must be one of: ${configManager.messageConfigs.keys.joinToString(", ")}"
|
||||
)
|
||||
)
|
||||
inputQueue.remove()
|
||||
ArgumentParseResult.success(config)
|
||||
}
|
||||
.build()
|
||||
}
|
||||
|
||||
fun worldPlayers(name: String): CommandArgument<CommandSender, WorldPlayers> {
|
||||
return commandManager.argumentBuilder(WorldPlayers::class.java, name)
|
||||
.withSuggestionsProvider { _, _ ->
|
||||
val suggestions = Bukkit.getWorlds().map { it.name }.toMutableList()
|
||||
suggestions.add("all")
|
||||
suggestions
|
||||
}
|
||||
.withParser { _, inputQueue ->
|
||||
val input = inputQueue.peek()
|
||||
if (input == null || input.isEmpty()) {
|
||||
return@withParser ArgumentParseResult.failure(
|
||||
IllegalArgumentException("No input provided.")
|
||||
)
|
||||
}
|
||||
if (input == "all") {
|
||||
inputQueue.remove()
|
||||
return@withParser ArgumentParseResult.success(WorldPlayers(
|
||||
Bukkit.getWorlds().flatMap { it.players }
|
||||
))
|
||||
}
|
||||
val world = Bukkit.getWorld(input)
|
||||
?: return@withParser ArgumentParseResult.failure(
|
||||
IllegalArgumentException("No such world: $input")
|
||||
)
|
||||
inputQueue.remove()
|
||||
ArgumentParseResult.success(WorldPlayers(ImmutableList.copyOf(world.players)))
|
||||
}
|
||||
.build()
|
||||
}
|
||||
fun worldPlayers(name: String): CommandArgument<CommandSender, WorldPlayers> {
|
||||
return commandManager.argumentBuilder(WorldPlayers::class.java, name)
|
||||
.withSuggestionsProvider { _, _ ->
|
||||
val suggestions = Bukkit.getWorlds().map { it.name }.toMutableList()
|
||||
suggestions.add("all")
|
||||
suggestions
|
||||
}
|
||||
.withParser { _, inputQueue ->
|
||||
val input = inputQueue.peek()
|
||||
if (input.isEmpty()) {
|
||||
return@withParser ArgumentParseResult.failure(
|
||||
IllegalArgumentException("No input provided.")
|
||||
)
|
||||
}
|
||||
if (input == "all") {
|
||||
inputQueue.remove()
|
||||
return@withParser ArgumentParseResult.success(WorldPlayers(
|
||||
Bukkit.getWorlds().flatMap { it.players }
|
||||
))
|
||||
}
|
||||
val world = Bukkit.getWorld(input)
|
||||
?: return@withParser ArgumentParseResult.failure(
|
||||
IllegalArgumentException("No such world: $input")
|
||||
)
|
||||
inputQueue.remove()
|
||||
ArgumentParseResult.success(WorldPlayers(ImmutableList.copyOf(world.players)))
|
||||
}
|
||||
.build()
|
||||
}
|
||||
|
||||
data class WorldPlayers(val players: Collection<Player>)
|
||||
data class WorldPlayers(val players: Collection<Player>)
|
||||
}
|
||||
@@ -1,7 +1,30 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.command
|
||||
|
||||
import org.koin.core.KoinComponent
|
||||
|
||||
interface BaseCommand : KoinComponent {
|
||||
fun register()
|
||||
fun register()
|
||||
}
|
||||
@@ -1,8 +1,29 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.command
|
||||
|
||||
import cloud.commandframework.context.CommandContext
|
||||
import cloud.commandframework.kotlin.extension.commandBuilder
|
||||
import cloud.commandframework.kotlin.extension.description
|
||||
import cloud.commandframework.minecraft.extras.MinecraftHelp
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import net.kyori.adventure.text.Component
|
||||
@@ -19,161 +40,174 @@ import org.koin.core.inject
|
||||
import xyz.jpenilla.announcerplus.AnnouncerPlus
|
||||
import xyz.jpenilla.announcerplus.config.ConfigManager
|
||||
import xyz.jpenilla.announcerplus.config.message.MessageConfig
|
||||
import xyz.jpenilla.announcerplus.util.description
|
||||
import xyz.jpenilla.jmplib.Chat
|
||||
import java.util.Collections
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class CommandAnnouncerPlus : BaseCommand {
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val commandManager: CommandManager by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val minecraftHelp: MinecraftHelp<CommandSender> by inject()
|
||||
private val argumentFactory: ArgumentFactory by inject()
|
||||
private val chat: Chat by inject()
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val commandManager: CommandManager by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val minecraftHelp: MinecraftHelp<CommandSender> by inject()
|
||||
private val argumentFactory: ArgumentFactory by inject()
|
||||
private val chat: Chat by inject()
|
||||
|
||||
override fun register() {
|
||||
commandManager.commandBuilder("ap", aliases = arrayOf("announcerplus", "announcer")) {
|
||||
registerCopy {
|
||||
commandDescription("Shows help for AnnouncerPlus commands.")
|
||||
literal("help")
|
||||
argument(description("Help Query")) {
|
||||
argumentFactory.helpQuery("query")
|
||||
}
|
||||
handler(::executeHelp)
|
||||
}
|
||||
registerCopy {
|
||||
commandDescription("Prints some information about AnnouncerPlus.")
|
||||
literal("about")
|
||||
handler(::executeAbout)
|
||||
}
|
||||
registerCopy {
|
||||
permission = "announcerplus.reload"
|
||||
commandDescription("Reloads AnnouncerPlus configs.")
|
||||
literal("reload")
|
||||
handler(::executeReload)
|
||||
}
|
||||
registerCopy {
|
||||
permission = "announcerplus.list"
|
||||
commandDescription("Displays the chat messages of a message config to the command sender.")
|
||||
literal("list")
|
||||
argument(argumentFactory.messageConfig("config"))
|
||||
argument(argumentFactory.positiveInteger("page").asOptional())
|
||||
handler(::executeList)
|
||||
}
|
||||
override fun register() {
|
||||
commandManager.registerSubcommand("help") {
|
||||
permission = "announcerplus.command.help"
|
||||
commandDescription("Shows help for AnnouncerPlus commands.")
|
||||
argument(description("Help Query")) {
|
||||
argumentFactory.helpQuery("query")
|
||||
}
|
||||
handler(::executeHelp)
|
||||
}
|
||||
commandManager.registerSubcommand("about") {
|
||||
permission = "announcerplus.command.about"
|
||||
commandDescription("Prints some information about AnnouncerPlus.")
|
||||
handler(::executeAbout)
|
||||
}
|
||||
commandManager.registerSubcommand("reload") {
|
||||
permission = "announcerplus.command.reload"
|
||||
commandDescription("Reloads AnnouncerPlus configs.")
|
||||
handler(::executeReload)
|
||||
}
|
||||
commandManager.registerSubcommand("list") {
|
||||
permission = "announcerplus.command.list"
|
||||
commandDescription("Displays the chat messages of a message config to the command sender.")
|
||||
argument(argumentFactory.messageConfig("config"))
|
||||
argument(argumentFactory.positiveInteger("page").asOptional())
|
||||
handler(::executeList)
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeHelp(ctx: CommandContext<CommandSender>) {
|
||||
minecraftHelp.queryCommands(ctx.getOrDefault("query", "")!!, ctx.sender)
|
||||
}
|
||||
|
||||
private fun executeAbout(ctx: CommandContext<CommandSender>) {
|
||||
val color = randomColor()
|
||||
val text =
|
||||
"<hover:show_text:'<rainbow>click me!'><click:open_url:${announcerPlus.description.website}>${announcerPlus.name} <$color>${announcerPlus.description.version}"
|
||||
val header = "<gradient:white:$color:white><strikethrough>${
|
||||
"-".repeat(
|
||||
(announcerPlus.miniMessage().stripTokens(text).length / 1.2).roundToInt() + 4
|
||||
)
|
||||
}"
|
||||
listOf(
|
||||
header,
|
||||
text,
|
||||
"By <$color>jmp",
|
||||
header
|
||||
).forEach { chat.send(ctx.sender, chat.getCenteredMessage(it)) }
|
||||
}
|
||||
|
||||
private fun executeReload(ctx: CommandContext<CommandSender>) {
|
||||
chat.send(
|
||||
ctx.sender,
|
||||
chat.getCenteredMessage("<italic><gradient:${randomColor()}:${randomColor()}>Reloading ${announcerPlus.name} config...")
|
||||
)
|
||||
try {
|
||||
announcerPlus.reload()
|
||||
chat.send(ctx.sender, chat.getCenteredMessage("<green>Done."))
|
||||
} catch (e: Exception) {
|
||||
chat.send(
|
||||
ctx.sender,
|
||||
"<gradient:red:gold>I'm sorry, but there was an error reloading the plugin. This is most likely due to misconfiguration. Check console for more info."
|
||||
)
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeList(ctx: CommandContext<CommandSender>) {
|
||||
val color = randomColor()
|
||||
val config = ctx.get<MessageConfig>("config")
|
||||
val page = ctx.getOrDefault("page", 1) ?: 1
|
||||
val pagination = Pagination.builder().apply {
|
||||
resultsPerPage(17)
|
||||
width(53)
|
||||
line { line ->
|
||||
line.character('-')
|
||||
line.style(Style.style { builder ->
|
||||
builder.color(TextColor.fromHexString(color))
|
||||
builder.decorate(TextDecoration.STRIKETHROUGH)
|
||||
})
|
||||
}
|
||||
renderer(object : Pagination.Renderer {
|
||||
override fun renderNextPageButton(character: Char, style: Style, clickEvent: ClickEvent): Component {
|
||||
LinearComponents.linear(
|
||||
|
||||
)
|
||||
return Component.text()
|
||||
.append(Component.space())
|
||||
.append(Component.text("[", NamedTextColor.WHITE))
|
||||
.append(Component.text(character, style.clickEvent(clickEvent)))
|
||||
.append(Component.text("]", NamedTextColor.WHITE))
|
||||
.append(Component.space())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeHelp(ctx: CommandContext<CommandSender>) {
|
||||
minecraftHelp.queryCommands(ctx.getOrDefault("query", "")!!, ctx.sender)
|
||||
}
|
||||
|
||||
private fun executeAbout(ctx: CommandContext<CommandSender>) {
|
||||
val color = randomColor()
|
||||
val text = "<hover:show_text:'<rainbow>click me!'><click:open_url:${announcerPlus.description.website}>${announcerPlus.name} <$color>${announcerPlus.description.version}"
|
||||
val header = "<gradient:white:$color:white><strikethrough>${"-".repeat((announcerPlus.miniMessage.stripTokens(text).length / 1.2).roundToInt() + 4)}"
|
||||
listOf(
|
||||
header,
|
||||
text,
|
||||
"By <$color>jmp",
|
||||
header
|
||||
).forEach { chat.send(ctx.sender, chat.getCenteredMessage(it)) }
|
||||
}
|
||||
|
||||
private fun executeReload(ctx: CommandContext<CommandSender>) {
|
||||
chat.send(ctx.sender, chat.getCenteredMessage("<italic><gradient:${randomColor()}:${randomColor()}>Reloading ${announcerPlus.name} config..."))
|
||||
try {
|
||||
announcerPlus.reload()
|
||||
chat.send(ctx.sender, chat.getCenteredMessage("<green>Done."))
|
||||
} catch (e: Exception) {
|
||||
chat.send(ctx.sender, "<gradient:red:gold>I'm sorry, but there was an error reloading the plugin. This is most likely due to misconfiguration. Check console for more info.")
|
||||
e.printStackTrace()
|
||||
override fun renderPreviousPageButton(
|
||||
character: Char,
|
||||
style: Style,
|
||||
clickEvent: ClickEvent
|
||||
): Component {
|
||||
return Component.text()
|
||||
.append(Component.space())
|
||||
.append(Component.text("[", NamedTextColor.WHITE))
|
||||
.append(Component.text(character, style.clickEvent(clickEvent)))
|
||||
.append(Component.text("]", NamedTextColor.WHITE))
|
||||
.append(Component.space())
|
||||
.build()
|
||||
}
|
||||
}
|
||||
})
|
||||
nextButton { nextButton ->
|
||||
nextButton.style(Style.style { builder ->
|
||||
builder.decorate(TextDecoration.BOLD)
|
||||
builder.color(TextColor.fromHexString(color))
|
||||
builder.hoverEvent(HoverEvent.showText(Component.text("Next Page", NamedTextColor.GREEN)))
|
||||
})
|
||||
}
|
||||
previousButton { prevButton ->
|
||||
prevButton.style(Style.style { builder ->
|
||||
builder.decorate(TextDecoration.BOLD)
|
||||
builder.color(TextColor.fromHexString(color))
|
||||
builder.hoverEvent(HoverEvent.showText(Component.text("Previous Page", NamedTextColor.RED)))
|
||||
})
|
||||
}
|
||||
}.build<String>(
|
||||
Component.text("Messages"),
|
||||
{ value, _ -> Collections.singleton(value?.let { announcerPlus.miniMessage().parse(it) }) },
|
||||
{ "/announcerplus list ${config.name} $it" }
|
||||
)
|
||||
|
||||
private fun executeList(ctx: CommandContext<CommandSender>) {
|
||||
val color = randomColor()
|
||||
val config = ctx.get<MessageConfig>("config")
|
||||
val page = ctx.getOrDefault("page", 1) ?: 1
|
||||
val pagination = Pagination.builder().apply {
|
||||
resultsPerPage(17)
|
||||
width(53)
|
||||
line { line ->
|
||||
line.character('-')
|
||||
line.style(Style.style { builder ->
|
||||
builder.color(TextColor.fromHexString(color))
|
||||
builder.decorate(TextDecoration.STRIKETHROUGH)
|
||||
})
|
||||
}
|
||||
renderer(object : Pagination.Renderer {
|
||||
override fun renderNextPageButton(character: Char, style: Style, clickEvent: ClickEvent): Component {
|
||||
LinearComponents.linear(
|
||||
|
||||
)
|
||||
return Component.text()
|
||||
.append(Component.space())
|
||||
.append(Component.text("[", NamedTextColor.WHITE))
|
||||
.append(Component.text(character, style.clickEvent(clickEvent)))
|
||||
.append(Component.text("]", NamedTextColor.WHITE))
|
||||
.append(Component.space())
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun renderPreviousPageButton(
|
||||
character: Char,
|
||||
style: Style,
|
||||
clickEvent: ClickEvent
|
||||
): Component {
|
||||
return Component.text()
|
||||
.append(Component.space())
|
||||
.append(Component.text("[", NamedTextColor.WHITE))
|
||||
.append(Component.text(character, style.clickEvent(clickEvent)))
|
||||
.append(Component.text("]", NamedTextColor.WHITE))
|
||||
.append(Component.space())
|
||||
.build()
|
||||
}
|
||||
})
|
||||
nextButton { nextButton ->
|
||||
nextButton.style(Style.style { builder ->
|
||||
builder.decorate(TextDecoration.BOLD)
|
||||
builder.color(TextColor.fromHexString(color))
|
||||
builder.hoverEvent(HoverEvent.showText(Component.text("Next Page", NamedTextColor.GREEN)))
|
||||
})
|
||||
}
|
||||
previousButton { prevButton ->
|
||||
prevButton.style(Style.style { builder ->
|
||||
builder.decorate(TextDecoration.BOLD)
|
||||
builder.color(TextColor.fromHexString(color))
|
||||
builder.hoverEvent(HoverEvent.showText(Component.text("Previous Page", NamedTextColor.RED)))
|
||||
})
|
||||
}
|
||||
}.build<String>(
|
||||
Component.text("Messages"),
|
||||
{ value, _ -> Collections.singleton(value?.let { announcerPlus.miniMessage.parse(it) }) },
|
||||
{ "/announcerplus list ${config.name} $it" }
|
||||
)
|
||||
|
||||
val messages = arrayListOf<String>()
|
||||
for (msg in config.messages) {
|
||||
for (line in msg.messageText) {
|
||||
val b = StringBuilder()
|
||||
if (msg.messageText.indexOf(line) == 0) {
|
||||
b.append(" <color:$color>-</color:$color> ")
|
||||
} else {
|
||||
b.append(" <color:$color>-</color:$color> ")
|
||||
}
|
||||
b.append("<white>\"</white>$line<reset><white>\"")
|
||||
messages.add(configManager.parse(ctx.sender, b.toString()))
|
||||
}
|
||||
val messages = arrayListOf<String>()
|
||||
for (msg in config.messages) {
|
||||
for (line in msg.messageText) {
|
||||
val b = StringBuilder()
|
||||
if (msg.messageText.indexOf(line) == 0) {
|
||||
b.append(" <color:$color>-</color:$color> ")
|
||||
} else {
|
||||
b.append(" <color:$color>-</color:$color> ")
|
||||
}
|
||||
val l = arrayListOf<Component>(announcerPlus.miniMessage.parse("Config<gray>:</gray> <color:$color>${config.name}</color:$color> <gray><italic><hover:show_text:'<italic>Click to copy'><click:copy_to_clipboard:announcerplus.messages.${config.name}><white>(</white>announcerplus.messages.${config.name}<white>)</white>"))
|
||||
l.addAll(pagination.render(messages, page))
|
||||
chat.send(ctx.sender, l)
|
||||
b.append("<white>\"</white>$line<reset><white>\"")
|
||||
messages.add(configManager.parse(ctx.sender, b.toString()))
|
||||
}
|
||||
}
|
||||
val l = arrayListOf<Component>(
|
||||
announcerPlus.miniMessage()
|
||||
.parse("Config<gray>:</gray> <color:$color>${config.name}</color:$color> <gray><italic><hover:show_text:'<italic>Click to copy'><click:copy_to_clipboard:announcerplus.messages.${config.name}><white>(</white>announcerplus.messages.${config.name}<white>)</white>")
|
||||
)
|
||||
l.addAll(pagination.render(messages, page))
|
||||
chat.send(ctx.sender, l)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val colors = ImmutableSet.of(
|
||||
"#f44336", "#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#2196f3", "#03a9f4", "#00bcd4", "#009688", "#4caf50",
|
||||
"#8bc34a", "#cddc39", "#ffeb3b", "#ffc107", "#ff9800", "#ff5722", "#795548", "#9e9e9e", "#607d8b", "#333333")
|
||||
fun randomColor(): String = colors.random()
|
||||
}
|
||||
companion object {
|
||||
private val colors = ImmutableSet.of(
|
||||
"#f44336", "#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#2196f3", "#03a9f4", "#00bcd4", "#009688", "#4caf50",
|
||||
"#8bc34a", "#cddc39", "#ffeb3b", "#ffc107", "#ff9800", "#ff5722", "#795548", "#9e9e9e", "#607d8b", "#333333"
|
||||
)
|
||||
|
||||
fun randomColor(): String = colors.random()
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,32 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.command
|
||||
|
||||
import cloud.commandframework.arguments.standard.EnumArgument
|
||||
import cloud.commandframework.arguments.standard.StringArgument
|
||||
import cloud.commandframework.bukkit.parsers.MaterialArgument
|
||||
import cloud.commandframework.context.CommandContext
|
||||
import cloud.commandframework.kotlin.extension.commandBuilder
|
||||
import cloud.commandframework.kotlin.extension.description
|
||||
import net.kyori.adventure.bossbar.BossBar
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.koin.core.inject
|
||||
@@ -15,102 +36,99 @@ import xyz.jpenilla.announcerplus.config.message.ToastSettings
|
||||
import xyz.jpenilla.announcerplus.task.ActionBarUpdateTask
|
||||
import xyz.jpenilla.announcerplus.task.BossBarUpdateTask
|
||||
import xyz.jpenilla.announcerplus.task.TitleUpdateTask
|
||||
import xyz.jpenilla.announcerplus.util.description
|
||||
import xyz.jpenilla.jmplib.Chat
|
||||
|
||||
class CommandBroadcast : BaseCommand {
|
||||
private val commandManager: CommandManager by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val argumentFactory: ArgumentFactory by inject()
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val chat: Chat by inject()
|
||||
private val commandManager: CommandManager by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val argumentFactory: ArgumentFactory by inject()
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val chat: Chat by inject()
|
||||
|
||||
override fun register() {
|
||||
commandManager.commandBuilder("ap") {
|
||||
registerCopy("broadcast") {
|
||||
permission = "announcerplus.broadcast"
|
||||
commandDescription("Parses and broadcasts a message to chat in the specified world or all worlds.")
|
||||
argument(argumentFactory.worldPlayers("world"))
|
||||
argument(StringArgument.greedy("message"))
|
||||
handler(::executeBroadcast)
|
||||
}
|
||||
if (announcerPlus.toastTask != null) {
|
||||
registerCopy("broadcasttoast") {
|
||||
permission = "announcerplus.broadcasttoast"
|
||||
commandDescription("Parses and broadcasts a Toast style message to the specified world or all worlds.")
|
||||
argument(argumentFactory.worldPlayers("world"))
|
||||
argument(MaterialArgument.of("icon"))
|
||||
argument(EnumArgument.of(ToastSettings.FrameType::class.java, "frame"))
|
||||
argument(StringArgument.quoted("header"), description("Quoted String"))
|
||||
argument(StringArgument.quoted("body"), description("Quoted String"))
|
||||
handler(::executeBroadcastToast)
|
||||
}
|
||||
}
|
||||
registerCopy("broadcasttitle") {
|
||||
permission = "announcerplus.broadcasttitle"
|
||||
commandDescription("Parses and broadcasts a Title and Subtitle style message to the specified world or all worlds.")
|
||||
argument(argumentFactory.worldPlayers("world"))
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.quoted("title"), description("Quoted String"))
|
||||
argument(StringArgument.quoted("subtitle"), description("Quoted String"))
|
||||
handler(::executeBroadcastTitle)
|
||||
}
|
||||
registerCopy("broadcastactionbar") {
|
||||
permission = "announcerplus.broadcastactionbar"
|
||||
commandDescription("Parses and broadcasts an Action Bar style message to the specified world or all worlds.")
|
||||
argument(argumentFactory.worldPlayers("world"))
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.greedy("text"))
|
||||
handler(::executeBroadcastActionBar)
|
||||
}
|
||||
registerCopy("broadcastbossbar") {
|
||||
permission = "announcerplus.broadcastbossbar"
|
||||
commandDescription("Parses and broadcasts a Boss Bar style message to the specified world or all worlds.")
|
||||
argument(argumentFactory.worldPlayers("world"))
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(EnumArgument.of(BossBar.Overlay::class.java, "overlay"))
|
||||
argument(EnumArgument.of(BossBarUpdateTask.FillMode::class.java, "fillmode"))
|
||||
argument(EnumArgument.of(BossBar.Color::class.java, "color"))
|
||||
argument(StringArgument.greedy("text"))
|
||||
handler(::executeBroadcastBossBar)
|
||||
}
|
||||
}
|
||||
override fun register() {
|
||||
commandManager.registerSubcommand("broadcast") {
|
||||
permission = "announcerplus.command.broadcast.chat"
|
||||
commandDescription("Parses and broadcasts a message to chat in the specified world or all worlds.")
|
||||
argument(argumentFactory.worldPlayers("world"))
|
||||
argument(StringArgument.greedy("message"))
|
||||
handler(::executeBroadcast)
|
||||
}
|
||||
commandManager.registerSubcommand("broadcasttoast", announcerPlus.toastTask != null) {
|
||||
permission = "announcerplus.command.broadcast.toast"
|
||||
commandDescription("Parses and broadcasts a Toast style message to the specified world or all worlds.")
|
||||
argument(argumentFactory.worldPlayers("world"))
|
||||
argument(MaterialArgument.of("icon"))
|
||||
argument(EnumArgument.of(ToastSettings.FrameType::class.java, "frame"))
|
||||
argument(StringArgument.quoted("header"), description("Quoted String"))
|
||||
argument(StringArgument.quoted("body"), description("Quoted String"))
|
||||
handler(::executeBroadcastToast)
|
||||
}
|
||||
commandManager.registerSubcommand("broadcasttitle") {
|
||||
permission = "announcerplus.command.broadcast.title"
|
||||
commandDescription("Parses and broadcasts a Title and Subtitle style message to the specified world or all worlds.")
|
||||
argument(argumentFactory.worldPlayers("world"))
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.quoted("title"), description("Quoted String"))
|
||||
argument(StringArgument.quoted("subtitle"), description("Quoted String"))
|
||||
handler(::executeBroadcastTitle)
|
||||
}
|
||||
commandManager.registerSubcommand("broadcastactionbar") {
|
||||
permission = "announcerplus.command.broadcast.actionbar"
|
||||
commandDescription("Parses and broadcasts an Action Bar style message to the specified world or all worlds.")
|
||||
argument(argumentFactory.worldPlayers("world"))
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.greedy("text"))
|
||||
handler(::executeBroadcastActionBar)
|
||||
}
|
||||
commandManager.registerSubcommand("broadcastbossbar") {
|
||||
permission = "announcerplus.command.broadcast.bossbar"
|
||||
commandDescription("Parses and broadcasts a Boss Bar style message to the specified world or all worlds.")
|
||||
argument(argumentFactory.worldPlayers("world"))
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(EnumArgument.of(BossBar.Overlay::class.java, "overlay"))
|
||||
argument(EnumArgument.of(BossBarUpdateTask.FillMode::class.java, "fillmode"))
|
||||
argument(EnumArgument.of(BossBar.Color::class.java, "color"))
|
||||
argument(StringArgument.greedy("text"))
|
||||
handler(::executeBroadcastBossBar)
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeBroadcast(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<ArgumentFactory.WorldPlayers>("world").players) {
|
||||
chat.send(player, configManager.parse(player, ctx.get<String>("message")))
|
||||
}
|
||||
private fun executeBroadcast(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<ArgumentFactory.WorldPlayers>("world").players) {
|
||||
chat.send(player, configManager.parse(player, ctx.get<String>("message")))
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeBroadcastToast(ctx: CommandContext<CommandSender>) {
|
||||
val toast = ToastSettings(ctx.get("icon"), ctx.get("frame"), ctx.get("header"), ctx.get("body"))
|
||||
for (player in ctx.get<ArgumentFactory.WorldPlayers>("world").players) {
|
||||
toast.displayIfEnabled(player)
|
||||
}
|
||||
private fun executeBroadcastToast(ctx: CommandContext<CommandSender>) {
|
||||
val toast = ToastSettings(ctx.get("icon"), ctx.get("frame"), ctx.get("header"), ctx.get("body"))
|
||||
for (player in ctx.get<ArgumentFactory.WorldPlayers>("world").players) {
|
||||
toast.displayIfEnabled(player)
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeBroadcastTitle(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<ArgumentFactory.WorldPlayers>("world").players) {
|
||||
TitleUpdateTask(player, 0, ctx.get("seconds"), 1, ctx.get("title"), ctx.get("subtitle")).start()
|
||||
}
|
||||
private fun executeBroadcastTitle(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<ArgumentFactory.WorldPlayers>("world").players) {
|
||||
TitleUpdateTask(player, 0, ctx.get("seconds"), 1, ctx.get("title"), ctx.get("subtitle")).start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeBroadcastActionBar(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<ArgumentFactory.WorldPlayers>("world").players) {
|
||||
ActionBarUpdateTask(player, ctx.get<Int>("seconds") * 20L, true, ctx.get("text")).start()
|
||||
}
|
||||
private fun executeBroadcastActionBar(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<ArgumentFactory.WorldPlayers>("world").players) {
|
||||
ActionBarUpdateTask(player, ctx.get<Int>("seconds") * 20L, true, ctx.get("text")).start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeBroadcastBossBar(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<ArgumentFactory.WorldPlayers>("world").players) {
|
||||
BossBarUpdateTask(
|
||||
player,
|
||||
ctx.get("seconds"),
|
||||
ctx.get("overlay"),
|
||||
ctx.get("fillmode"),
|
||||
ctx.get<BossBar.Color>("color").toString(),
|
||||
ctx.get("text")
|
||||
).start()
|
||||
}
|
||||
private fun executeBroadcastBossBar(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<ArgumentFactory.WorldPlayers>("world").players) {
|
||||
BossBarUpdateTask(
|
||||
player,
|
||||
ctx.get("seconds"),
|
||||
ctx.get("overlay"),
|
||||
ctx.get("fillmode"),
|
||||
ctx.get<BossBar.Color>("color").toString(),
|
||||
ctx.get("text")
|
||||
).start()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,32 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.command
|
||||
|
||||
import cloud.commandframework.bukkit.CloudBukkitCapabilities
|
||||
import cloud.commandframework.execution.AsynchronousCommandExecutionCoordinator
|
||||
import cloud.commandframework.kotlin.MutableCommandBuilder
|
||||
import cloud.commandframework.kotlin.extension.commandBuilder
|
||||
import cloud.commandframework.minecraft.extras.MinecraftExceptionHandler
|
||||
import cloud.commandframework.minecraft.extras.MinecraftHelp
|
||||
import cloud.commandframework.paper.PaperCommandManager
|
||||
@@ -15,63 +41,80 @@ import xyz.jpenilla.announcerplus.util.Constants
|
||||
import java.util.function.Function
|
||||
|
||||
class CommandManager(announcerPlus: AnnouncerPlus) : PaperCommandManager<CommandSender>(
|
||||
announcerPlus,
|
||||
AsynchronousCommandExecutionCoordinator.newBuilder<CommandSender>().build(),
|
||||
Function.identity(),
|
||||
Function.identity()
|
||||
announcerPlus,
|
||||
AsynchronousCommandExecutionCoordinator.newBuilder<CommandSender>().build(),
|
||||
Function.identity(),
|
||||
Function.identity()
|
||||
) {
|
||||
|
||||
private val minecraftHelp = MinecraftHelp(
|
||||
"/announcerplus help",
|
||||
announcerPlus.audience::sender,
|
||||
this
|
||||
).apply {
|
||||
helpColors = MinecraftHelp.HelpColors.of(
|
||||
TextColor.color(0x00a3ff),
|
||||
NamedTextColor.WHITE,
|
||||
TextColor.color(0x284fff),
|
||||
NamedTextColor.GRAY,
|
||||
NamedTextColor.DARK_GRAY
|
||||
)
|
||||
setMessage(MinecraftHelp.MESSAGE_HELP_TITLE, "AnnouncerPlus Help")
|
||||
private val minecraftHelp = MinecraftHelp(
|
||||
"/announcerplus help",
|
||||
announcerPlus.audiences()::sender,
|
||||
this
|
||||
).apply {
|
||||
helpColors = MinecraftHelp.HelpColors.of(
|
||||
TextColor.color(0x00a3ff),
|
||||
NamedTextColor.WHITE,
|
||||
TextColor.color(0x284fff),
|
||||
NamedTextColor.GRAY,
|
||||
NamedTextColor.DARK_GRAY
|
||||
)
|
||||
setMessage(MinecraftHelp.MESSAGE_HELP_TITLE, "AnnouncerPlus Help")
|
||||
}
|
||||
|
||||
init {
|
||||
MinecraftExceptionHandler<CommandSender>()
|
||||
.withDefaultHandlers()
|
||||
.withDecorator {
|
||||
Component.text()
|
||||
.append(Constants.CHAT_PREFIX)
|
||||
.append(it)
|
||||
.build()
|
||||
}
|
||||
.apply(this, announcerPlus.audiences()::sender)
|
||||
|
||||
if (queryCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) {
|
||||
this.registerBrigadier()
|
||||
this.brigadierManager()?.setNativeNumberSuggestions(false)
|
||||
announcerPlus.logger.info("Successfully registered Mojang Brigadier support for commands.")
|
||||
}
|
||||
|
||||
init {
|
||||
MinecraftExceptionHandler<CommandSender>()
|
||||
.withDefaultHandlers()
|
||||
.withDecorator {
|
||||
Component.text()
|
||||
.append(Constants.CHAT_PREFIX)
|
||||
.append(it)
|
||||
.build()
|
||||
}
|
||||
.apply(this, announcerPlus.audience::sender)
|
||||
|
||||
try {
|
||||
this.registerBrigadier()
|
||||
this.brigadierManager()?.setNativeNumberSuggestions(false)
|
||||
announcerPlus.logger.info("Successfully registered Mojang Brigadier support for commands.")
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
||||
try {
|
||||
this.registerAsynchronousCompletions()
|
||||
announcerPlus.logger.info("Successfully registered asynchronous command completion listener.")
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
||||
loadKoinModules(module {
|
||||
single { this@CommandManager }
|
||||
single { minecraftHelp }
|
||||
single { ArgumentFactory() }
|
||||
})
|
||||
|
||||
listOf(
|
||||
CommandAnnouncerPlus(),
|
||||
CommandBroadcast(),
|
||||
CommandSend(),
|
||||
CommandParse()
|
||||
).forEach(BaseCommand::register)
|
||||
if (queryCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) {
|
||||
this.registerAsynchronousCompletions()
|
||||
announcerPlus.logger.info("Successfully registered asynchronous command completion listener.")
|
||||
}
|
||||
|
||||
loadKoinModules(module {
|
||||
single { this@CommandManager }
|
||||
single { minecraftHelp }
|
||||
single { ArgumentFactory() }
|
||||
})
|
||||
|
||||
listOf(
|
||||
CommandAnnouncerPlus(),
|
||||
CommandBroadcast(),
|
||||
CommandSend(),
|
||||
CommandParse()
|
||||
).forEach(BaseCommand::register)
|
||||
}
|
||||
|
||||
fun rootBuilder(
|
||||
lambda: MutableCommandBuilder<CommandSender>.() -> Unit = {}
|
||||
) = this.commandBuilder("ap", aliases = arrayOf("announcerplus", "announcer"), lambda = lambda)
|
||||
|
||||
fun registerSubcommand(
|
||||
literal: String,
|
||||
lambda: MutableCommandBuilder<CommandSender>.() -> Unit
|
||||
) = this.rootBuilder().literal(literal).apply(lambda).register()
|
||||
|
||||
fun registerSubcommand(
|
||||
literal: String,
|
||||
registrationPredicate: Boolean,
|
||||
lambda: MutableCommandBuilder<CommandSender>.() -> Unit
|
||||
) {
|
||||
if (registrationPredicate) {
|
||||
this.registerSubcommand(literal, lambda)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,32 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.command
|
||||
|
||||
import cloud.commandframework.arguments.standard.EnumArgument
|
||||
import cloud.commandframework.arguments.standard.StringArgument
|
||||
import cloud.commandframework.bukkit.parsers.MaterialArgument
|
||||
import cloud.commandframework.context.CommandContext
|
||||
import cloud.commandframework.kotlin.extension.commandBuilder
|
||||
import cloud.commandframework.kotlin.extension.description
|
||||
import net.kyori.adventure.bossbar.BossBar
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
@@ -16,107 +37,104 @@ import xyz.jpenilla.announcerplus.config.message.ToastSettings
|
||||
import xyz.jpenilla.announcerplus.task.ActionBarUpdateTask
|
||||
import xyz.jpenilla.announcerplus.task.BossBarUpdateTask
|
||||
import xyz.jpenilla.announcerplus.task.TitleUpdateTask
|
||||
import xyz.jpenilla.announcerplus.util.description
|
||||
import xyz.jpenilla.jmplib.Chat
|
||||
|
||||
class CommandParse : BaseCommand {
|
||||
private val commandManager: CommandManager by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val argumentFactory: ArgumentFactory by inject()
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val chat: Chat by inject()
|
||||
private val commandManager: CommandManager by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val argumentFactory: ArgumentFactory by inject()
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val chat: Chat by inject()
|
||||
|
||||
override fun register() {
|
||||
commandManager.commandBuilder("ap") {
|
||||
registerCopy("parse") {
|
||||
permission = "announcerplus.parse"
|
||||
commandDescription("Parses a message and echoes it back.")
|
||||
argument(StringArgument.greedy("message"))
|
||||
handler(::executeParse)
|
||||
}
|
||||
if (announcerPlus.toastTask != null) {
|
||||
registerCopy("parsetoast") {
|
||||
permission = "announcerplus.parsetoast"
|
||||
senderType<Player>()
|
||||
commandDescription("Parses a Toast style message and displays it to the command sender.")
|
||||
argument(MaterialArgument.of("icon"))
|
||||
argument(EnumArgument.of(ToastSettings.FrameType::class.java, "frame"))
|
||||
argument(StringArgument.quoted("header"), description("Quoted String"))
|
||||
argument(StringArgument.quoted("body"), description("Quoted String"))
|
||||
handler(::executeParseToast)
|
||||
}
|
||||
}
|
||||
registerCopy("parsetitle") {
|
||||
permission = "announcerplus.parsetitle"
|
||||
senderType<Player>()
|
||||
commandDescription("Parses a Title and Subtitle style message and displays it to the command sender.")
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.quoted("title"), description("Quoted String"))
|
||||
argument(StringArgument.quoted("subtitle"), description("Quoted String"))
|
||||
handler(::executeParseTitle)
|
||||
}
|
||||
registerCopy("parseactionbar") {
|
||||
permission = "announcerplus.parseactionbar"
|
||||
senderType<Player>()
|
||||
commandDescription("Parses an Action Bar style message and displays it to the command sender.")
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.greedy("text"))
|
||||
handler(::executeParseActionBar)
|
||||
}
|
||||
registerCopy("parsebossbar") {
|
||||
permission = "announcerplus.parsebossbar"
|
||||
senderType<Player>()
|
||||
commandDescription("Parses a Boss Bar style message and displays it to the command sender.")
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(EnumArgument.of(BossBar.Overlay::class.java, "overlay"))
|
||||
argument(EnumArgument.of(BossBarUpdateTask.FillMode::class.java, "fillmode"))
|
||||
argument(EnumArgument.of(BossBar.Color::class.java, "color"))
|
||||
argument(StringArgument.greedy("text"))
|
||||
handler(::executeParseBossBar)
|
||||
}
|
||||
registerCopy("parseanimation") {
|
||||
permission = "announcerplus.parseanimation"
|
||||
senderType<Player>()
|
||||
commandDescription("Parses a message with an animation and displays it to the command sender.")
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.greedy("message"))
|
||||
handler(::executeParseAnimation)
|
||||
}
|
||||
}
|
||||
override fun register() {
|
||||
commandManager.registerSubcommand("parse") {
|
||||
permission = "announcerplus.command.parse.chat"
|
||||
commandDescription("Parses a message and echoes it back.")
|
||||
argument(StringArgument.greedy("message"))
|
||||
handler(::executeParse)
|
||||
}
|
||||
commandManager.registerSubcommand("parsetoast", announcerPlus.toastTask != null) {
|
||||
permission = "announcerplus.command.parse.toast"
|
||||
senderType<Player>()
|
||||
commandDescription("Parses a Toast style message and displays it to the command sender.")
|
||||
argument(MaterialArgument.of("icon"))
|
||||
argument(EnumArgument.of(ToastSettings.FrameType::class.java, "frame"))
|
||||
argument(StringArgument.quoted("header"), description("Quoted String"))
|
||||
argument(StringArgument.quoted("body"), description("Quoted String"))
|
||||
handler(::executeParseToast)
|
||||
}
|
||||
commandManager.registerSubcommand("parsetitle") {
|
||||
permission = "announcerplus.command.parse.title"
|
||||
senderType<Player>()
|
||||
commandDescription("Parses a Title and Subtitle style message and displays it to the command sender.")
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.quoted("title"), description("Quoted String"))
|
||||
argument(StringArgument.quoted("subtitle"), description("Quoted String"))
|
||||
handler(::executeParseTitle)
|
||||
}
|
||||
commandManager.registerSubcommand("parseactionbar") {
|
||||
permission = "announcerplus.command.parse.actionbar"
|
||||
senderType<Player>()
|
||||
commandDescription("Parses an Action Bar style message and displays it to the command sender.")
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.greedy("text"))
|
||||
handler(::executeParseActionBar)
|
||||
}
|
||||
commandManager.registerSubcommand("parsebossbar") {
|
||||
permission = "announcerplus.command.parse.bossbar"
|
||||
senderType<Player>()
|
||||
commandDescription("Parses a Boss Bar style message and displays it to the command sender.")
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(EnumArgument.of(BossBar.Overlay::class.java, "overlay"))
|
||||
argument(EnumArgument.of(BossBarUpdateTask.FillMode::class.java, "fillmode"))
|
||||
argument(EnumArgument.of(BossBar.Color::class.java, "color"))
|
||||
argument(StringArgument.greedy("text"))
|
||||
handler(::executeParseBossBar)
|
||||
}
|
||||
commandManager.registerSubcommand("parseanimation") {
|
||||
permission = "announcerplus.command.parse.animation"
|
||||
senderType<Player>()
|
||||
commandDescription("Parses a message with an animation and displays it to the command sender.")
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.greedy("message"))
|
||||
handler(::executeParseAnimation)
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeParse(ctx: CommandContext<CommandSender>) {
|
||||
chat.send(ctx.sender, configManager.parse(ctx.sender, ctx.get<String>("message")))
|
||||
}
|
||||
private fun executeParse(ctx: CommandContext<CommandSender>) {
|
||||
chat.send(ctx.sender, configManager.parse(ctx.sender, ctx.get<String>("message")))
|
||||
}
|
||||
|
||||
private fun executeParseToast(ctx: CommandContext<CommandSender>) {
|
||||
val toast = ToastSettings(ctx.get("icon"), ctx.get("frame"), ctx.get("header"), ctx.get("body"))
|
||||
toast.displayIfEnabled(ctx.sender as Player)
|
||||
}
|
||||
private fun executeParseToast(ctx: CommandContext<CommandSender>) {
|
||||
val toast = ToastSettings(ctx.get("icon"), ctx.get("frame"), ctx.get("header"), ctx.get("body"))
|
||||
toast.displayIfEnabled(ctx.sender as Player)
|
||||
}
|
||||
|
||||
private fun executeParseTitle(ctx: CommandContext<CommandSender>) {
|
||||
TitleUpdateTask(ctx.sender as Player, 0, ctx.get("seconds"), 1, ctx.get("title"), ctx.get("subtitle")).start()
|
||||
}
|
||||
private fun executeParseTitle(ctx: CommandContext<CommandSender>) {
|
||||
TitleUpdateTask(ctx.sender as Player, 0, ctx.get("seconds"), 1, ctx.get("title"), ctx.get("subtitle")).start()
|
||||
}
|
||||
|
||||
private fun executeParseActionBar(ctx: CommandContext<CommandSender>) {
|
||||
ActionBarUpdateTask(ctx.sender as Player, ctx.get<Int>("seconds") * 20L, true, ctx.get("text")).start()
|
||||
}
|
||||
private fun executeParseActionBar(ctx: CommandContext<CommandSender>) {
|
||||
ActionBarUpdateTask(ctx.sender as Player, ctx.get<Int>("seconds") * 20L, true, ctx.get("text")).start()
|
||||
}
|
||||
|
||||
private fun executeParseBossBar(ctx: CommandContext<CommandSender>) {
|
||||
BossBarUpdateTask(
|
||||
ctx.sender as Player,
|
||||
ctx.get("seconds"),
|
||||
ctx.get("overlay"),
|
||||
ctx.get("fillmode"),
|
||||
ctx.get<BossBar.Color>("color").toString(),
|
||||
ctx.get("text")
|
||||
).start()
|
||||
}
|
||||
private fun executeParseBossBar(ctx: CommandContext<CommandSender>) {
|
||||
BossBarUpdateTask(
|
||||
ctx.sender as Player,
|
||||
ctx.get("seconds"),
|
||||
ctx.get("overlay"),
|
||||
ctx.get("fillmode"),
|
||||
ctx.get<BossBar.Color>("color").toString(),
|
||||
ctx.get("text")
|
||||
).start()
|
||||
}
|
||||
|
||||
private fun executeParseAnimation(ctx: CommandContext<CommandSender>) {
|
||||
val player = ctx.sender as Player
|
||||
val seconds = ctx.get<Int>("seconds")
|
||||
val message = ctx.get<String>("message")
|
||||
TitleUpdateTask(player, 0, seconds, 0, message, message).start()
|
||||
ActionBarUpdateTask(player, seconds * 20L, false, message).start()
|
||||
}
|
||||
private fun executeParseAnimation(ctx: CommandContext<CommandSender>) {
|
||||
val player = ctx.sender as Player
|
||||
val seconds = ctx.get<Int>("seconds")
|
||||
val message = ctx.get<String>("message")
|
||||
TitleUpdateTask(player, 0, seconds, 0, message, message).start()
|
||||
ActionBarUpdateTask(player, seconds * 20L, false, message).start()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.command
|
||||
|
||||
import cloud.commandframework.arguments.standard.EnumArgument
|
||||
@@ -6,8 +29,6 @@ import cloud.commandframework.bukkit.arguments.selector.MultiplePlayerSelector
|
||||
import cloud.commandframework.bukkit.parsers.MaterialArgument
|
||||
import cloud.commandframework.bukkit.parsers.selector.MultiplePlayerSelectorArgument
|
||||
import cloud.commandframework.context.CommandContext
|
||||
import cloud.commandframework.kotlin.extension.commandBuilder
|
||||
import cloud.commandframework.kotlin.extension.description
|
||||
import net.kyori.adventure.bossbar.BossBar
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.koin.core.inject
|
||||
@@ -17,102 +38,99 @@ import xyz.jpenilla.announcerplus.config.message.ToastSettings
|
||||
import xyz.jpenilla.announcerplus.task.ActionBarUpdateTask
|
||||
import xyz.jpenilla.announcerplus.task.BossBarUpdateTask
|
||||
import xyz.jpenilla.announcerplus.task.TitleUpdateTask
|
||||
import xyz.jpenilla.announcerplus.util.description
|
||||
import xyz.jpenilla.jmplib.Chat
|
||||
|
||||
class CommandSend : BaseCommand {
|
||||
private val commandManager: CommandManager by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val argumentFactory: ArgumentFactory by inject()
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val chat: Chat by inject()
|
||||
private val commandManager: CommandManager by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val argumentFactory: ArgumentFactory by inject()
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val chat: Chat by inject()
|
||||
|
||||
override fun register() {
|
||||
commandManager.commandBuilder("ap") {
|
||||
registerCopy("send") {
|
||||
permission = "announcerplus.send"
|
||||
commandDescription("Parses a message and sends it to the specified players.")
|
||||
argument(MultiplePlayerSelectorArgument.of("players"))
|
||||
argument(StringArgument.greedy("message"))
|
||||
handler(::executeSend)
|
||||
}
|
||||
if (announcerPlus.toastTask != null) {
|
||||
registerCopy("sendtoast") {
|
||||
permission = "announcerplus.sendtoast"
|
||||
commandDescription("Parses and sends a Toast style message to the specified players.")
|
||||
argument(MultiplePlayerSelectorArgument.of("players"))
|
||||
argument(MaterialArgument.of("icon"))
|
||||
argument(EnumArgument.of(ToastSettings.FrameType::class.java, "frame"))
|
||||
argument(StringArgument.quoted("header"), description("Quoted String"))
|
||||
argument(StringArgument.quoted("body"), description("Quoted String"))
|
||||
handler(::executeSendToast)
|
||||
}
|
||||
}
|
||||
registerCopy("sendtitle") {
|
||||
permission = "announcerplus.sendtitle"
|
||||
commandDescription("Parses and sends a Title and Subtitle style message to the specified players.")
|
||||
argument(MultiplePlayerSelectorArgument.of("players"))
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.quoted("title"), description("Quoted String"))
|
||||
argument(StringArgument.quoted("subtitle"), description("Quoted String"))
|
||||
handler(::executeSendTitle)
|
||||
}
|
||||
registerCopy("sendactionbar") {
|
||||
permission = "announcerplus.sendactionbar"
|
||||
commandDescription("Parses and sends an Action Bar style message to the specified players.")
|
||||
argument(MultiplePlayerSelectorArgument.of("players"))
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.greedy("text"))
|
||||
handler(::executeSendActionBar)
|
||||
}
|
||||
registerCopy("sendbossbar") {
|
||||
permission = "announcerplus.sendbossbar"
|
||||
commandDescription("Parses and sends a Boss Bar style message to the specified players.")
|
||||
argument(MultiplePlayerSelectorArgument.of("players"))
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(EnumArgument.of(BossBar.Overlay::class.java, "overlay"))
|
||||
argument(EnumArgument.of(BossBarUpdateTask.FillMode::class.java, "fillmode"))
|
||||
argument(EnumArgument.of(BossBar.Color::class.java, "color"))
|
||||
argument(StringArgument.greedy("text"))
|
||||
handler(::executeSendBossBar)
|
||||
}
|
||||
}
|
||||
override fun register() {
|
||||
commandManager.registerSubcommand("send") {
|
||||
permission = "announcerplus.command.send.chat"
|
||||
commandDescription("Parses a message and sends it to the specified players.")
|
||||
argument(MultiplePlayerSelectorArgument.of("players"))
|
||||
argument(StringArgument.greedy("message"))
|
||||
handler(::executeSend)
|
||||
}
|
||||
commandManager.registerSubcommand("sendtoast", announcerPlus.toastTask != null) {
|
||||
permission = "announcerplus.command.send.toast"
|
||||
commandDescription("Parses and sends a Toast style message to the specified players.")
|
||||
argument(MultiplePlayerSelectorArgument.of("players"))
|
||||
argument(MaterialArgument.of("icon"))
|
||||
argument(EnumArgument.of(ToastSettings.FrameType::class.java, "frame"))
|
||||
argument(StringArgument.quoted("header"), description("Quoted String"))
|
||||
argument(StringArgument.quoted("body"), description("Quoted String"))
|
||||
handler(::executeSendToast)
|
||||
}
|
||||
commandManager.registerSubcommand("sendtitle") {
|
||||
permission = "announcerplus.command.send.title"
|
||||
commandDescription("Parses and sends a Title and Subtitle style message to the specified players.")
|
||||
argument(MultiplePlayerSelectorArgument.of("players"))
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.quoted("title"), description("Quoted String"))
|
||||
argument(StringArgument.quoted("subtitle"), description("Quoted String"))
|
||||
handler(::executeSendTitle)
|
||||
}
|
||||
commandManager.registerSubcommand("sendactionbar") {
|
||||
permission = "announcerplus.command.send.actionbar"
|
||||
commandDescription("Parses and sends an Action Bar style message to the specified players.")
|
||||
argument(MultiplePlayerSelectorArgument.of("players"))
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(StringArgument.greedy("text"))
|
||||
handler(::executeSendActionBar)
|
||||
}
|
||||
commandManager.registerSubcommand("sendbossbar") {
|
||||
permission = "announcerplus.command.send.bossbar"
|
||||
commandDescription("Parses and sends a Boss Bar style message to the specified players.")
|
||||
argument(MultiplePlayerSelectorArgument.of("players"))
|
||||
argument(argumentFactory.positiveInteger("seconds"))
|
||||
argument(EnumArgument.of(BossBar.Overlay::class.java, "overlay"))
|
||||
argument(EnumArgument.of(BossBarUpdateTask.FillMode::class.java, "fillmode"))
|
||||
argument(EnumArgument.of(BossBar.Color::class.java, "color"))
|
||||
argument(StringArgument.greedy("text"))
|
||||
handler(::executeSendBossBar)
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeSend(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<MultiplePlayerSelector>("players").players) {
|
||||
chat.send(player, configManager.parse(player, ctx.get<String>("message")))
|
||||
}
|
||||
private fun executeSend(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<MultiplePlayerSelector>("players").players) {
|
||||
chat.send(player, configManager.parse(player, ctx.get<String>("message")))
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeSendToast(ctx: CommandContext<CommandSender>) {
|
||||
val toast = ToastSettings(ctx.get("icon"), ctx.get("frame"), ctx.get("header"), ctx.get("body"))
|
||||
for (player in ctx.get<MultiplePlayerSelector>("players").players) {
|
||||
toast.displayIfEnabled(player)
|
||||
}
|
||||
private fun executeSendToast(ctx: CommandContext<CommandSender>) {
|
||||
val toast = ToastSettings(ctx.get("icon"), ctx.get("frame"), ctx.get("header"), ctx.get("body"))
|
||||
for (player in ctx.get<MultiplePlayerSelector>("players").players) {
|
||||
toast.displayIfEnabled(player)
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeSendTitle(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<MultiplePlayerSelector>("players").players) {
|
||||
TitleUpdateTask(player, 0, ctx.get("seconds"), 1, ctx.get("title"), ctx.get("subtitle")).start()
|
||||
}
|
||||
private fun executeSendTitle(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<MultiplePlayerSelector>("players").players) {
|
||||
TitleUpdateTask(player, 0, ctx.get("seconds"), 1, ctx.get("title"), ctx.get("subtitle")).start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeSendActionBar(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<MultiplePlayerSelector>("players").players) {
|
||||
ActionBarUpdateTask(player, ctx.get<Int>("seconds") * 20L, true, ctx.get("text")).start()
|
||||
}
|
||||
private fun executeSendActionBar(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<MultiplePlayerSelector>("players").players) {
|
||||
ActionBarUpdateTask(player, ctx.get<Int>("seconds") * 20L, true, ctx.get("text")).start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeSendBossBar(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<MultiplePlayerSelector>("players").players) {
|
||||
BossBarUpdateTask(
|
||||
player,
|
||||
ctx.get("seconds"),
|
||||
ctx.get("overlay"),
|
||||
ctx.get("fillmode"),
|
||||
ctx.get<BossBar.Color>("color").toString(),
|
||||
ctx.get("text")
|
||||
).start()
|
||||
}
|
||||
private fun executeSendBossBar(ctx: CommandContext<CommandSender>) {
|
||||
for (player in ctx.get<MultiplePlayerSelector>("players").players) {
|
||||
BossBarUpdateTask(
|
||||
player,
|
||||
ctx.get("seconds"),
|
||||
ctx.get("overlay"),
|
||||
ctx.get("fillmode"),
|
||||
ctx.get<BossBar.Color>("color").toString(),
|
||||
ctx.get("text")
|
||||
).start()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package xyz.jpenilla.announcerplus.compatability
|
||||
|
||||
import net.ess3.api.IEssentials
|
||||
import net.ess3.api.IUser
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class EssentialsHook {
|
||||
val essentials = Bukkit.getServer().pluginManager.getPlugin("Essentials") as IEssentials
|
||||
|
||||
fun isAfk(player: Player): Boolean {
|
||||
return user(player).isAfk
|
||||
}
|
||||
|
||||
fun isVanished(player: Player): Boolean {
|
||||
return user(player).isVanished
|
||||
}
|
||||
|
||||
fun user(player: Player): IUser {
|
||||
return essentials.getUser(player)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.compatibility
|
||||
|
||||
import net.ess3.api.IEssentials
|
||||
import net.ess3.api.IUser
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class EssentialsHook {
|
||||
val essentials = Bukkit.getServer().pluginManager.getPlugin("Essentials") as IEssentials
|
||||
|
||||
fun isAfk(player: Player): Boolean {
|
||||
return user(player).isAfk
|
||||
}
|
||||
|
||||
fun isVanished(player: Player): Boolean {
|
||||
return user(player).isVanished
|
||||
}
|
||||
|
||||
fun user(player: Player): IUser {
|
||||
return essentials.getUser(player)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.config
|
||||
|
||||
import org.bukkit.command.CommandSender
|
||||
@@ -14,71 +37,73 @@ import java.nio.file.Files
|
||||
import kotlin.streams.toList
|
||||
|
||||
class ConfigManager(private val announcerPlus: AnnouncerPlus) {
|
||||
private val serializers: TypeSerializerCollection
|
||||
private val configOptions: ConfigurationOptions
|
||||
private val serializers: TypeSerializerCollection
|
||||
private val configOptions: ConfigurationOptions
|
||||
|
||||
private val mainConfigPath = announcerPlus.dataFolder.toPath().resolve("main.conf")
|
||||
private val mainConfigLoader: HoconConfigurationLoader
|
||||
lateinit var mainConfig: MainConfig
|
||||
private val mainConfigPath = announcerPlus.dataFolder.toPath().resolve("main.conf")
|
||||
private val mainConfigLoader: HoconConfigurationLoader
|
||||
lateinit var mainConfig: MainConfig
|
||||
|
||||
private val firstJoinConfigPath = announcerPlus.dataFolder.toPath().resolve("first-join.conf")
|
||||
private val firstJoinConfigLoader: HoconConfigurationLoader
|
||||
lateinit var firstJoinConfig: JoinQuitConfig
|
||||
private val firstJoinConfigPath = announcerPlus.dataFolder.toPath().resolve("first-join.conf")
|
||||
private val firstJoinConfigLoader: HoconConfigurationLoader
|
||||
lateinit var firstJoinConfig: JoinQuitConfig
|
||||
|
||||
private val mapperFactory = ObjectMapper.factoryBuilder()
|
||||
.addNodeResolver { name, _ ->
|
||||
/* We don't want to attempt serializing delegated properties, and they can't be @Transient */
|
||||
if (name.endsWith("delegate")) {
|
||||
NodeResolver.SKIP_FIELD
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}.build()
|
||||
private val mapperFactory = ObjectMapper.factoryBuilder()
|
||||
.addNodeResolver { name, _ ->
|
||||
/* We don't want to attempt serializing delegated properties, and they can't be @Transient */
|
||||
if (name.endsWith("delegate")) {
|
||||
NodeResolver.SKIP_FIELD
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}.build()
|
||||
|
||||
val messageConfigs = hashMapOf<String, MessageConfig>()
|
||||
val joinQuitConfigs = hashMapOf<String, JoinQuitConfig>()
|
||||
val messageConfigs = hashMapOf<String, MessageConfig>()
|
||||
val joinQuitConfigs = hashMapOf<String, JoinQuitConfig>()
|
||||
|
||||
init {
|
||||
serializers = TypeSerializerCollection.defaults().childBuilder()
|
||||
.registerAnnotatedObjects(mapperFactory)
|
||||
.build()
|
||||
init {
|
||||
serializers = TypeSerializerCollection.defaults().childBuilder()
|
||||
.registerAnnotatedObjects(mapperFactory)
|
||||
.build()
|
||||
|
||||
configOptions = ConfigurationOptions.defaults().serializers(serializers)
|
||||
configOptions = ConfigurationOptions.defaults().serializers(serializers)
|
||||
|
||||
mainConfigLoader = HoconConfigurationLoader.builder().path(mainConfigPath).build()
|
||||
firstJoinConfigLoader = HoconConfigurationLoader.builder().path(firstJoinConfigPath).build()
|
||||
mainConfigLoader = HoconConfigurationLoader.builder().path(mainConfigPath).build()
|
||||
firstJoinConfigLoader = HoconConfigurationLoader.builder().path(firstJoinConfigPath).build()
|
||||
|
||||
reload()
|
||||
reload()
|
||||
}
|
||||
|
||||
fun reload() {
|
||||
load()
|
||||
save()
|
||||
}
|
||||
|
||||
private fun load() {
|
||||
Files.createDirectories(announcerPlus.dataFolder.toPath())
|
||||
|
||||
val mainConfigRoot = mainConfigLoader.load(configOptions)
|
||||
try {
|
||||
mainConfig = MainConfig.loadFrom(mainConfigRoot)
|
||||
} catch (e: Exception) {
|
||||
throw InvalidConfigurationException("Failed to load the main.conf config file. This is due to misconfiguration", e)
|
||||
}
|
||||
|
||||
fun reload() {
|
||||
load()
|
||||
save()
|
||||
val firstJoinConfigRoot = firstJoinConfigLoader.load(configOptions)
|
||||
try {
|
||||
firstJoinConfig = JoinQuitConfig.loadFrom(firstJoinConfigRoot, null)
|
||||
} catch (e: Exception) {
|
||||
throw InvalidConfigurationException("Failed to load the main.conf config file. This is due to misconfiguration", e)
|
||||
}
|
||||
|
||||
private fun load() {
|
||||
Files.createDirectories(announcerPlus.dataFolder.toPath())
|
||||
loadMessageConfigs()
|
||||
loadJoinQuitConfigs()
|
||||
}
|
||||
|
||||
val mainConfigRoot = mainConfigLoader.load(configOptions)
|
||||
try {
|
||||
mainConfig = MainConfig.loadFrom(mainConfigRoot)
|
||||
} catch (e: Exception) {
|
||||
throw InvalidConfigurationException("Failed to load the main.conf config file. This is due to misconfiguration", e)
|
||||
}
|
||||
|
||||
val firstJoinConfigRoot = firstJoinConfigLoader.load(configOptions)
|
||||
try {
|
||||
firstJoinConfig = JoinQuitConfig.loadFrom(firstJoinConfigRoot, null)
|
||||
} catch (e: Exception) {
|
||||
throw InvalidConfigurationException("Failed to load the main.conf config file. This is due to misconfiguration", e)
|
||||
}
|
||||
|
||||
loadMessageConfigs()
|
||||
loadJoinQuitConfigs()
|
||||
}
|
||||
|
||||
private fun save() {
|
||||
val mainConfigRoot = mainConfigLoader.createNode(configOptions.header("""
|
||||
private fun save() {
|
||||
val mainConfigRoot = mainConfigLoader.createNode(
|
||||
configOptions.header(
|
||||
"""
|
||||
| ___ ____ __ __
|
||||
| / | ____ ____ ____ __ ______ ________ _____/ __ \/ /_ _______ __/ /_
|
||||
| / /| | / __ \/ __ \/ __ \/ / / / __ \/ ___/ _ \/ ___/ /_/ / / / / / ___/ /_ __/
|
||||
@@ -86,98 +111,108 @@ class ConfigManager(private val announcerPlus: AnnouncerPlus) {
|
||||
| /_/ |_/_/ /_/_/ /_/\____/\__,_/_/ /_/\___/\___/_/ /_/ /_/\__,_/____/
|
||||
|
|
||||
| v${announcerPlus.description.version}
|
||||
""".trimMargin()))
|
||||
mainConfig.saveTo(mainConfigRoot)
|
||||
mainConfigLoader.save(mainConfigRoot)
|
||||
""".trimMargin()
|
||||
)
|
||||
)
|
||||
mainConfig.saveTo(mainConfigRoot)
|
||||
mainConfigLoader.save(mainConfigRoot)
|
||||
|
||||
val firstJoinConfigRoot = firstJoinConfigLoader.createNode(configOptions.header(
|
||||
"If enabled in main.conf, this join config will be used when players join the server for the first time.\n" +
|
||||
"All other join configs will be skipped for first-join if this is enabled."
|
||||
))
|
||||
firstJoinConfig.saveTo(firstJoinConfigRoot)
|
||||
firstJoinConfigRoot.removeChild("quit-section")
|
||||
firstJoinConfigLoader.save(firstJoinConfigRoot)
|
||||
val firstJoinConfigRoot = firstJoinConfigLoader.createNode(
|
||||
configOptions.header(
|
||||
"If enabled in main.conf, this join config will be used when players join the server for the first time.\n" +
|
||||
"All other join configs will be skipped for first-join if this is enabled."
|
||||
)
|
||||
)
|
||||
firstJoinConfig.saveTo(firstJoinConfigRoot)
|
||||
firstJoinConfigRoot.removeChild("quit-section")
|
||||
firstJoinConfigLoader.save(firstJoinConfigRoot)
|
||||
}
|
||||
|
||||
private fun loadJoinQuitConfigs() {
|
||||
joinQuitConfigs.clear()
|
||||
val path = announcerPlus.dataFolder.toPath().resolve("join-quit-configs")
|
||||
if (!Files.exists(path)) {
|
||||
announcerPlus.logger.info("Creating join quit config folder")
|
||||
Files.createDirectories(path)
|
||||
}
|
||||
if (Files.list(path).toList().isEmpty()) {
|
||||
announcerPlus.logger.info("No join/quit configs found, creating default.conf")
|
||||
|
||||
private fun loadJoinQuitConfigs() {
|
||||
joinQuitConfigs.clear()
|
||||
val path = announcerPlus.dataFolder.toPath().resolve("join-quit-configs")
|
||||
if (!Files.exists(path)) {
|
||||
announcerPlus.logger.info("Creating join quit config folder")
|
||||
Files.createDirectories(path)
|
||||
}
|
||||
if (Files.list(path).toList().isEmpty()) {
|
||||
announcerPlus.logger.info("No join/quit configs found, creating default.conf")
|
||||
|
||||
val defaultConfig = path.resolve("default.conf")
|
||||
val defaultConfigLoader = HoconConfigurationLoader.builder().path(defaultConfig).build()
|
||||
val defaultConfigRoot = defaultConfigLoader.createNode(configOptions.header(
|
||||
"To give a player these join/quit messages give them the announcerplus.join.default\n" +
|
||||
" and announcerplus.quit.default permissions"))
|
||||
JoinQuitConfig().saveTo(defaultConfigRoot)
|
||||
defaultConfigLoader.save(defaultConfigRoot)
|
||||
}
|
||||
Files.list(path).forEach {
|
||||
val configLoader = HoconConfigurationLoader.builder().path(it).build()
|
||||
val name = it.toFile().nameWithoutExtension
|
||||
try {
|
||||
val root = configLoader.load(configOptions)
|
||||
joinQuitConfigs[name] = JoinQuitConfig.loadFrom(root, name)
|
||||
|
||||
joinQuitConfigs[name]?.saveTo(root)
|
||||
configLoader.save(root)
|
||||
} catch (e: Exception) {
|
||||
throw InvalidConfigurationException("Failed to load message config: ${it.fileName}. This is due to an invalid config file.", e)
|
||||
}
|
||||
}
|
||||
val defaultConfig = path.resolve("default.conf")
|
||||
val defaultConfigLoader = HoconConfigurationLoader.builder().path(defaultConfig).build()
|
||||
val defaultConfigRoot = defaultConfigLoader.createNode(
|
||||
configOptions.header(
|
||||
"To give a player these join/quit messages give them the announcerplus.join.default\n" +
|
||||
" and announcerplus.quit.default permissions"
|
||||
)
|
||||
)
|
||||
JoinQuitConfig().saveTo(defaultConfigRoot)
|
||||
defaultConfigLoader.save(defaultConfigRoot)
|
||||
}
|
||||
Files.list(path).forEach {
|
||||
val configLoader = HoconConfigurationLoader.builder().path(it).build()
|
||||
val name = it.toFile().nameWithoutExtension
|
||||
try {
|
||||
val root = configLoader.load(configOptions)
|
||||
joinQuitConfigs[name] = JoinQuitConfig.loadFrom(root, name)
|
||||
|
||||
private fun loadMessageConfigs() {
|
||||
messageConfigs.values.forEach(MessageConfig::stop)
|
||||
messageConfigs.clear()
|
||||
val path = announcerPlus.dataFolder.toPath().resolve("message-configs")
|
||||
if (!Files.exists(path)) {
|
||||
announcerPlus.logger.info("Creating message config folder")
|
||||
Files.createDirectories(path)
|
||||
}
|
||||
if (Files.list(path).toList().isEmpty()) {
|
||||
announcerPlus.logger.info("No message configs found, creating demo.conf")
|
||||
joinQuitConfigs[name]?.saveTo(root)
|
||||
configLoader.save(root)
|
||||
} catch (e: Exception) {
|
||||
throw InvalidConfigurationException("Failed to load message config: ${it.fileName}. This is due to an invalid config file.", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val defaultConfig = path.resolve("demo.conf")
|
||||
val defaultConfigLoader = HoconConfigurationLoader.builder().path(defaultConfig).build()
|
||||
val defaultConfigRoot = defaultConfigLoader.createNode(configOptions.header(
|
||||
"""For a player to get these messages give them the announcerplus.messages.demo permission
|
||||
private fun loadMessageConfigs() {
|
||||
messageConfigs.values.forEach(MessageConfig::stop)
|
||||
messageConfigs.clear()
|
||||
val path = announcerPlus.dataFolder.toPath().resolve("message-configs")
|
||||
if (!Files.exists(path)) {
|
||||
announcerPlus.logger.info("Creating message config folder")
|
||||
Files.createDirectories(path)
|
||||
}
|
||||
if (Files.list(path).toList().isEmpty()) {
|
||||
announcerPlus.logger.info("No message configs found, creating demo.conf")
|
||||
|
||||
val defaultConfig = path.resolve("demo.conf")
|
||||
val defaultConfigLoader = HoconConfigurationLoader.builder().path(defaultConfig).build()
|
||||
val defaultConfigRoot = defaultConfigLoader.createNode(
|
||||
configOptions.header(
|
||||
"""For a player to get these messages give them the announcerplus.messages.demo permission
|
||||
| If EssentialsX is installed, then giving a player the announcerplus.messages.demo.afk permission
|
||||
| will stop them from receiving these messages while afk""".trimMargin()))
|
||||
MessageConfig().saveTo(defaultConfigRoot)
|
||||
defaultConfigLoader.save(defaultConfigRoot)
|
||||
}
|
||||
Files.list(path).forEach {
|
||||
val configLoader = HoconConfigurationLoader.builder().path(it).build()
|
||||
val name = it.toFile().nameWithoutExtension
|
||||
try {
|
||||
val root = configLoader.load(configOptions)
|
||||
messageConfigs[name] = MessageConfig.loadFrom(root, name)
|
||||
| will stop them from receiving these messages while afk""".trimMargin()
|
||||
)
|
||||
)
|
||||
MessageConfig().saveTo(defaultConfigRoot)
|
||||
defaultConfigLoader.save(defaultConfigRoot)
|
||||
}
|
||||
Files.list(path).forEach {
|
||||
val configLoader = HoconConfigurationLoader.builder().path(it).build()
|
||||
val name = it.toFile().nameWithoutExtension
|
||||
try {
|
||||
val root = configLoader.load(configOptions)
|
||||
messageConfigs[name] = MessageConfig.loadFrom(root, name)
|
||||
|
||||
messageConfigs[name]?.saveTo(root)
|
||||
configLoader.save(root)
|
||||
} catch (e: Exception) {
|
||||
throw InvalidConfigurationException("Failed to load join/quit config: ${it.fileName}. This is due to an invalid config file.", e)
|
||||
}
|
||||
}
|
||||
messageConfigs[name]?.saveTo(root)
|
||||
configLoader.save(root)
|
||||
} catch (e: Exception) {
|
||||
throw InvalidConfigurationException("Failed to load join/quit config: ${it.fileName}. This is due to an invalid config file.", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun parse(player: CommandSender?, message: String): String {
|
||||
val p = player as? Player
|
||||
|
||||
val msg = announcerPlus.chat().parse(p, message, mainConfig.customPlaceholders)
|
||||
if (msg.startsWith("<center>")) {
|
||||
return announcerPlus.chat().getCenteredMessage(msg.replace("<center>", ""))
|
||||
}
|
||||
|
||||
fun parse(player: CommandSender?, message: String): String {
|
||||
val p = player as? Player
|
||||
return msg
|
||||
}
|
||||
|
||||
val msg = announcerPlus.chat.parse(p, message, mainConfig.customPlaceholders)
|
||||
if (msg.startsWith("<center>")) {
|
||||
return announcerPlus.chat.getCenteredMessage(msg.replace("<center>", ""))
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
fun parse(player: CommandSender?, messages: List<String>): List<String> =
|
||||
messages.map { parse(player, it) }
|
||||
fun parse(player: CommandSender?, messages: List<String>): List<String> =
|
||||
messages.map { parse(player, it) }
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.config
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
@@ -24,189 +47,190 @@ import xyz.jpenilla.announcerplus.util.dispatchCommandAsConsole
|
||||
import xyz.jpenilla.announcerplus.util.runAsync
|
||||
import xyz.jpenilla.announcerplus.util.runSync
|
||||
import xyz.jpenilla.jmplib.Chat
|
||||
import xyz.jpenilla.jmplib.Environment
|
||||
|
||||
@ConfigSerializable
|
||||
class JoinQuitConfig : KoinComponent {
|
||||
|
||||
@Setting("visible-permission")
|
||||
@Comment("If set to something other than \"\", this setting's value will be the permission required to see these join/quit messages when they are broadcasted for a player")
|
||||
var permission = ""
|
||||
@Setting("visible-permission")
|
||||
@Comment("If set to something other than \"\", this setting's value will be the permission required to see these join/quit messages when they are broadcasted for a player")
|
||||
var permission = ""
|
||||
|
||||
@Setting("join-section")
|
||||
@Comment("Player Join related settings")
|
||||
var join = JoinSection()
|
||||
@Setting("join-section")
|
||||
@Comment("Player Join related settings")
|
||||
var join = JoinSection()
|
||||
|
||||
@Setting("quit-section")
|
||||
@Comment("Player Quit related settings")
|
||||
var quit = QuitSection()
|
||||
@Setting("quit-section")
|
||||
@Comment("Player Quit related settings")
|
||||
var quit = QuitSection()
|
||||
|
||||
@ConfigSerializable
|
||||
class JoinSection {
|
||||
@Setting("randomize-join-sounds")
|
||||
@Comment(Constants.CONFIG_COMMENT_SOUNDS_RANDOM)
|
||||
var randomSound = true
|
||||
@ConfigSerializable
|
||||
class JoinSection {
|
||||
@Setting("randomize-join-sounds")
|
||||
@Comment(Constants.CONFIG_COMMENT_SOUNDS_RANDOM)
|
||||
var randomSound = true
|
||||
|
||||
@Setting("randomize-join-broadcast-sounds")
|
||||
@Comment(Constants.CONFIG_COMMENT_SOUNDS_RANDOM)
|
||||
var randomBroadcastSound = true
|
||||
@Setting("randomize-join-broadcast-sounds")
|
||||
@Comment(Constants.CONFIG_COMMENT_SOUNDS_RANDOM)
|
||||
var randomBroadcastSound = true
|
||||
|
||||
@Setting("join-sounds")
|
||||
@Comment("These sound(s) will be played to the joining player.\n ${Constants.CONFIG_COMMENT_SOUNDS_LINE2}")
|
||||
var sounds =
|
||||
"minecraft:entity.strider.happy,minecraft:entity.villager.ambient,minecraft:block.note_block.cow_bell"
|
||||
@Setting("join-sounds")
|
||||
@Comment("These sound(s) will be played to the joining player.\n ${Constants.CONFIG_COMMENT_SOUNDS_LINE2}")
|
||||
var sounds =
|
||||
"minecraft:entity.strider.happy,minecraft:entity.villager.ambient,minecraft:block.note_block.cow_bell"
|
||||
|
||||
@Setting("join-broadcast-sounds")
|
||||
@Comment("These sound(s) will be played to the joining player.\n ${Constants.CONFIG_COMMENT_SOUNDS_LINE2}")
|
||||
var broadcastSounds = "minecraft:entity.enderman.teleport"
|
||||
@Setting("join-broadcast-sounds")
|
||||
@Comment("These sound(s) will be played to the joining player.\n ${Constants.CONFIG_COMMENT_SOUNDS_LINE2}")
|
||||
var broadcastSounds = "minecraft:entity.enderman.teleport"
|
||||
|
||||
@Setting("join-messages")
|
||||
@Comment("These messages will be sent to the joining Player. These messages are sometimes called a \"Message of the Day\" or a \"MotD\"")
|
||||
val messages = arrayListOf(
|
||||
"<hover:show_text:'<yellow>Username</yellow><gray>:</gray> {user}'>{nick}</hover> <yellow>joined the game",
|
||||
"<center><rainbow><italic>Welcome,</rainbow> {user}<yellow>!",
|
||||
"<center><gradient:black:white:black>------------------------------------</gradient>",
|
||||
"This server is using <blue>Announcer<italic>Plus<reset>!",
|
||||
"<gradient:green:white>Configure these messages by editing the config files!"
|
||||
)
|
||||
@Setting("join-messages")
|
||||
@Comment("These messages will be sent to the joining Player. These messages are sometimes called a \"Message of the Day\" or a \"MotD\"")
|
||||
val messages = arrayListOf(
|
||||
"<hover:show_text:'<yellow>Username</yellow><gray>:</gray> {user}'>{nick}</hover> <yellow>joined the game",
|
||||
"<center><rainbow><italic>Welcome,</rainbow> {user}<yellow>!",
|
||||
"<center><gradient:black:white:black>------------------------------------</gradient>",
|
||||
"This server is using <blue>Announcer<italic>Plus<reset>!",
|
||||
"<gradient:green:white>Configure these messages by editing the config files!"
|
||||
)
|
||||
|
||||
@Setting("join-broadcasts")
|
||||
@Comment("These messages will be sent to every Player online except the joining Player. Also known as join messages.")
|
||||
val broadcasts =
|
||||
arrayListOf("<hover:show_text:'<yellow>Username</yellow><gray>:</gray> {user}'>{nick}</hover> <yellow>joined the game")
|
||||
@Setting("join-broadcasts")
|
||||
@Comment("These messages will be sent to every Player online except the joining Player. Also known as join messages.")
|
||||
val broadcasts =
|
||||
arrayListOf("<hover:show_text:'<yellow>Username</yellow><gray>:</gray> {user}'>{nick}</hover> <yellow>joined the game")
|
||||
|
||||
@Setting("join-commands")
|
||||
@Comment("These commands will be run by the console on Player join.\n Example: \"minecraft:give %player_name% dirt\"")
|
||||
val commands = arrayListOf<String>()
|
||||
@Setting("join-commands")
|
||||
@Comment("These commands will be run by the console on Player join.\n Example: \"minecraft:give %player_name% dirt\"")
|
||||
val commands = arrayListOf<String>()
|
||||
|
||||
@Setting("as-player-join-commands")
|
||||
@Comment("These commands will be run as the Player on Player join.\n Example: \"ap about\"")
|
||||
val asPlayerCommands = arrayListOf<String>()
|
||||
@Setting("as-player-join-commands")
|
||||
@Comment("These commands will be run as the Player on Player join.\n Example: \"ap about\"")
|
||||
val asPlayerCommands = arrayListOf<String>()
|
||||
|
||||
@Setting("title-settings")
|
||||
@Comment("Settings relating to showing a title to the joining Player")
|
||||
var title = TitleSettings(
|
||||
1, 7, 1,
|
||||
"<bold><italic><gradient:green:blue:green:{animate:scroll:0.1}>Welcome</gradient><yellow>{animate:flash:!:!!:!!!:10}",
|
||||
"<{animate:pulse:red:blue:yellow:green:10}>{user}"
|
||||
)
|
||||
@Setting("title-settings")
|
||||
@Comment("Settings relating to showing a title to the joining Player")
|
||||
var title = TitleSettings(
|
||||
1, 7, 1,
|
||||
"<bold><italic><gradient:green:blue:green:{animate:scroll:0.1}>Welcome</gradient><yellow>{animate:flash:!:!!:!!!:10}",
|
||||
"<{animate:pulse:red:blue:yellow:green:10}>{user}"
|
||||
)
|
||||
|
||||
@Setting("action-bar-settings")
|
||||
@Comment("Settings relating to showing an Action Bar to the joining Player")
|
||||
var actionBar = ActionBarSettings(
|
||||
false, 8,
|
||||
"<gradient:green:blue:green:{animate:scroll:0.1}>|||||||||||||||||||||||||||||||||||||||</gradient>"
|
||||
)
|
||||
@Setting("action-bar-settings")
|
||||
@Comment("Settings relating to showing an Action Bar to the joining Player")
|
||||
var actionBar = ActionBarSettings(
|
||||
false, 8,
|
||||
"<gradient:green:blue:green:{animate:scroll:0.1}>|||||||||||||||||||||||||||||||||||||||</gradient>"
|
||||
)
|
||||
|
||||
@Setting("boss-bar-settings")
|
||||
@Comment("Settings relating to showing a Boss Bar to the joining Player")
|
||||
var bossBar = BossBarSettings()
|
||||
@Setting("boss-bar-settings")
|
||||
@Comment("Settings relating to showing a Boss Bar to the joining Player")
|
||||
var bossBar = BossBarSettings()
|
||||
|
||||
@Setting("toast-settings")
|
||||
@Comment("Configure the Toast that will be showed to the joining player")
|
||||
var toast = ToastSettings(
|
||||
Material.DIAMOND, ToastSettings.FrameType.CHALLENGE,
|
||||
"<gradient:green:blue><bold><italic>AnnouncerPlus", "<rainbow>Welcome to the server!"
|
||||
)
|
||||
@Setting("toast-settings")
|
||||
@Comment("Configure the Toast that will be showed to the joining player")
|
||||
var toast = ToastSettings(
|
||||
Material.DIAMOND, ToastSettings.FrameType.CHALLENGE,
|
||||
"<gradient:green:blue><bold><italic>AnnouncerPlus", "<rainbow>Welcome to the server!"
|
||||
)
|
||||
|
||||
fun messageElements(): Collection<MessageElement> = ImmutableSet.of(
|
||||
actionBar,
|
||||
bossBar,
|
||||
title,
|
||||
toast
|
||||
)
|
||||
}
|
||||
fun messageElements(): Collection<MessageElement> = ImmutableSet.of(
|
||||
actionBar,
|
||||
bossBar,
|
||||
title,
|
||||
toast
|
||||
)
|
||||
}
|
||||
|
||||
@ConfigSerializable
|
||||
class QuitSection {
|
||||
@Setting("randomize-quit-sounds")
|
||||
@Comment(Constants.CONFIG_COMMENT_SOUNDS_RANDOM)
|
||||
var randomSound = true
|
||||
@ConfigSerializable
|
||||
class QuitSection {
|
||||
@Setting("randomize-quit-sounds")
|
||||
@Comment(Constants.CONFIG_COMMENT_SOUNDS_RANDOM)
|
||||
var randomSound = true
|
||||
|
||||
@Setting("quit-sounds")
|
||||
@Comment("These sound(s) will be played to online players on player quit\n ${Constants.CONFIG_COMMENT_SOUNDS_LINE2}")
|
||||
var sounds = "minecraft:entity.enderman.teleport"
|
||||
@Setting("quit-sounds")
|
||||
@Comment("These sound(s) will be played to online players on player quit\n ${Constants.CONFIG_COMMENT_SOUNDS_LINE2}")
|
||||
var sounds = "minecraft:entity.enderman.teleport"
|
||||
|
||||
@Setting("quit-broadcasts")
|
||||
@Comment("These messages will be sent to online players on player quit. Also known as quit messages")
|
||||
val broadcasts =
|
||||
arrayListOf("<hover:show_text:'<yellow>Username</yellow><gray>:</gray> {user}'>{nick}</hover> <yellow>left the game")
|
||||
@Setting("quit-broadcasts")
|
||||
@Comment("These messages will be sent to online players on player quit. Also known as quit messages")
|
||||
val broadcasts =
|
||||
arrayListOf("<hover:show_text:'<yellow>Username</yellow><gray>:</gray> {user}'>{nick}</hover> <yellow>left the game")
|
||||
|
||||
@Setting("quit-commands")
|
||||
@Comment("These commands will be run by the console on Player quit.\n Example: \"broadcast %player_name% left\"")
|
||||
val commands = arrayListOf<String>()
|
||||
}
|
||||
@Setting("quit-commands")
|
||||
@Comment("These commands will be run by the console on Player quit.\n Example: \"broadcast %player_name% left\"")
|
||||
val commands = arrayListOf<String>()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val MAPPER = ObjectMapper.factoryBuilder().addNodeResolver(NodeResolver.onlyWithSetting()).build()
|
||||
.get(JoinQuitConfig::class.java)
|
||||
companion object {
|
||||
private val MAPPER = ObjectMapper.factoryBuilder().addNodeResolver(NodeResolver.onlyWithSetting()).build()
|
||||
.get(JoinQuitConfig::class.java)
|
||||
|
||||
fun loadFrom(node: CommentedConfigurationNode, name: String?): JoinQuitConfig =
|
||||
MAPPER.load(node).populate(name)
|
||||
}
|
||||
fun loadFrom(node: CommentedConfigurationNode, name: String?): JoinQuitConfig =
|
||||
MAPPER.load(node).populate(name)
|
||||
}
|
||||
|
||||
fun saveTo(node: CommentedConfigurationNode) =
|
||||
MAPPER.save(this, node)
|
||||
fun saveTo(node: CommentedConfigurationNode) =
|
||||
MAPPER.save(this, node)
|
||||
|
||||
fun populate(name: String?): JoinQuitConfig =
|
||||
this.apply { this.name = name }
|
||||
fun populate(name: String?): JoinQuitConfig =
|
||||
this.apply { this.name = name }
|
||||
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val chat: Chat by inject()
|
||||
private var name: String? = null
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val chat: Chat by inject()
|
||||
private var name: String? = null
|
||||
|
||||
fun onJoin(player: Player) {
|
||||
/* name is null for first-join config */
|
||||
if (name != null && !player.hasPermission("announcerplus.join.$name")) return
|
||||
chat.send(player, announcerPlus.configManager.parse(player, join.messages))
|
||||
announcerPlus.runSync(3L) {
|
||||
if (!isVanished(player)) {
|
||||
val onlinePlayers = ImmutableList.copyOf(Bukkit.getOnlinePlayers())
|
||||
announcerPlus.runAsync {
|
||||
onlinePlayers.forEach { onlinePlayer ->
|
||||
if (onlinePlayer.name != player.name) {
|
||||
if (announcerPlus.perms!!.playerHas(onlinePlayer, permission) || permission.isEmpty()) {
|
||||
chat.send(onlinePlayer, announcerPlus.configManager.parse(player, join.broadcasts))
|
||||
if (join.broadcastSounds != "") {
|
||||
chat.playSounds(onlinePlayer, join.randomBroadcastSound, join.broadcastSounds)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
join.commands.forEach { dispatchCommandAsConsole(announcerPlus.configManager.parse(player, it)) }
|
||||
join.asPlayerCommands.forEach { player.performCommand(announcerPlus.configManager.parse(player, it)) }
|
||||
}
|
||||
}
|
||||
announcerPlus.runAsync(if (announcerPlus.majorMinecraftVersion <= 12) 5L else 0L) {
|
||||
join.messageElements().forEach { it.displayIfEnabled(player) }
|
||||
if (join.sounds != "") {
|
||||
chat.playSounds(player, join.randomSound, join.sounds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onQuit(player: Player) {
|
||||
if (name == null || !player.hasPermission("announcerplus.quit.$name") || isVanished(player)) return
|
||||
ImmutableList.copyOf(Bukkit.getOnlinePlayers()).forEach { onlinePlayer ->
|
||||
fun onJoin(player: Player) {
|
||||
/* name is null for first-join config */
|
||||
if (name != null && !player.hasPermission("announcerplus.join.$name")) return
|
||||
chat.send(player, announcerPlus.configManager.parse(player, join.messages))
|
||||
announcerPlus.runSync(3L) {
|
||||
if (!isVanished(player)) {
|
||||
val onlinePlayers = ImmutableList.copyOf(Bukkit.getOnlinePlayers())
|
||||
announcerPlus.runAsync {
|
||||
onlinePlayers.forEach { onlinePlayer ->
|
||||
if (onlinePlayer.name != player.name) {
|
||||
if (announcerPlus.perms!!.playerHas(onlinePlayer, permission) || permission.isEmpty()) {
|
||||
chat.send(onlinePlayer, announcerPlus.configManager.parse(player, quit.broadcasts))
|
||||
if (quit.sounds.isNotEmpty()) {
|
||||
chat.playSounds(onlinePlayer, quit.randomSound, quit.sounds)
|
||||
}
|
||||
if (announcerPlus.perms!!.playerHas(onlinePlayer, permission) || permission.isEmpty()) {
|
||||
chat.send(onlinePlayer, announcerPlus.configManager.parse(player, join.broadcasts))
|
||||
if (join.broadcastSounds != "") {
|
||||
chat.playSounds(onlinePlayer, join.randomBroadcastSound, join.broadcastSounds)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
quit.commands.forEach { dispatchCommandAsConsole(announcerPlus.configManager.parse(player, it)) }
|
||||
join.commands.forEach { dispatchCommandAsConsole(announcerPlus.configManager.parse(player, it)) }
|
||||
join.asPlayerCommands.forEach { player.performCommand(announcerPlus.configManager.parse(player, it)) }
|
||||
}
|
||||
}
|
||||
announcerPlus.runAsync(if (Environment.majorMinecraftVersion() <= 12) 5L else 0L) {
|
||||
join.messageElements().forEach { it.displayIfEnabled(player) }
|
||||
if (join.sounds != "") {
|
||||
chat.playSounds(player, join.randomSound, join.sounds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isVanished(player: Player): Boolean {
|
||||
for (meta in player.getMetadata("vanished")) {
|
||||
if (meta.asBoolean()) return true
|
||||
fun onQuit(player: Player) {
|
||||
if (name == null || !player.hasPermission("announcerplus.quit.$name") || isVanished(player)) return
|
||||
ImmutableList.copyOf(Bukkit.getOnlinePlayers()).forEach { onlinePlayer ->
|
||||
if (onlinePlayer.name != player.name) {
|
||||
if (announcerPlus.perms!!.playerHas(onlinePlayer, permission) || permission.isEmpty()) {
|
||||
chat.send(onlinePlayer, announcerPlus.configManager.parse(player, quit.broadcasts))
|
||||
if (quit.sounds.isNotEmpty()) {
|
||||
chat.playSounds(onlinePlayer, quit.randomSound, quit.sounds)
|
||||
}
|
||||
}
|
||||
if (announcerPlus.essentials != null) {
|
||||
return announcerPlus.essentials!!.isVanished(player)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
quit.commands.forEach { dispatchCommandAsConsole(announcerPlus.configManager.parse(player, it)) }
|
||||
}
|
||||
|
||||
private fun isVanished(player: Player): Boolean {
|
||||
for (meta in player.getMetadata("vanished")) {
|
||||
if (meta.asBoolean()) return true
|
||||
}
|
||||
if (announcerPlus.essentials != null) {
|
||||
return announcerPlus.essentials!!.isVanished(player)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.config
|
||||
|
||||
import org.spongepowered.configurate.CommentedConfigurationNode
|
||||
@@ -8,73 +31,80 @@ import org.spongepowered.configurate.objectmapping.meta.Comment
|
||||
@ConfigSerializable
|
||||
class MainConfig {
|
||||
|
||||
@Comment("Here you can define custom placeholders for use in plugin messages\n These placeholders can be used like \"{placeholder}\", i.e. \"{nick}\" or \"{r}rainbow text{rc}\"")
|
||||
val customPlaceholders = hashMapOf(
|
||||
"nick" to "%essentials_nickname%",
|
||||
"user" to "%player_name%",
|
||||
"prefix1" to "<bold><blue>[<green>!</green>]</blue></bold>",
|
||||
"r" to "<rainbow>",
|
||||
"rc" to "</rainbow>"
|
||||
@Comment("Here you can define custom placeholders for use in plugin messages\n These placeholders can be used like \"{placeholder}\", i.e. \"{nick}\" or \"{r}rainbow text{rc}\"")
|
||||
val customPlaceholders = hashMapOf(
|
||||
"nick" to "%essentials_nickname%",
|
||||
"user" to "%player_name%",
|
||||
"prefix1" to "<bold><blue>[<green>!</green>]</blue></bold>",
|
||||
"r" to "<rainbow>",
|
||||
"rc" to "</rainbow>"
|
||||
)
|
||||
|
||||
@Comment("This setting enables or disables all timed broadcasts")
|
||||
var enableBroadcasts = true
|
||||
|
||||
@Comment("This setting enables or disables all Join event features")
|
||||
var joinFeatures = true
|
||||
|
||||
@Comment("This setting enables or disables all Quit event features")
|
||||
var quitFeatures = true
|
||||
|
||||
@Comment(
|
||||
"This setting enables or disables the first-join.conf\n" +
|
||||
"If enabled, on a player's first join the first-join.conf will be used instead of any other join configs."
|
||||
)
|
||||
var firstJoinConfigEnabled = false
|
||||
|
||||
@Comment(
|
||||
"Here you can define randomized join configs.\n" +
|
||||
" To assign randomized join configs, give the announcerplus.randomjoin.demo permission, replacing demo with your randomized config\n" +
|
||||
" NOTE: The randomized config named 'demo' will be ignored by the plugin. You must choose a new name to use this feature.\n" +
|
||||
" WARNING: If you are OP make sure to negate the appropriate permissions so that you do not get duplicate join/quit messages"
|
||||
)
|
||||
val randomJoinConfigs = hashMapOf(
|
||||
"demo" to arrayListOf(
|
||||
JoinQuitPair("default", 0.1),
|
||||
JoinQuitPair("default", 0.2)
|
||||
)
|
||||
)
|
||||
|
||||
@Comment("This setting enables or disables all timed broadcasts")
|
||||
var enableBroadcasts = true
|
||||
|
||||
@Comment("This setting enables or disables all Join event features")
|
||||
var joinFeatures = true
|
||||
|
||||
@Comment("This setting enables or disables all Quit event features")
|
||||
var quitFeatures = true
|
||||
|
||||
@Comment("This setting enables or disables the first-join.conf\n" +
|
||||
"If enabled, on a player's first join the first-join.conf will be used instead of any other join configs.")
|
||||
var firstJoinConfigEnabled = false
|
||||
|
||||
@Comment("Here you can define randomized join configs.\n" +
|
||||
" To assign randomized join configs, give the announcerplus.randomjoin.demo permission, replacing demo with your randomized config\n" +
|
||||
" WARNING: If you are OP make sure to negate the appropriate permissions so that you do not get duplicate join/quit messages")
|
||||
val randomJoinConfigs = hashMapOf(
|
||||
"demo" to arrayListOf(
|
||||
JoinQuitPair("default", 0.1),
|
||||
JoinQuitPair("default", 0.2)
|
||||
)
|
||||
@Comment(
|
||||
"Here you can define randomized quit configs.\n" +
|
||||
" To assign randomized quit configs, give the announcerplus.randomquit.demo permission, replacing demo with your randomized config\n" +
|
||||
" NOTE: The randomized config named 'demo' will be ignored by the plugin. You must choose a new name to use this feature.\n" +
|
||||
" WARNING: If you are OP make sure to negate the appropriate permissions so that you do not get duplicate join/quit messages"
|
||||
)
|
||||
val randomQuitConfigs = hashMapOf(
|
||||
"demo" to arrayListOf(
|
||||
JoinQuitPair("default", 0.2),
|
||||
JoinQuitPair("default", 0.1)
|
||||
)
|
||||
)
|
||||
|
||||
@Comment("Here you can define randomized join configs.\n" +
|
||||
" To assign randomized quit configs, give the announcerplus.randomquit.demo permission, replacing demo with your randomized config\n" +
|
||||
" NOTE: The randomized config named 'demo' will be ignored by the plugin. You must choose a new name to use this feature.\n" +
|
||||
" WARNING: If you are OP make sure to negate the appropriate permissions so that you do not get duplicate join/quit messages")
|
||||
val randomQuitConfigs = hashMapOf(
|
||||
"demo" to arrayListOf(
|
||||
JoinQuitPair("default", 0.2),
|
||||
JoinQuitPair("default", 0.1)
|
||||
)
|
||||
)
|
||||
|
||||
@ConfigSerializable
|
||||
class JoinQuitPair {
|
||||
constructor()
|
||||
constructor(configName: String, weight: Double) {
|
||||
this.configName = configName
|
||||
this.weight = weight
|
||||
}
|
||||
|
||||
@Comment("The name of the config (the text before .conf in the file name)")
|
||||
var configName = "default"
|
||||
|
||||
@Comment("The weight of this config for random selection, 0.0-1.0")
|
||||
var weight = 0.1
|
||||
@ConfigSerializable
|
||||
class JoinQuitPair {
|
||||
constructor()
|
||||
constructor(configName: String, weight: Double) {
|
||||
this.configName = configName
|
||||
this.weight = weight
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val MAPPER = ObjectMapper.factory().get(MainConfig::class.java)
|
||||
@Comment("The name of the config (the text before .conf in the file name)")
|
||||
var configName = "default"
|
||||
|
||||
fun loadFrom(node: CommentedConfigurationNode): MainConfig {
|
||||
return MAPPER.load(node)
|
||||
}
|
||||
}
|
||||
@Comment("The weight of this config for random selection, 0.0-1.0")
|
||||
var weight = 0.1
|
||||
}
|
||||
|
||||
fun saveTo(node: CommentedConfigurationNode) {
|
||||
MAPPER.save(this, node)
|
||||
companion object {
|
||||
private val MAPPER = ObjectMapper.factory().get(MainConfig::class.java)
|
||||
|
||||
fun loadFrom(node: CommentedConfigurationNode): MainConfig {
|
||||
return MAPPER.load(node)
|
||||
}
|
||||
}
|
||||
|
||||
fun saveTo(node: CommentedConfigurationNode) {
|
||||
MAPPER.save(this, node)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.config.message
|
||||
|
||||
import org.bukkit.entity.Player
|
||||
@@ -8,27 +31,27 @@ import xyz.jpenilla.announcerplus.task.ActionBarUpdateTask
|
||||
@ConfigSerializable
|
||||
class ActionBarSettings : MessageElement {
|
||||
|
||||
@Comment("Seconds of duration for the Action Bar to stay on screen")
|
||||
var durationSeconds = 6
|
||||
@Comment("Seconds of duration for the Action Bar to stay on screen")
|
||||
var durationSeconds = 6
|
||||
|
||||
@Comment("Should the fade out animation of the Action Bar be enabled?")
|
||||
var enableFadeOut = false
|
||||
@Comment("Should the fade out animation of the Action Bar be enabled?")
|
||||
var enableFadeOut = false
|
||||
|
||||
@Comment("The text for the Action Bar. Set to \"\" (empty string) to disable. Accepts animations")
|
||||
var text = ""
|
||||
@Comment("The text for the Action Bar. Set to \"\" (empty string) to disable. Accepts animations")
|
||||
var text = ""
|
||||
|
||||
constructor()
|
||||
constructor(fadeEnabled: Boolean, durationSeconds: Int, text: String) {
|
||||
this.enableFadeOut = fadeEnabled
|
||||
this.durationSeconds = durationSeconds
|
||||
this.text = text
|
||||
}
|
||||
constructor()
|
||||
constructor(fadeEnabled: Boolean, durationSeconds: Int, text: String) {
|
||||
this.enableFadeOut = fadeEnabled
|
||||
this.durationSeconds = durationSeconds
|
||||
this.text = text
|
||||
}
|
||||
|
||||
override fun isEnabled(): Boolean {
|
||||
return text != ""
|
||||
}
|
||||
override fun isEnabled(): Boolean {
|
||||
return text != ""
|
||||
}
|
||||
|
||||
override fun display(player: Player) {
|
||||
ActionBarUpdateTask(player, durationSeconds * 20L, enableFadeOut, text).start()
|
||||
}
|
||||
override fun display(player: Player) {
|
||||
ActionBarUpdateTask(player, durationSeconds * 20L, enableFadeOut, text).start()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.config.message
|
||||
|
||||
import net.kyori.adventure.bossbar.BossBar
|
||||
@@ -9,34 +32,36 @@ import xyz.jpenilla.announcerplus.task.BossBarUpdateTask
|
||||
@ConfigSerializable
|
||||
class BossBarSettings : MessageElement {
|
||||
|
||||
@Comment("Seconds of duration for the Boss Bar to stay on screen")
|
||||
var durationSeconds = 12
|
||||
@Comment("Seconds of duration for the Boss Bar to stay on screen")
|
||||
var durationSeconds = 12
|
||||
|
||||
@Comment("The text for the Boss Bar. Set to \"\" (empty string) to disable. Accepts animations")
|
||||
var text = ""
|
||||
@Comment("The text for the Boss Bar. Set to \"\" (empty string) to disable. Accepts animations")
|
||||
var text = ""
|
||||
|
||||
@Comment("The color for the Boss Bar. For a list of colors, visit: https://papermc.io/javadocs/paper/1.16/org/bukkit/boss/BarColor.html\n" +
|
||||
" This field technically accepts animations, although only the \"Flashing Text\" animation used with valid Boss Bar colors will actually work.")
|
||||
var color = "YELLOW"
|
||||
@Comment(
|
||||
"The color for the Boss Bar. For a list of colors, visit: https://papermc.io/javadocs/paper/1.16/org/bukkit/boss/BarColor.html\n" +
|
||||
" This field technically accepts animations, although only the \"Flashing Text\" animation used with valid Boss Bar colors will actually work."
|
||||
)
|
||||
var color = "YELLOW"
|
||||
|
||||
@Comment("The overlay for the Boss Bar. Possible values: PROGRESS, NOTCHED_6, NOTCHED_10, NOTCHED_12, NOTCHED_20")
|
||||
var overlay = BossBar.Overlay.PROGRESS
|
||||
@Comment("The overlay for the Boss Bar. Possible values: PROGRESS, NOTCHED_6, NOTCHED_10, NOTCHED_12, NOTCHED_20")
|
||||
var overlay = BossBar.Overlay.PROGRESS
|
||||
|
||||
@Comment("The fill mode for the Boss Bar. Possible modes: FILL, DRAIN, FULL, EMPTY")
|
||||
var fillMode = BossBarUpdateTask.FillMode.DRAIN
|
||||
@Comment("The fill mode for the Boss Bar. Possible modes: FILL, DRAIN, FULL, EMPTY")
|
||||
var fillMode = BossBarUpdateTask.FillMode.DRAIN
|
||||
|
||||
constructor()
|
||||
constructor(durationSeconds: Int, color: String, text: String) {
|
||||
this.durationSeconds = durationSeconds
|
||||
this.color = color
|
||||
this.text = text
|
||||
}
|
||||
constructor()
|
||||
constructor(durationSeconds: Int, color: String, text: String) {
|
||||
this.durationSeconds = durationSeconds
|
||||
this.color = color
|
||||
this.text = text
|
||||
}
|
||||
|
||||
override fun isEnabled(): Boolean {
|
||||
return text != ""
|
||||
}
|
||||
override fun isEnabled(): Boolean {
|
||||
return text != ""
|
||||
}
|
||||
|
||||
override fun display(player: Player) {
|
||||
BossBarUpdateTask(player, durationSeconds, overlay, fillMode, color, text).start()
|
||||
}
|
||||
override fun display(player: Player) {
|
||||
BossBarUpdateTask(player, durationSeconds, overlay, fillMode, color, text).start()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.config.message
|
||||
|
||||
import com.google.common.collect.ImmutableSet
|
||||
@@ -8,56 +31,56 @@ import xyz.jpenilla.announcerplus.util.Constants
|
||||
@ConfigSerializable
|
||||
class Message {
|
||||
|
||||
@Comment("The lines of text for this message. Can be empty for no chat messages.")
|
||||
val messageText = arrayListOf<String>()
|
||||
@Comment("The lines of text for this message. Can be empty for no chat messages.")
|
||||
val messageText = arrayListOf<String>()
|
||||
|
||||
@Comment("Configure the Action Bar for this message")
|
||||
var actionBar = ActionBarSettings()
|
||||
@Comment("Configure the Action Bar for this message")
|
||||
var actionBar = ActionBarSettings()
|
||||
|
||||
@Comment("Configure the Boss Bar for this message")
|
||||
var bossBar = BossBarSettings()
|
||||
@Comment("Configure the Boss Bar for this message")
|
||||
var bossBar = BossBarSettings()
|
||||
|
||||
@Comment("Configure the Title for this message")
|
||||
var title = TitleSettings()
|
||||
@Comment("Configure the Title for this message")
|
||||
var title = TitleSettings()
|
||||
|
||||
@Comment("Configure the Toast/Achievement/Advancement for this message")
|
||||
var toast = ToastSettings()
|
||||
@Comment("Configure the Toast/Achievement/Advancement for this message")
|
||||
var toast = ToastSettings()
|
||||
|
||||
@Comment("The sounds to play when this message is sent\n ${Constants.CONFIG_COMMENT_SOUNDS_LINE2}")
|
||||
var sounds = ""
|
||||
@Comment("The sounds to play when this message is sent\n ${Constants.CONFIG_COMMENT_SOUNDS_LINE2}")
|
||||
var sounds = ""
|
||||
|
||||
@Comment(Constants.CONFIG_COMMENT_SOUNDS_RANDOM)
|
||||
var soundsRandomized = true
|
||||
@Comment(Constants.CONFIG_COMMENT_SOUNDS_RANDOM)
|
||||
var soundsRandomized = true
|
||||
|
||||
@Comment("These commands will run as console on broadcast. Example: \"broadcast This is a test\"")
|
||||
val commands = arrayListOf<String>()
|
||||
@Comment("These commands will run as console on broadcast. Example: \"broadcast This is a test\"")
|
||||
val commands = arrayListOf<String>()
|
||||
|
||||
@Comment("These commands will run as console once per player on broadcast. Example: \"minecraft:give %player_name% dirt\"")
|
||||
val perPlayerCommands = arrayListOf<String>()
|
||||
@Comment("These commands will run as console once per player on broadcast. Example: \"minecraft:give %player_name% dirt\"")
|
||||
val perPlayerCommands = arrayListOf<String>()
|
||||
|
||||
@Comment("These commands will run once per player, as the player on broadcast. Example: \"ap about\"")
|
||||
val asPlayerCommands = arrayListOf<String>()
|
||||
@Comment("These commands will run once per player, as the player on broadcast. Example: \"ap about\"")
|
||||
val asPlayerCommands = arrayListOf<String>()
|
||||
|
||||
constructor()
|
||||
constructor(text: List<String>) {
|
||||
this.messageText.addAll(text)
|
||||
}
|
||||
constructor()
|
||||
constructor(text: List<String>) {
|
||||
this.messageText.addAll(text)
|
||||
}
|
||||
|
||||
fun messageElements(): Collection<MessageElement> = ImmutableSet.of(
|
||||
actionBar,
|
||||
bossBar,
|
||||
title,
|
||||
toast
|
||||
)
|
||||
fun messageElements(): Collection<MessageElement> = ImmutableSet.of(
|
||||
actionBar,
|
||||
bossBar,
|
||||
title,
|
||||
toast
|
||||
)
|
||||
|
||||
fun sounds(sounds: String): Message = apply { this.sounds = sounds }
|
||||
fun sounds(sounds: String): Message = apply { this.sounds = sounds }
|
||||
|
||||
fun actionBar(actionBar: ActionBarSettings): Message = apply { this.actionBar = actionBar }
|
||||
fun actionBar(actionBar: ActionBarSettings): Message = apply { this.actionBar = actionBar }
|
||||
|
||||
fun bossBar(bossBar: BossBarSettings): Message = apply { this.bossBar = bossBar }
|
||||
fun bossBar(bossBar: BossBarSettings): Message = apply { this.bossBar = bossBar }
|
||||
|
||||
fun title(title: TitleSettings): Message = apply { this.title = title }
|
||||
fun title(title: TitleSettings): Message = apply { this.title = title }
|
||||
|
||||
fun toast(toast: ToastSettings): Message = apply { this.toast = toast }
|
||||
fun toast(toast: ToastSettings): Message = apply { this.toast = toast }
|
||||
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.config.message
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
@@ -23,134 +46,164 @@ import xyz.jpenilla.jmplib.Chat
|
||||
@ConfigSerializable
|
||||
class MessageConfig : KoinComponent {
|
||||
|
||||
@Setting
|
||||
@Comment("The list of messages for a config")
|
||||
val messages = arrayListOf(
|
||||
Message(arrayListOf("<center><rainbow>Test AnnouncerPlus broadcast!")),
|
||||
Message().bossBar(BossBarSettings(25, "{animate:flash:YELLOW:PURPLE:40}",
|
||||
"<green>-| <white>{animate:scrolltext:Hello this is an example Boss Bar announcement:20:3}</white> |-")),
|
||||
Message(arrayListOf(
|
||||
"{prefix1} 1. <gradient:blue:green:blue>Multi-line test AnnouncerPlus broadcast",
|
||||
"{prefix1} 2. <gradient:red:gold:red>Line number two of three",
|
||||
"{prefix1} 3. <bold><rainbow>this is the last line (line 3)"))
|
||||
.toast(ToastSettings(Material.DIAMOND, ToastSettings.FrameType.CHALLENGE,
|
||||
"<gradient:green:blue><bold><italic>AnnouncerPlus", "<rainbow>This is a Toast message!")),
|
||||
Message(arrayListOf("{prefix1} Test <gradient:blue:aqua>AnnouncerPlus</gradient> broadcast with sound<green>!"))
|
||||
.sounds("minecraft:entity.strider.happy,minecraft:entity.villager.ambient,minecraft:block.note_block.cow_bell"),
|
||||
Message(arrayListOf("{prefix1} Use <click:run_command:/ap about><hover:show_text:'<rainbow>Click to run!'><rainbow>/ap about</rainbow></hover></click> to check the plugin version"))
|
||||
.actionBar(ActionBarSettings(true, 15, "<{animate:randomcolor:pulse:25}>-| <white>{animate:scrolltext:Hello there this is some very long text being displayed in a scrolling window!! =):20:3}</white> |-")),
|
||||
Message(arrayListOf("<bold><italic>Hello, </bold></italic> {nick} {prefix1} {r}!!!!!!!!!{rc}"))
|
||||
.title(TitleSettings(1, 13, 2, "<gradient:green:blue:green:{animate:scroll:0.1}>||||||||||||||||||||||||||||||||||||||||||||", "<{animate:pulse:red:blue:10}>{animate:type:This is a test... typing...:6}")),
|
||||
Message(arrayListOf("<center><gradient:red:blue>Centered text Example"))
|
||||
.bossBar(BossBarSettings(25, "PINK",
|
||||
"<bold>This is an example <italic><gradient:blue:light_purple>Boss Bar"))
|
||||
@Setting
|
||||
@Comment("The list of messages for a config")
|
||||
val messages = arrayListOf(
|
||||
Message(arrayListOf("<center><rainbow>Test AnnouncerPlus broadcast!")),
|
||||
Message().bossBar(
|
||||
BossBarSettings(
|
||||
25, "{animate:flash:YELLOW:PURPLE:40}",
|
||||
"<green>-| <white>{animate:scrolltext:Hello this is an example Boss Bar announcement:20:3}</white> |-"
|
||||
)
|
||||
),
|
||||
Message(
|
||||
arrayListOf(
|
||||
"{prefix1} 1. <gradient:blue:green:blue>Multi-line test AnnouncerPlus broadcast",
|
||||
"{prefix1} 2. <gradient:red:gold:red>Line number two of three",
|
||||
"{prefix1} 3. <bold><rainbow>this is the last line (line 3)"
|
||||
)
|
||||
)
|
||||
.toast(
|
||||
ToastSettings(
|
||||
Material.DIAMOND, ToastSettings.FrameType.CHALLENGE,
|
||||
"<gradient:green:blue><bold><italic>AnnouncerPlus", "<rainbow>This is a Toast message!"
|
||||
)
|
||||
),
|
||||
Message(arrayListOf("{prefix1} Test <gradient:blue:aqua>AnnouncerPlus</gradient> broadcast with sound<green>!"))
|
||||
.sounds("minecraft:entity.strider.happy,minecraft:entity.villager.ambient,minecraft:block.note_block.cow_bell"),
|
||||
Message(arrayListOf("{prefix1} Use <click:run_command:/ap about><hover:show_text:'<rainbow>Click to run!'><rainbow>/ap about</rainbow></hover></click> to check the plugin version"))
|
||||
.actionBar(
|
||||
ActionBarSettings(
|
||||
true,
|
||||
15,
|
||||
"<{animate:randomcolor:pulse:25}>-| <white>{animate:scrolltext:Hello there this is some very long text being displayed in a scrolling window!! =):20:3}</white> |-"
|
||||
)
|
||||
),
|
||||
Message(arrayListOf("<bold><italic>Hello, </bold></italic> {nick} {prefix1} {r}!!!!!!!!!{rc}"))
|
||||
.title(
|
||||
TitleSettings(
|
||||
1,
|
||||
13,
|
||||
2,
|
||||
"<gradient:green:blue:green:{animate:scroll:0.1}>||||||||||||||||||||||||||||||||||||||||||||",
|
||||
"<{animate:pulse:red:blue:10}>{animate:type:This is a test... typing...:6}"
|
||||
)
|
||||
),
|
||||
Message(arrayListOf("<center><gradient:red:blue>Centered text Example"))
|
||||
.bossBar(
|
||||
BossBarSettings(
|
||||
25, "PINK",
|
||||
"<bold>This is an example <italic><gradient:blue:light_purple>Boss Bar"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@Setting("every-broadcast-commands")
|
||||
@Comment("These commands will run as console once each interval\n Example: \"broadcast This is a test\"")
|
||||
val commands = arrayListOf<String>()
|
||||
@Setting("every-broadcast-commands")
|
||||
@Comment("These commands will run as console once each interval\n Example: \"broadcast This is a test\"")
|
||||
val commands = arrayListOf<String>()
|
||||
|
||||
@Setting("every-broadcast-per-player-commands")
|
||||
@Comment("These commands will run as console once per player each interval\n Example: \"minecraft:give %player_name% dirt\"")
|
||||
val perPlayerCommands = arrayListOf<String>()
|
||||
@Setting("every-broadcast-per-player-commands")
|
||||
@Comment("These commands will run as console once per player each interval\n Example: \"minecraft:give %player_name% dirt\"")
|
||||
val perPlayerCommands = arrayListOf<String>()
|
||||
|
||||
@Setting("every-broadcast-as-player-commands")
|
||||
@Comment("These commands will run once per player each interval, as the player\n Example: \"ap about\"")
|
||||
val asPlayerCommands = arrayListOf<String>()
|
||||
@Setting("every-broadcast-as-player-commands")
|
||||
@Comment("These commands will run once per player each interval, as the player\n Example: \"ap about\"")
|
||||
val asPlayerCommands = arrayListOf<String>()
|
||||
|
||||
@Setting("interval-time-unit")
|
||||
@Comment("The unit of time used for the interval\n Can be SECONDS, MINUTES, or HOURS")
|
||||
var timeUnit = TimeUnit.MINUTES
|
||||
@Setting("interval-time-unit")
|
||||
@Comment("The unit of time used for the interval\n Can be SECONDS, MINUTES, or HOURS")
|
||||
var timeUnit = TimeUnit.MINUTES
|
||||
|
||||
@Setting("interval-time-amount")
|
||||
@Comment("The amount of time used for the interval")
|
||||
var interval = 3
|
||||
@Setting("interval-time-amount")
|
||||
@Comment("The amount of time used for the interval")
|
||||
var interval = 3
|
||||
|
||||
@Setting("random-message-order")
|
||||
@Comment("Should the messages be sent in order of the config or in random order")
|
||||
var randomOrder = false
|
||||
@Setting("random-message-order")
|
||||
@Comment("Should the messages be sent in order of the config or in random order")
|
||||
var randomOrder = false
|
||||
|
||||
companion object {
|
||||
private val MAPPER = ObjectMapper.factoryBuilder().addNodeResolver(NodeResolver.onlyWithSetting()).build()
|
||||
.get(MessageConfig::class.java)
|
||||
companion object {
|
||||
private val MAPPER = ObjectMapper.factoryBuilder().addNodeResolver(NodeResolver.onlyWithSetting()).build()
|
||||
.get(MessageConfig::class.java)
|
||||
|
||||
fun loadFrom(node: CommentedConfigurationNode, name: String): MessageConfig =
|
||||
MAPPER.load(node).populate(name)
|
||||
fun loadFrom(node: CommentedConfigurationNode, name: String): MessageConfig =
|
||||
MAPPER.load(node).populate(name)
|
||||
}
|
||||
|
||||
fun saveTo(node: CommentedConfigurationNode) {
|
||||
MAPPER.save(this, node)
|
||||
}
|
||||
|
||||
fun populate(name: String): MessageConfig =
|
||||
this.apply { this.name = name }
|
||||
|
||||
private var broadcastTask: BukkitTask? = null
|
||||
lateinit var name: String
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val chat: Chat by inject()
|
||||
private val broadcastQueue = ArrayDeque<Message>()
|
||||
|
||||
fun broadcast() {
|
||||
stop()
|
||||
broadcastQueue.clear()
|
||||
broadcastQueue.addAll(shuffledMessages())
|
||||
broadcastTask = announcerPlus.asyncTimer(0L, timeUnit.getTicks(interval)) {
|
||||
if (broadcastQueue.isNotEmpty()) {
|
||||
broadcast(broadcastQueue.removeFirst())
|
||||
} else {
|
||||
broadcast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun saveTo(node: CommentedConfigurationNode) =
|
||||
MAPPER.save(this, node)
|
||||
|
||||
fun populate(name: String): MessageConfig =
|
||||
this.apply { this.name = name }
|
||||
|
||||
private var broadcastTask: BukkitTask? = null
|
||||
lateinit var name: String
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val chat: Chat by inject()
|
||||
private val broadcastQueue = ArrayDeque<Message>()
|
||||
|
||||
fun broadcast() {
|
||||
stop()
|
||||
broadcastQueue.clear()
|
||||
broadcastQueue.addAll(shuffledMessages())
|
||||
broadcastTask = announcerPlus.asyncTimer(0L, timeUnit.getTicks(interval)) {
|
||||
if (broadcastQueue.isNotEmpty()) {
|
||||
broadcast(broadcastQueue.removeFirst())
|
||||
} else {
|
||||
broadcast()
|
||||
}
|
||||
private fun broadcast(message: Message) {
|
||||
val onlinePlayers = announcerPlus.getOnMain { ImmutableList.copyOf(Bukkit.getOnlinePlayers()) }
|
||||
for (onlinePlayer in onlinePlayers) {
|
||||
if (announcerPlus.essentials != null) {
|
||||
if (announcerPlus.essentials!!.isAfk(onlinePlayer) && announcerPlus.perms!!.playerHas(onlinePlayer, "${announcerPlus.name}.messages.$name.afk")) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
private fun broadcast(message: Message) {
|
||||
val onlinePlayers = announcerPlus.getOnMain { ImmutableList.copyOf(Bukkit.getOnlinePlayers()) }
|
||||
for (onlinePlayer in onlinePlayers) {
|
||||
if (announcerPlus.essentials != null) {
|
||||
if (announcerPlus.essentials!!.isAfk(onlinePlayer) && announcerPlus.perms!!.playerHas(onlinePlayer, "${announcerPlus.name}.messages.$name.afk")) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (announcerPlus.perms!!.playerHas(onlinePlayer, "${announcerPlus.name}.messages.$name")) {
|
||||
with(message) {
|
||||
if (messageText.size != 0) {
|
||||
chat.send(onlinePlayer, configManager.parse(onlinePlayer, messageText))
|
||||
}
|
||||
chat.playSounds(onlinePlayer, soundsRandomized, sounds)
|
||||
messageElements().forEach { it.displayIfEnabled(onlinePlayer) }
|
||||
}
|
||||
announcerPlus.runSync {
|
||||
message.perPlayerCommands.forEach { dispatchCommandAsConsole(configManager.parse(onlinePlayer, it)) }
|
||||
message.asPlayerCommands.forEach { onlinePlayer.performCommand(configManager.parse(onlinePlayer, it)) }
|
||||
perPlayerCommands.forEach { dispatchCommandAsConsole(configManager.parse(onlinePlayer, it)) }
|
||||
asPlayerCommands.forEach { onlinePlayer.performCommand(configManager.parse(onlinePlayer, it)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (announcerPlus.perms!!.playerHas(onlinePlayer, "${announcerPlus.name}.messages.$name")) {
|
||||
with(message) {
|
||||
if (messageText.size != 0) {
|
||||
chat.send(onlinePlayer, configManager.parse(onlinePlayer, messageText))
|
||||
}
|
||||
chat.playSounds(onlinePlayer, soundsRandomized, sounds)
|
||||
messageElements().forEach { it.displayIfEnabled(onlinePlayer) }
|
||||
}
|
||||
announcerPlus.runSync {
|
||||
message.commands.forEach { dispatchCommandAsConsole(configManager.parse(null, it)) }
|
||||
commands.forEach { dispatchCommandAsConsole(configManager.parse(null, it)) }
|
||||
message.perPlayerCommands.forEach { dispatchCommandAsConsole(configManager.parse(onlinePlayer, it)) }
|
||||
message.asPlayerCommands.forEach { onlinePlayer.performCommand(configManager.parse(onlinePlayer, it)) }
|
||||
perPlayerCommands.forEach { dispatchCommandAsConsole(configManager.parse(onlinePlayer, it)) }
|
||||
asPlayerCommands.forEach { onlinePlayer.performCommand(configManager.parse(onlinePlayer, it)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun shuffledMessages(): List<Message> {
|
||||
if (randomOrder) {
|
||||
return messages.shuffled()
|
||||
}
|
||||
return messages
|
||||
announcerPlus.runSync {
|
||||
message.commands.forEach { dispatchCommandAsConsole(configManager.parse(null, it)) }
|
||||
commands.forEach { dispatchCommandAsConsole(configManager.parse(null, it)) }
|
||||
}
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
broadcastTask?.cancel()
|
||||
private fun shuffledMessages(): List<Message> {
|
||||
if (randomOrder) {
|
||||
return messages.shuffled()
|
||||
}
|
||||
return messages
|
||||
}
|
||||
|
||||
enum class TimeUnit(val ticks: Long) {
|
||||
SECONDS(20L),
|
||||
MINUTES(1200L),
|
||||
HOURS(72000L);
|
||||
fun stop() {
|
||||
broadcastTask?.cancel()
|
||||
}
|
||||
|
||||
fun getTicks(units: Int): Long =
|
||||
ticks * units
|
||||
}
|
||||
enum class TimeUnit(val ticks: Long) {
|
||||
SECONDS(20L),
|
||||
MINUTES(1200L),
|
||||
HOURS(72000L);
|
||||
|
||||
fun getTicks(units: Int): Long =
|
||||
ticks * units
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,38 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.config.message
|
||||
|
||||
import org.bukkit.entity.Player
|
||||
import org.koin.core.KoinComponent
|
||||
|
||||
interface MessageElement : KoinComponent {
|
||||
fun isEnabled(): Boolean
|
||||
fun display(player: Player)
|
||||
fun isEnabled(): Boolean
|
||||
fun display(player: Player)
|
||||
|
||||
fun displayIfEnabled(player: Player) {
|
||||
if (isEnabled()) {
|
||||
display(player)
|
||||
}
|
||||
fun displayIfEnabled(player: Player) {
|
||||
if (isEnabled()) {
|
||||
display(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.config.message
|
||||
|
||||
import org.bukkit.entity.Player
|
||||
@@ -7,39 +30,39 @@ import xyz.jpenilla.announcerplus.task.TitleUpdateTask
|
||||
|
||||
@ConfigSerializable
|
||||
class TitleSettings : MessageElement {
|
||||
constructor()
|
||||
constructor(fadeInSeconds: Int, durationSeconds: Int, fadeOutSeconds: Int, title: String, subTitle: String) {
|
||||
this.fadeInSeconds = fadeInSeconds
|
||||
this.fadeOutSeconds = fadeOutSeconds
|
||||
this.title = title
|
||||
this.subtitle = subTitle
|
||||
this.durationSeconds = durationSeconds
|
||||
constructor()
|
||||
constructor(fadeInSeconds: Int, durationSeconds: Int, fadeOutSeconds: Int, title: String, subTitle: String) {
|
||||
this.fadeInSeconds = fadeInSeconds
|
||||
this.fadeOutSeconds = fadeOutSeconds
|
||||
this.title = title
|
||||
this.subtitle = subTitle
|
||||
this.durationSeconds = durationSeconds
|
||||
}
|
||||
|
||||
@Comment("Seconds of duration for the title fade-in animation")
|
||||
var fadeInSeconds = 1
|
||||
|
||||
@Comment("Seconds of duration for the title to stay on screen")
|
||||
var durationSeconds = 5
|
||||
|
||||
@Comment("Seconds of duration for the title fade-out animation")
|
||||
var fadeOutSeconds = 1
|
||||
|
||||
@Comment("Title text. If the title and subtitle are both set to \"\" (empty string), then this title is disabled")
|
||||
var title = ""
|
||||
|
||||
@Comment("Subtitle text. If the title and subtitle are both set to \"\" (empty string), then this title is disabled")
|
||||
var subtitle = ""
|
||||
|
||||
override fun isEnabled(): Boolean {
|
||||
return if (fadeInSeconds == 0 && durationSeconds == 0 && fadeOutSeconds == 0) {
|
||||
false
|
||||
} else {
|
||||
title != "" || subtitle != ""
|
||||
}
|
||||
}
|
||||
|
||||
@Comment("Seconds of duration for the title fade-in animation")
|
||||
var fadeInSeconds = 1
|
||||
|
||||
@Comment("Seconds of duration for the title to stay on screen")
|
||||
var durationSeconds = 5
|
||||
|
||||
@Comment("Seconds of duration for the title fade-out animation")
|
||||
var fadeOutSeconds = 1
|
||||
|
||||
@Comment("Title text. If the title and subtitle are both set to \"\" (empty string), then this title is disabled")
|
||||
var title = ""
|
||||
|
||||
@Comment("Subtitle text. If the title and subtitle are both set to \"\" (empty string), then this title is disabled")
|
||||
var subtitle = ""
|
||||
|
||||
override fun isEnabled(): Boolean {
|
||||
return if (fadeInSeconds == 0 && durationSeconds == 0 && fadeOutSeconds == 0) {
|
||||
false
|
||||
} else {
|
||||
title != "" || subtitle != ""
|
||||
}
|
||||
}
|
||||
|
||||
override fun display(player: Player) {
|
||||
TitleUpdateTask(player, fadeInSeconds, durationSeconds, fadeOutSeconds, title, subtitle).start()
|
||||
}
|
||||
override fun display(player: Player) {
|
||||
TitleUpdateTask(player, fadeInSeconds, durationSeconds, fadeOutSeconds, title, subtitle).start()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.config.message
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
@@ -10,91 +33,92 @@ import org.koin.core.inject
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable
|
||||
import org.spongepowered.configurate.objectmapping.meta.Comment
|
||||
import xyz.jpenilla.announcerplus.AnnouncerPlus
|
||||
import xyz.jpenilla.jmplib.Environment
|
||||
|
||||
@ConfigSerializable
|
||||
class ToastSettings : MessageElement {
|
||||
|
||||
@Comment("The icon for the Toast/Advancement notification")
|
||||
var icon = Material.DIAMOND
|
||||
@Comment("The icon for the Toast/Advancement notification")
|
||||
var icon = Material.DIAMOND
|
||||
|
||||
@Comment("Should the icon item be enchanted?")
|
||||
var iconEnchanted = false
|
||||
@Comment("Should the icon item be enchanted?")
|
||||
var iconEnchanted = false
|
||||
|
||||
@Comment("Enter custom model data for the icon item. -1 to disable")
|
||||
var iconCustomModelData = -1
|
||||
@Comment("Enter custom model data for the icon item. -1 to disable")
|
||||
var iconCustomModelData = -1
|
||||
|
||||
@Comment("The text for the header of the Toast. If this and the footer are set to \"\" (empty string), the toast is disabled")
|
||||
var header = ""
|
||||
@Comment("The text for the header of the Toast. If this and the footer are set to \"\" (empty string), the toast is disabled")
|
||||
var header = ""
|
||||
|
||||
@Comment("The text for the footer of the Toast. If this and the header are set to \"\" (empty string), the toast is disabled")
|
||||
var footer = ""
|
||||
@Comment("The text for the footer of the Toast. If this and the header are set to \"\" (empty string), the toast is disabled")
|
||||
var footer = ""
|
||||
|
||||
@Comment("The frame for the Toast. Can be CHALLENGE, GOAL, or TASK")
|
||||
var frame = FrameType.GOAL
|
||||
@Comment("The frame for the Toast. Can be CHALLENGE, GOAL, or TASK")
|
||||
var frame = FrameType.GOAL
|
||||
|
||||
constructor()
|
||||
constructor(icon: Material, frameType: FrameType, header: String, footer: String) {
|
||||
this.icon = icon
|
||||
this.frame = frameType
|
||||
this.header = header
|
||||
this.footer = footer
|
||||
constructor()
|
||||
constructor(icon: Material, frameType: FrameType, header: String, footer: String) {
|
||||
this.icon = icon
|
||||
this.frame = frameType
|
||||
this.header = header
|
||||
this.footer = footer
|
||||
}
|
||||
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val miniMessage: MiniMessage by inject()
|
||||
|
||||
override fun isEnabled(): Boolean {
|
||||
return header != "" || footer != ""
|
||||
}
|
||||
|
||||
override fun display(player: Player) {
|
||||
announcerPlus.toastTask?.queueToast(this, player)
|
||||
}
|
||||
|
||||
fun getJson(player: Player): JsonObject {
|
||||
val json = JsonObject()
|
||||
val display = JsonObject()
|
||||
val icon = JsonObject()
|
||||
val iconString = if (Environment.majorMinecraftVersion() <= 12) this.icon.name else this.icon.key.toString()
|
||||
icon.addProperty("item", iconString)
|
||||
val nbtBuilder = StringBuilder("{CustomModelData:$iconCustomModelData")
|
||||
if (iconEnchanted) {
|
||||
nbtBuilder.append(",Enchantments:[{id:\"aqua_affinity\",lvl:1}]}")
|
||||
} else {
|
||||
nbtBuilder.append("}")
|
||||
}
|
||||
icon.addProperty("nbt", nbtBuilder.toString())
|
||||
display.add("icon", icon)
|
||||
val titleComponent = LinearComponents.linear(
|
||||
miniMessage.parse(announcerPlus.configManager.parse(player, header)),
|
||||
Component.newline(),
|
||||
miniMessage.parse(announcerPlus.configManager.parse(player, footer))
|
||||
)
|
||||
val title = announcerPlus.jsonParser.parse(
|
||||
if (Environment.majorMinecraftVersion() >= 16) {
|
||||
announcerPlus.gsonComponentSerializer.serialize(titleComponent)
|
||||
} else {
|
||||
announcerPlus.downsamplingGsonComponentSerializer.serialize(titleComponent)
|
||||
}
|
||||
)
|
||||
display.add("title", title)
|
||||
display.addProperty("description", "AnnouncerPlus Toast Description")
|
||||
display.addProperty("frame", frame.value)
|
||||
display.addProperty("announce_to_chat", false)
|
||||
display.addProperty("show_toast", true)
|
||||
display.addProperty("hidden", true)
|
||||
val trigger = JsonObject()
|
||||
trigger.addProperty("trigger", "minecraft:impossible")
|
||||
val criteria = JsonObject()
|
||||
criteria.add("impossible", trigger)
|
||||
json.add("criteria", criteria)
|
||||
json.add("display", display)
|
||||
return json
|
||||
}
|
||||
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val miniMessage: MiniMessage by inject()
|
||||
|
||||
override fun isEnabled(): Boolean {
|
||||
return header != "" || footer != ""
|
||||
}
|
||||
|
||||
override fun display(player: Player) {
|
||||
announcerPlus.toastTask?.queueToast(this, player)
|
||||
}
|
||||
|
||||
fun getJson(player: Player): JsonObject {
|
||||
val json = JsonObject()
|
||||
val display = JsonObject()
|
||||
val icon = JsonObject()
|
||||
val iconString = if (announcerPlus.majorMinecraftVersion <= 12) this.icon.name else this.icon.key.toString()
|
||||
icon.addProperty("item", iconString)
|
||||
val nbtBuilder = StringBuilder("{CustomModelData:$iconCustomModelData")
|
||||
if (iconEnchanted) {
|
||||
nbtBuilder.append(",Enchantments:[{id:\"aqua_affinity\",lvl:1}]}")
|
||||
} else {
|
||||
nbtBuilder.append("}")
|
||||
}
|
||||
icon.addProperty("nbt", nbtBuilder.toString())
|
||||
display.add("icon", icon)
|
||||
val titleComponent = LinearComponents.linear(
|
||||
miniMessage.parse(announcerPlus.configManager.parse(player, header)),
|
||||
Component.newline(),
|
||||
miniMessage.parse(announcerPlus.configManager.parse(player, footer))
|
||||
)
|
||||
val title = announcerPlus.jsonParser.parse(
|
||||
if (announcerPlus.majorMinecraftVersion >= 16) {
|
||||
announcerPlus.gsonComponentSerializer.serialize(titleComponent)
|
||||
} else {
|
||||
announcerPlus.downsamplingGsonComponentSerializer.serialize(titleComponent)
|
||||
}
|
||||
)
|
||||
display.add("title", title)
|
||||
display.addProperty("description", "AnnouncerPlus Toast Description")
|
||||
display.addProperty("frame", frame.value)
|
||||
display.addProperty("announce_to_chat", false)
|
||||
display.addProperty("show_toast", true)
|
||||
display.addProperty("hidden", true)
|
||||
val trigger = JsonObject()
|
||||
trigger.addProperty("trigger", "minecraft:impossible")
|
||||
val criteria = JsonObject()
|
||||
criteria.add("impossible", trigger)
|
||||
json.add("criteria", criteria)
|
||||
json.add("display", display)
|
||||
return json
|
||||
}
|
||||
|
||||
enum class FrameType(val value: String) {
|
||||
CHALLENGE("challenge"),
|
||||
GOAL("goal"),
|
||||
TASK("task"),
|
||||
}
|
||||
enum class FrameType(val value: String) {
|
||||
CHALLENGE("challenge"),
|
||||
GOAL("goal"),
|
||||
TASK("task"),
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.task
|
||||
|
||||
import org.bukkit.entity.Player
|
||||
@@ -6,28 +29,28 @@ import xyz.jpenilla.announcerplus.textanimation.AnimationHolder
|
||||
import xyz.jpenilla.jmplib.Chat
|
||||
|
||||
class ActionBarUpdateTask(
|
||||
private val player: Player,
|
||||
private val lifeTime: Long,
|
||||
private val shouldFade: Boolean,
|
||||
private val text: String
|
||||
private val player: Player,
|
||||
private val lifeTime: Long,
|
||||
private val shouldFade: Boolean,
|
||||
private val text: String
|
||||
) : UpdateTask() {
|
||||
private val chat: Chat by inject()
|
||||
private val animationHolder = AnimationHolder(player, text)
|
||||
private val chat: Chat by inject()
|
||||
private val animationHolder = AnimationHolder(player, text)
|
||||
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
if (!shouldFade) {
|
||||
chat.sendActionBar(player, "")
|
||||
}
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
if (!shouldFade) {
|
||||
chat.sendActionBar(player, "")
|
||||
}
|
||||
}
|
||||
|
||||
override fun update() {
|
||||
chat.sendActionBar(player, animationHolder.parseNext(text))
|
||||
}
|
||||
override fun update() {
|
||||
chat.sendActionBar(player, animationHolder.parseNext(text))
|
||||
}
|
||||
|
||||
override fun shouldContinue(): Boolean {
|
||||
return ticksLived < lifeTime && player.isOnline
|
||||
}
|
||||
override fun shouldContinue(): Boolean {
|
||||
return ticksLived < lifeTime && player.isOnline
|
||||
}
|
||||
|
||||
override fun synchronizationContext() = SynchronizationContext.ASYNC
|
||||
override fun synchronizationContext() = SynchronizationContext.ASYNC
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.task
|
||||
|
||||
import net.kyori.adventure.bossbar.BossBar
|
||||
@@ -11,44 +34,44 @@ import xyz.jpenilla.announcerplus.config.ConfigManager
|
||||
import xyz.jpenilla.announcerplus.textanimation.AnimationHolder
|
||||
|
||||
class BossBarUpdateTask(
|
||||
private val player: Player,
|
||||
private val lifeTime: Int,
|
||||
overlay: BossBar.Overlay,
|
||||
private val fillMode: FillMode,
|
||||
private val color: String,
|
||||
private val text: String
|
||||
private val player: Player,
|
||||
private val lifeTime: Int,
|
||||
overlay: BossBar.Overlay,
|
||||
private val fillMode: FillMode,
|
||||
private val color: String,
|
||||
private val text: String
|
||||
) : UpdateTask() {
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val miniMessage: MiniMessage by inject()
|
||||
private val audience = get<BukkitAudiences>().player(player)
|
||||
private val textAnimation = AnimationHolder(player, text)
|
||||
private val colorAnimation = AnimationHolder(player, color)
|
||||
private val bar = BossBar.bossBar(Component.empty(), 0.5f, BossBar.Color.BLUE, overlay)
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val miniMessage: MiniMessage by inject()
|
||||
private val audience = get<BukkitAudiences>().player(player)
|
||||
private val textAnimation = AnimationHolder(player, text)
|
||||
private val colorAnimation = AnimationHolder(player, color)
|
||||
private val bar = BossBar.bossBar(Component.empty(), 0.5f, BossBar.Color.BLUE, overlay)
|
||||
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
audience.hideBossBar(bar)
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
audience.hideBossBar(bar)
|
||||
}
|
||||
|
||||
override fun update() {
|
||||
bar.color(BossBar.Color.NAMES.value(colorAnimation.parseNext(color).toLowerCase()) ?: BossBar.Color.BLUE)
|
||||
bar.name(miniMessage.parse(configManager.parse(player, textAnimation.parseNext(text))))
|
||||
when (fillMode) {
|
||||
FillMode.FILL -> bar.progress(ticksLived / (lifeTime * 20f))
|
||||
FillMode.DRAIN -> bar.progress(1f - (ticksLived / (lifeTime * 20f)))
|
||||
FillMode.FULL -> if (ticksLived == 0L) bar.progress(1f)
|
||||
FillMode.EMPTY -> if (ticksLived == 0L) bar.progress(0f)
|
||||
}
|
||||
if (ticksLived == 0L) audience.showBossBar(bar)
|
||||
}
|
||||
|
||||
override fun update() {
|
||||
bar.color(BossBar.Color.NAMES.value(colorAnimation.parseNext(color).toLowerCase()) ?: BossBar.Color.BLUE)
|
||||
bar.name(miniMessage.parse(configManager.parse(player, textAnimation.parseNext(text))))
|
||||
when (fillMode) {
|
||||
FillMode.FILL -> bar.progress(ticksLived / (lifeTime * 20f))
|
||||
FillMode.DRAIN -> bar.progress(1f - (ticksLived / (lifeTime * 20f)))
|
||||
FillMode.FULL -> if (ticksLived == 0L) bar.progress(1f)
|
||||
FillMode.EMPTY -> if (ticksLived == 0L) bar.progress(0f)
|
||||
}
|
||||
if (ticksLived == 0L) audience.showBossBar(bar)
|
||||
}
|
||||
override fun shouldContinue(): Boolean {
|
||||
return ticksLived < lifeTime * 20L && player.isOnline
|
||||
}
|
||||
|
||||
override fun shouldContinue(): Boolean {
|
||||
return ticksLived < lifeTime * 20L && player.isOnline
|
||||
}
|
||||
override fun synchronizationContext() = SynchronizationContext.ASYNC
|
||||
|
||||
override fun synchronizationContext() = SynchronizationContext.ASYNC
|
||||
|
||||
enum class FillMode {
|
||||
FILL, DRAIN, FULL, EMPTY
|
||||
}
|
||||
enum class FillMode {
|
||||
FILL, DRAIN, FULL, EMPTY
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.task
|
||||
|
||||
import org.bukkit.entity.Player
|
||||
@@ -8,42 +31,52 @@ import xyz.jpenilla.jmplib.Chat
|
||||
import java.time.temporal.ChronoUnit
|
||||
|
||||
class TitleUpdateTask(
|
||||
private val player: Player,
|
||||
private val fadeIn: Int,
|
||||
private val duration: Int,
|
||||
private val fadeOut: Int,
|
||||
private val title: String,
|
||||
private val subTitle: String
|
||||
private val player: Player,
|
||||
private val fadeIn: Int,
|
||||
private val duration: Int,
|
||||
private val fadeOut: Int,
|
||||
private val title: String,
|
||||
private val subTitle: String
|
||||
) : UpdateTask() {
|
||||
private val chat: Chat by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val titleAnimation = AnimationHolder(player, title)
|
||||
private val subTitleAnimation = AnimationHolder(player, subTitle)
|
||||
private val chat: Chat by inject()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val titleAnimation = AnimationHolder(player, title)
|
||||
private val subTitleAnimation = AnimationHolder(player, subTitle)
|
||||
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
if (fadeOut == 0) {
|
||||
chat.showTitle(player, chat.getTitleSeconds("", "", 0, 0, 0))
|
||||
} else {
|
||||
chat.showTitle(player, chat.getTitleSeconds(configManager.parse(player, titleAnimation.parseNext(title)), subTitleAnimation.parseNext(subTitle), 0, 0, fadeOut))
|
||||
}
|
||||
override fun stop() {
|
||||
super.stop()
|
||||
if (fadeOut != 0) {
|
||||
chat.showTitle(
|
||||
player,
|
||||
chat.getTitleSeconds(configManager.parse(player, titleAnimation.parseNext(title)), subTitleAnimation.parseNext(subTitle), 0, 0, fadeOut)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun update() {
|
||||
when (fadeIn) {
|
||||
0 -> chat.showTitle(player, chat.getTitle(configManager.parse(player, titleAnimation.parseNext(title)), subTitleAnimation.parseNext(subTitle), ChronoUnit.SECONDS, 0, ChronoUnit.MILLIS, 200, ChronoUnit.SECONDS, 0))
|
||||
else -> when (ticksLived) {
|
||||
0L -> chat.showTitle(player, chat.getTitle(configManager.parse(player, titleAnimation.parseNext(title)), subTitleAnimation.parseNext(subTitle), ChronoUnit.SECONDS, fadeIn, ChronoUnit.MILLIS, 200, ChronoUnit.SECONDS, 0))
|
||||
else -> if (ticksLived > fadeIn * 20L) {
|
||||
chat.showTitle(player, chat.getTitle(configManager.parse(player, titleAnimation.parseNext(title)), subTitleAnimation.parseNext(subTitle), ChronoUnit.SECONDS, 0, ChronoUnit.MILLIS, 200, ChronoUnit.SECONDS, 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun update() {
|
||||
if (fadeIn == 0) {
|
||||
chat.showTitle(
|
||||
player,
|
||||
chat.getTitle(configManager.parse(player, titleAnimation.parseNext(title)), subTitleAnimation.parseNext(subTitle), ChronoUnit.SECONDS, 0, ChronoUnit.MILLIS, 200, ChronoUnit.SECONDS, 0)
|
||||
)
|
||||
} else {
|
||||
if (ticksLived == 0L) {
|
||||
chat.showTitle(
|
||||
player,
|
||||
chat.getTitle(configManager.parse(player, titleAnimation.parseNext(title)), subTitleAnimation.parseNext(subTitle), ChronoUnit.SECONDS, fadeIn, ChronoUnit.MILLIS, 200, ChronoUnit.SECONDS, 0)
|
||||
)
|
||||
} else if (ticksLived > fadeIn * 20L) {
|
||||
chat.showTitle(
|
||||
player,
|
||||
chat.getTitle(configManager.parse(player, titleAnimation.parseNext(title)), subTitleAnimation.parseNext(subTitle), ChronoUnit.SECONDS, 0, ChronoUnit.MILLIS, 200, ChronoUnit.SECONDS, 0)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldContinue(): Boolean {
|
||||
return ticksLived < 20L * (fadeIn + duration) && player.isOnline
|
||||
}
|
||||
override fun shouldContinue(): Boolean {
|
||||
return ticksLived < 20L * (fadeIn + duration) && player.isOnline
|
||||
}
|
||||
|
||||
override fun synchronizationContext() = SynchronizationContext.ASYNC
|
||||
override fun synchronizationContext() = SynchronizationContext.ASYNC
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.task
|
||||
|
||||
import com.google.gson.Gson
|
||||
@@ -10,165 +33,166 @@ import xyz.jpenilla.announcerplus.config.message.ToastSettings
|
||||
import xyz.jpenilla.announcerplus.util.asyncTimer
|
||||
import xyz.jpenilla.announcerplus.util.runSync
|
||||
import xyz.jpenilla.jmplib.Crafty
|
||||
import xyz.jpenilla.jmplib.Environment
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util.concurrent.ConcurrentLinkedDeque
|
||||
import kotlin.random.Random.Default.nextInt
|
||||
|
||||
class ToastTask : KoinComponent {
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val queuedToasts = ConcurrentLinkedDeque<QueuedToast>()
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private val queuedToasts = ConcurrentLinkedDeque<QueuedToast>()
|
||||
|
||||
private val toastTask = announcerPlus.asyncTimer(0L, 1L) {
|
||||
if (queuedToasts.isNotEmpty()) {
|
||||
val toast = queuedToasts.removeFirst()
|
||||
if (toast.player.isOnline) {
|
||||
displayToastImmediately(toast)
|
||||
}
|
||||
private val toastTask = announcerPlus.asyncTimer(0L, 1L) {
|
||||
if (queuedToasts.isNotEmpty()) {
|
||||
val toast = queuedToasts.removeFirst()
|
||||
if (toast.player.isOnline) {
|
||||
displayToastImmediately(toast)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun queueToast(toastSettings: ToastSettings, player: Player) {
|
||||
queuedToasts.add(QueuedToast(player, toastSettings))
|
||||
}
|
||||
|
||||
fun cancel() {
|
||||
toastTask.cancel()
|
||||
}
|
||||
|
||||
data class QueuedToast(val player: Player, val toast: ToastSettings)
|
||||
|
||||
private fun displayToastImmediately(queuedToast: QueuedToast) {
|
||||
val (player, toast) = queuedToast
|
||||
announcerPlus.runSync {
|
||||
val minecraftKey =
|
||||
MinecraftKey_ctr.newInstance(announcerPlus.name.toLowerCase(), nextInt(1000000).toString())
|
||||
val serializedAdvancement = if (Environment.majorMinecraftVersion() >= 16) {
|
||||
SerializedAdvancement_deserialize(
|
||||
null,
|
||||
toast.getJson(player),
|
||||
LootDeserializationContext_ctr.newInstance(
|
||||
minecraftKey,
|
||||
MinecraftServer_getLootPredicateManager(MinecraftServer_getServer())
|
||||
)
|
||||
)
|
||||
} else {
|
||||
ChatDeserializer_deserialize(
|
||||
null,
|
||||
AdvancementDataWorld_DESERIALIZER,
|
||||
announcerPlus.gson.toJson(toast.getJson(player)),
|
||||
SerializedAdvancement_class
|
||||
)
|
||||
}
|
||||
val advancement = SerializedAdvancement_getAdvancement(serializedAdvancement, minecraftKey)
|
||||
val nmsPlayer = player.handle
|
||||
val advancementData = EntityPlayer_getAdvancementData(nmsPlayer)
|
||||
val advancementProgress = AdvancementDataPlayer_getProgress(advancementData, advancement)
|
||||
(AdvancementProgress_remainingCriteria(advancementProgress) as Iterable<*>).forEach {
|
||||
AdvancementDataPlayer_grantCriteria(advancementData, advancement, it)
|
||||
}
|
||||
announcerPlus.runSync(20L) {
|
||||
(AdvancementProgress_awardedCriteria(advancementProgress) as Iterable<*>).forEach {
|
||||
AdvancementDataPlayer_revokeCriteria(advancementData, advancement, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object Reflect {
|
||||
val MinecraftServer_class = Crafty.needNmsClass("MinecraftServer")
|
||||
val MinecraftServer_getServer =
|
||||
Crafty.findStaticMethod(MinecraftServer_class, "getServer", MinecraftServer_class)
|
||||
?: error("Cannot find getServer")
|
||||
|
||||
val MinecraftKey_class = Crafty.needNmsClass("MinecraftKey")
|
||||
val MinecraftKey_ctr = MinecraftKey_class.getDeclaredConstructor(String::class.java, String::class.java)
|
||||
?: error("Cannot find MinecraftKey constructor")
|
||||
|
||||
val Advancement_class = Crafty.needNmsClass("Advancement")
|
||||
val SerializedAdvancement_class = Crafty.needNmsClass("Advancement\$SerializedAdvancement")
|
||||
|
||||
val SerializedAdvancement_getAdvancement = SerializedAdvancement_class.declaredMethods.find { method ->
|
||||
method.returnType == Advancement_class
|
||||
&& method.parameterCount == 1
|
||||
&& method.parameterTypes[0] == MinecraftKey_class
|
||||
&& !Modifier.isStatic(method.modifiers)
|
||||
} ?: error("Cannot find SerializedAdvancement#getAdvancement")
|
||||
|
||||
val EntityPlayer_class = Crafty.needNmsClass("EntityPlayer")
|
||||
val CraftPlayer_class = Crafty.needCraftClass("entity.CraftPlayer")
|
||||
val CraftPlayer_getHandle = CraftPlayer_class.getMethod("getHandle")
|
||||
?: error("Cannot find CraftPlayer#getHandle")
|
||||
val Player.handle: Any
|
||||
get() = CraftPlayer_getHandle(this)
|
||||
|
||||
val AdvancementProgress_class = Crafty.needNmsClass("AdvancementProgress")
|
||||
val AdvancementDataPlayer_class = Crafty.needNmsClass("AdvancementDataPlayer")
|
||||
val EntityPlayer_getAdvancementData = EntityPlayer_class.methods.find { method ->
|
||||
method.returnType == AdvancementDataPlayer_class
|
||||
&& method.parameterCount == 0
|
||||
} ?: error("Cannot find EntityPlayer#getAdvancementData")
|
||||
|
||||
val AdvancementDataPlayer_getProgress = AdvancementDataPlayer_class.methods.find { method ->
|
||||
method.returnType == AdvancementProgress_class
|
||||
&& method.parameterCount == 1
|
||||
&& method.parameterTypes[0] == Advancement_class
|
||||
} ?: error("Cannot find AdvancementDataPlayer#getProgress")
|
||||
|
||||
val AdvancementDataPlayer_grantCriteria =
|
||||
AdvancementDataPlayer_class.getDeclaredMethod("grantCriteria", Advancement_class, String::class.java)
|
||||
?: error("Cannot find AdvancementDataPlayer#grantCriteria")
|
||||
val AdvancementDataPlayer_revokeCriteria = try {
|
||||
AdvancementDataPlayer_class.getDeclaredMethod("revokeCritera", Advancement_class, String::class.java) // lol
|
||||
} catch (e: NoSuchMethodException) {
|
||||
AdvancementDataPlayer_class.getDeclaredMethod("revokeCriteria", Advancement_class, String::class.java)
|
||||
} ?: error("Cannot find AdvancementDataPlayer#revokeCriteria")
|
||||
val AdvancementProgress_remainingCriteria = AdvancementProgress_class.getDeclaredMethod("getRemainingCriteria")
|
||||
?: error("Cannot find AdvancementProgress#getRemainingCriteria")
|
||||
val AdvancementProgress_awardedCriteria = AdvancementProgress_class.getDeclaredMethod("getAwardedCriteria")
|
||||
?: error("Cannot find AdvancementProgress#getAwardedCriteria")
|
||||
|
||||
// start 1.12 -> 1.15
|
||||
val ChatDeserializer_class by lazy { Crafty.needNmsClass("ChatDeserializer") }
|
||||
val AdvancementDataWorld_class by lazy { Crafty.needNmsClass("AdvancementDataWorld") }
|
||||
|
||||
val ChatDeserializer_deserialize by lazy {
|
||||
ChatDeserializer_class.methods.find { method ->
|
||||
method.parameterCount == 3
|
||||
&& method.parameterTypes.contains(Gson::class.java)
|
||||
&& method.parameterTypes.contains(String::class.java)
|
||||
&& method.parameterTypes.contains(Class::class.java)
|
||||
} ?: error("Cannot find ChatDeserializer.deserialize")
|
||||
}
|
||||
|
||||
fun queueToast(toastSettings: ToastSettings, player: Player) {
|
||||
queuedToasts.add(QueuedToast(player, toastSettings))
|
||||
val AdvancementDataWorld_DESERIALIZER by lazy {
|
||||
AdvancementDataWorld_class.getField("DESERIALIZER").get(null)
|
||||
?: error("Cannot find AdvancementDataWorld.DESERIALIZER")
|
||||
}
|
||||
// end 1.12 -> 1.15
|
||||
|
||||
// start 1.16+
|
||||
val LootPredicateManager_class by lazy { Crafty.needNmsClass("LootPredicateManager") }
|
||||
val MinecraftServer_getLootPredicateManager by lazy {
|
||||
MinecraftServer_class.declaredMethods.find { method ->
|
||||
method.returnType == LootPredicateManager_class
|
||||
&& method.parameterCount == 0
|
||||
} ?: error("Cannot find MinecraftServer#getLootPredicateManager")
|
||||
}
|
||||
|
||||
fun cancel() {
|
||||
toastTask.cancel()
|
||||
val LootDeserializationContext_class by lazy { Crafty.needNmsClass("LootDeserializationContext") }
|
||||
val LootDeserializationContext_ctr by lazy {
|
||||
LootDeserializationContext_class.getDeclaredConstructor(MinecraftKey_class, LootPredicateManager_class)
|
||||
?: error("Cannot find LootDeserializationContext constructor")
|
||||
}
|
||||
|
||||
data class QueuedToast(val player: Player, val toast: ToastSettings)
|
||||
|
||||
private fun displayToastImmediately(queuedToast: QueuedToast) {
|
||||
val (player, toast) = queuedToast
|
||||
announcerPlus.runSync {
|
||||
val minecraftKey =
|
||||
MinecraftKey_ctr.newInstance(announcerPlus.name.toLowerCase(), nextInt(1000000).toString())
|
||||
val serializedAdvancement = if (announcerPlus.majorMinecraftVersion >= 16) {
|
||||
SerializedAdvancement_deserialize(
|
||||
null,
|
||||
toast.getJson(player),
|
||||
LootDeserializationContext_ctr.newInstance(
|
||||
minecraftKey,
|
||||
MinecraftServer_getLootPredicateManager(MinecraftServer_getServer())
|
||||
)
|
||||
)
|
||||
} else {
|
||||
ChatDeserializer_deserialize(
|
||||
null,
|
||||
AdvancementDataWorld_DESERIALIZER,
|
||||
announcerPlus.gson.toJson(toast.getJson(player)),
|
||||
SerializedAdvancement_class
|
||||
)
|
||||
}
|
||||
val advancement = SerializedAdvancement_getAdvancement(serializedAdvancement, minecraftKey)
|
||||
val nmsPlayer = player.handle
|
||||
val advancementData = EntityPlayer_getAdvancementData(nmsPlayer)
|
||||
val advancementProgress = AdvancementDataPlayer_getProgress(advancementData, advancement)
|
||||
(AdvancementProgress_remainingCriteria(advancementProgress) as Iterable<*>).forEach {
|
||||
AdvancementDataPlayer_grantCriteria(advancementData, advancement, it)
|
||||
}
|
||||
announcerPlus.runSync(20L) {
|
||||
(AdvancementProgress_awardedCriteria(advancementProgress) as Iterable<*>).forEach {
|
||||
AdvancementDataPlayer_revokeCriteria(advancementData, advancement, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object Reflect {
|
||||
val MinecraftServer_class = Crafty.needNmsClass("MinecraftServer")
|
||||
val MinecraftServer_getServer =
|
||||
Crafty.findStaticMethod(MinecraftServer_class, "getServer", MinecraftServer_class)
|
||||
?: error("Cannot find getServer")
|
||||
|
||||
val MinecraftKey_class = Crafty.needNmsClass("MinecraftKey")
|
||||
val MinecraftKey_ctr = MinecraftKey_class.getDeclaredConstructor(String::class.java, String::class.java)
|
||||
?: error("Cannot find MinecraftKey constructor")
|
||||
|
||||
val Advancement_class = Crafty.needNmsClass("Advancement")
|
||||
val SerializedAdvancement_class = Crafty.needNmsClass("Advancement\$SerializedAdvancement")
|
||||
|
||||
val SerializedAdvancement_getAdvancement = SerializedAdvancement_class.declaredMethods.find { method ->
|
||||
method.returnType == Advancement_class
|
||||
&& method.parameterCount == 1
|
||||
&& method.parameterTypes[0] == MinecraftKey_class
|
||||
&& !Modifier.isStatic(method.modifiers)
|
||||
} ?: error("Cannot find SerializedAdvancement#getAdvancement")
|
||||
|
||||
val EntityPlayer_class = Crafty.needNmsClass("EntityPlayer")
|
||||
val CraftPlayer_class = Crafty.needCraftClass("entity.CraftPlayer")
|
||||
val CraftPlayer_getHandle = CraftPlayer_class.getMethod("getHandle")
|
||||
?: error("Cannot find CraftPlayer#getHandle")
|
||||
val Player.handle: Any
|
||||
get() = CraftPlayer_getHandle(this)
|
||||
|
||||
val AdvancementProgress_class = Crafty.needNmsClass("AdvancementProgress")
|
||||
val AdvancementDataPlayer_class = Crafty.needNmsClass("AdvancementDataPlayer")
|
||||
val EntityPlayer_getAdvancementData = EntityPlayer_class.methods.find { method ->
|
||||
method.returnType == AdvancementDataPlayer_class
|
||||
&& method.parameterCount == 0
|
||||
} ?: error("Cannot find EntityPlayer#getAdvancementData")
|
||||
|
||||
val AdvancementDataPlayer_getProgress = AdvancementDataPlayer_class.methods.find { method ->
|
||||
method.returnType == AdvancementProgress_class
|
||||
&& method.parameterCount == 1
|
||||
&& method.parameterTypes[0] == Advancement_class
|
||||
} ?: error("Cannot find AdvancementDataPlayer#getProgress")
|
||||
|
||||
val AdvancementDataPlayer_grantCriteria =
|
||||
AdvancementDataPlayer_class.getDeclaredMethod("grantCriteria", Advancement_class, String::class.java)
|
||||
?: error("Cannot find AdvancementDataPlayer#grantCriteria")
|
||||
val AdvancementDataPlayer_revokeCriteria = try {
|
||||
AdvancementDataPlayer_class.getDeclaredMethod("revokeCritera", Advancement_class, String::class.java) // lol
|
||||
} catch (e: NoSuchMethodException) {
|
||||
AdvancementDataPlayer_class.getDeclaredMethod("revokeCriteria", Advancement_class, String::class.java)
|
||||
} ?: error("Cannot find AdvancementDataPlayer#revokeCriteria")
|
||||
val AdvancementProgress_remainingCriteria = AdvancementProgress_class.getDeclaredMethod("getRemainingCriteria")
|
||||
?: error("Cannot find AdvancementProgress#getRemainingCriteria")
|
||||
val AdvancementProgress_awardedCriteria = AdvancementProgress_class.getDeclaredMethod("getAwardedCriteria")
|
||||
?: error("Cannot find AdvancementProgress#getAwardedCriteria")
|
||||
|
||||
// start 1.12 -> 1.15
|
||||
val ChatDeserializer_class by lazy { Crafty.needNmsClass("ChatDeserializer") }
|
||||
val AdvancementDataWorld_class by lazy { Crafty.needNmsClass("AdvancementDataWorld") }
|
||||
|
||||
val ChatDeserializer_deserialize by lazy {
|
||||
ChatDeserializer_class.methods.find { method ->
|
||||
method.parameterCount == 3
|
||||
&& method.parameterTypes.contains(Gson::class.java)
|
||||
&& method.parameterTypes.contains(String::class.java)
|
||||
&& method.parameterTypes.contains(Class::class.java)
|
||||
} ?: error("Cannot find ChatDeserializer.deserialize")
|
||||
}
|
||||
|
||||
val AdvancementDataWorld_DESERIALIZER by lazy {
|
||||
AdvancementDataWorld_class.getField("DESERIALIZER").get(null)
|
||||
?: error("Cannot find AdvancementDataWorld.DESERIALIZER")
|
||||
}
|
||||
// end 1.12 -> 1.15
|
||||
|
||||
// start 1.16+
|
||||
val LootPredicateManager_class by lazy { Crafty.needNmsClass("LootPredicateManager") }
|
||||
val MinecraftServer_getLootPredicateManager by lazy {
|
||||
MinecraftServer_class.declaredMethods.find { method ->
|
||||
method.returnType == LootPredicateManager_class
|
||||
&& method.parameterCount == 0
|
||||
} ?: error("Cannot find MinecraftServer#getLootPredicateManager")
|
||||
}
|
||||
|
||||
val LootDeserializationContext_class by lazy { Crafty.needNmsClass("LootDeserializationContext") }
|
||||
val LootDeserializationContext_ctr by lazy {
|
||||
LootDeserializationContext_class.getDeclaredConstructor(MinecraftKey_class, LootPredicateManager_class)
|
||||
?: error("Cannot find LootDeserializationContext constructor")
|
||||
}
|
||||
|
||||
val SerializedAdvancement_deserialize by lazy {
|
||||
SerializedAdvancement_class.declaredMethods.find { method ->
|
||||
method.returnType == SerializedAdvancement_class
|
||||
&& method.parameterCount == 2
|
||||
&& method.parameterTypes.contains(JsonObject::class.java)
|
||||
&& method.parameterTypes.contains(LootDeserializationContext_class)
|
||||
} ?: error("Cannot find SerializedAdvancement.deserialize")
|
||||
}
|
||||
// end 1.16+
|
||||
val SerializedAdvancement_deserialize by lazy {
|
||||
SerializedAdvancement_class.declaredMethods.find { method ->
|
||||
method.returnType == SerializedAdvancement_class
|
||||
&& method.parameterCount == 2
|
||||
&& method.parameterTypes.contains(JsonObject::class.java)
|
||||
&& method.parameterTypes.contains(LootDeserializationContext_class)
|
||||
} ?: error("Cannot find SerializedAdvancement.deserialize")
|
||||
}
|
||||
// end 1.16+
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.task
|
||||
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
@@ -8,38 +31,38 @@ import xyz.jpenilla.announcerplus.util.asyncTimer
|
||||
import xyz.jpenilla.announcerplus.util.syncTimer
|
||||
|
||||
abstract class UpdateTask : KoinComponent {
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private var updateTask: BukkitTask? = null
|
||||
var ticksLived = 0L
|
||||
private val announcerPlus: AnnouncerPlus by inject()
|
||||
private var updateTask: BukkitTask? = null
|
||||
var ticksLived = 0L
|
||||
|
||||
open fun start(): UpdateTask = apply {
|
||||
open fun start(): UpdateTask = apply {
|
||||
stop()
|
||||
val runnable = Runnable {
|
||||
if (!shouldContinue()) {
|
||||
stop()
|
||||
val runnable = Runnable {
|
||||
if (!shouldContinue()) {
|
||||
stop()
|
||||
}
|
||||
update()
|
||||
ticksLived++
|
||||
}
|
||||
updateTask = when (synchronizationContext()) {
|
||||
SynchronizationContext.SYNC -> announcerPlus.syncTimer(0L, 1L, runnable)
|
||||
SynchronizationContext.ASYNC -> announcerPlus.asyncTimer(0L, 1L, runnable)
|
||||
}
|
||||
}
|
||||
update()
|
||||
ticksLived++
|
||||
}
|
||||
|
||||
open fun stop() {
|
||||
updateTask?.cancel()
|
||||
updateTask = null
|
||||
updateTask = when (synchronizationContext()) {
|
||||
SynchronizationContext.SYNC -> announcerPlus.syncTimer(0L, 1L, runnable)
|
||||
SynchronizationContext.ASYNC -> announcerPlus.asyncTimer(0L, 1L, runnable)
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun update()
|
||||
open fun stop() {
|
||||
updateTask?.cancel()
|
||||
updateTask = null
|
||||
}
|
||||
|
||||
abstract fun shouldContinue(): Boolean
|
||||
abstract fun update()
|
||||
|
||||
abstract fun synchronizationContext(): SynchronizationContext
|
||||
abstract fun shouldContinue(): Boolean
|
||||
|
||||
enum class SynchronizationContext {
|
||||
SYNC,
|
||||
ASYNC
|
||||
}
|
||||
abstract fun synchronizationContext(): SynchronizationContext
|
||||
|
||||
enum class SynchronizationContext {
|
||||
SYNC,
|
||||
ASYNC
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.textanimation
|
||||
|
||||
import net.kyori.adventure.text.format.NamedTextColor
|
||||
@@ -14,112 +37,112 @@ import xyz.jpenilla.announcerplus.textanimation.animation.ScrollingText
|
||||
import xyz.jpenilla.announcerplus.textanimation.animation.Typewriter
|
||||
|
||||
class AnimationHolder(private val player: Player?, private val message: String) : KoinComponent {
|
||||
companion object {
|
||||
private val pattern = "\\{animate:/?([a-z][^}]*)/?}?".toPattern()
|
||||
}
|
||||
companion object {
|
||||
private val pattern = "\\{animate:/?([a-z][^}]*)/?}?".toPattern()
|
||||
}
|
||||
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val matcher = pattern.matcher(message)
|
||||
private val animations = HashMap<String, TextAnimation>()
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val matcher = pattern.matcher(message)
|
||||
private val animations = HashMap<String, TextAnimation>()
|
||||
|
||||
init {
|
||||
while (matcher.find()) {
|
||||
val tokens = matcher.group(1).split(":")
|
||||
init {
|
||||
while (matcher.find()) {
|
||||
val tokens = matcher.group(1).split(":")
|
||||
|
||||
when (tokens[0]) {
|
||||
"scroll" -> {
|
||||
val speed = try {
|
||||
tokens[1].toFloat()
|
||||
} catch (e: Exception) {
|
||||
0.1f
|
||||
}
|
||||
animations[matcher.group()] = ScrollingGradient(speed)
|
||||
}
|
||||
|
||||
"flash" -> {
|
||||
val colors = ArrayList(tokens.subList(1, tokens.size))
|
||||
var ticks: Int
|
||||
try {
|
||||
ticks = colors.last().toInt()
|
||||
colors.removeAt(colors.lastIndex)
|
||||
} catch (e: Exception) {
|
||||
ticks = 10
|
||||
}
|
||||
animations[matcher.group()] = FlashingText(colors, ticks)
|
||||
}
|
||||
|
||||
"pulse" -> {
|
||||
val colors = ArrayList(tokens.subList(1, tokens.size))
|
||||
var ticks: Int
|
||||
try {
|
||||
ticks = colors.last().toInt()
|
||||
colors.removeAt(colors.lastIndex)
|
||||
} catch (e: Exception) {
|
||||
ticks = 10
|
||||
}
|
||||
val textColors = colors.map { color ->
|
||||
NamedTextColor.NAMES.value(color)
|
||||
?: TextColor.fromHexString(color)
|
||||
?: NamedTextColor.WHITE
|
||||
}
|
||||
animations[matcher.group()] = PulsingColor(textColors, ticks)
|
||||
}
|
||||
|
||||
"type" -> {
|
||||
val text = tokens[1]
|
||||
val ticks = try {
|
||||
tokens[2].toInt()
|
||||
} catch (e: Exception) {
|
||||
6
|
||||
}
|
||||
animations[matcher.group()] = Typewriter(player, text, ticks)
|
||||
}
|
||||
|
||||
"randomcolor" -> {
|
||||
val type = try {
|
||||
RandomColor.Type.of(tokens[1])
|
||||
} catch (e: Exception) {
|
||||
RandomColor.Type.PULSE
|
||||
}
|
||||
val ticks = try {
|
||||
tokens[2].toInt()
|
||||
} catch (e: Exception) {
|
||||
10
|
||||
}
|
||||
animations[matcher.group()] = RandomColor(type, ticks)
|
||||
}
|
||||
|
||||
"scrolltext" -> {
|
||||
val text = tokens[1]
|
||||
val window = try {
|
||||
tokens[2].toInt()
|
||||
} catch (e: Exception) {
|
||||
10
|
||||
}
|
||||
val ticks = try {
|
||||
tokens[3].toInt()
|
||||
} catch (e: Exception) {
|
||||
4
|
||||
}
|
||||
animations[matcher.group()] = ScrollingText(player, text, window, ticks)
|
||||
}
|
||||
}
|
||||
when (tokens[0]) {
|
||||
"scroll" -> {
|
||||
val speed = try {
|
||||
tokens[1].toFloat()
|
||||
} catch (e: Exception) {
|
||||
0.1f
|
||||
}
|
||||
animations[matcher.group()] = ScrollingGradient(speed)
|
||||
}
|
||||
}
|
||||
|
||||
fun parseNext(text: String = message): String {
|
||||
var msg = text
|
||||
animations.forEach { animation ->
|
||||
msg = msg.replace(animation.key, animation.value.nextValue())
|
||||
"flash" -> {
|
||||
val colors = ArrayList(tokens.subList(1, tokens.size))
|
||||
var ticks: Int
|
||||
try {
|
||||
ticks = colors.last().toInt()
|
||||
colors.removeAt(colors.lastIndex)
|
||||
} catch (e: Exception) {
|
||||
ticks = 10
|
||||
}
|
||||
animations[matcher.group()] = FlashingText(colors, ticks)
|
||||
}
|
||||
return configManager.parse(player, msg)
|
||||
}
|
||||
|
||||
fun parseCurrent(text: String = message): String {
|
||||
var msg = text
|
||||
animations.forEach { animation ->
|
||||
msg = msg.replace(animation.key, animation.value.getValue())
|
||||
"pulse" -> {
|
||||
val colors = ArrayList(tokens.subList(1, tokens.size))
|
||||
var ticks: Int
|
||||
try {
|
||||
ticks = colors.last().toInt()
|
||||
colors.removeAt(colors.lastIndex)
|
||||
} catch (e: Exception) {
|
||||
ticks = 10
|
||||
}
|
||||
val textColors = colors.map { color ->
|
||||
NamedTextColor.NAMES.value(color)
|
||||
?: TextColor.fromHexString(color)
|
||||
?: NamedTextColor.WHITE
|
||||
}
|
||||
animations[matcher.group()] = PulsingColor(textColors, ticks)
|
||||
}
|
||||
return configManager.parse(player, msg)
|
||||
|
||||
"type" -> {
|
||||
val text = tokens[1]
|
||||
val ticks = try {
|
||||
tokens[2].toInt()
|
||||
} catch (e: Exception) {
|
||||
6
|
||||
}
|
||||
animations[matcher.group()] = Typewriter(player, text, ticks)
|
||||
}
|
||||
|
||||
"randomcolor" -> {
|
||||
val type = try {
|
||||
RandomColor.Type.of(tokens[1])
|
||||
} catch (e: Exception) {
|
||||
RandomColor.Type.PULSE
|
||||
}
|
||||
val ticks = try {
|
||||
tokens[2].toInt()
|
||||
} catch (e: Exception) {
|
||||
10
|
||||
}
|
||||
animations[matcher.group()] = RandomColor(type, ticks)
|
||||
}
|
||||
|
||||
"scrolltext" -> {
|
||||
val text = tokens[1]
|
||||
val window = try {
|
||||
tokens[2].toInt()
|
||||
} catch (e: Exception) {
|
||||
10
|
||||
}
|
||||
val ticks = try {
|
||||
tokens[3].toInt()
|
||||
} catch (e: Exception) {
|
||||
4
|
||||
}
|
||||
animations[matcher.group()] = ScrollingText(player, text, window, ticks)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun parseNext(text: String = message): String {
|
||||
var msg = text
|
||||
animations.forEach { animation ->
|
||||
msg = msg.replace(animation.key, animation.value.nextValue())
|
||||
}
|
||||
return configManager.parse(player, msg)
|
||||
}
|
||||
|
||||
fun parseCurrent(text: String = message): String {
|
||||
var msg = text
|
||||
animations.forEach { animation ->
|
||||
msg = msg.replace(animation.key, animation.value.getValue())
|
||||
}
|
||||
return configManager.parse(player, msg)
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,31 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.textanimation
|
||||
|
||||
import org.koin.core.KoinComponent
|
||||
|
||||
interface TextAnimation : KoinComponent {
|
||||
fun getValue(): String
|
||||
fun nextValue(): String
|
||||
fun getValue(): String
|
||||
fun nextValue(): String
|
||||
}
|
||||
+39
-16
@@ -1,25 +1,48 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.textanimation.animation
|
||||
|
||||
import xyz.jpenilla.announcerplus.textanimation.TextAnimation
|
||||
|
||||
class FlashingText(private val colors: List<String>, private val ticks: Int) : TextAnimation {
|
||||
private var index = 0
|
||||
private var ticksLived = 0
|
||||
private var color = colors[0]
|
||||
private var index = 0
|
||||
private var ticksLived = 0
|
||||
private var color = colors[0]
|
||||
|
||||
override fun getValue(): String {
|
||||
return color
|
||||
}
|
||||
override fun getValue(): String {
|
||||
return color
|
||||
}
|
||||
|
||||
override fun nextValue(): String {
|
||||
ticksLived++
|
||||
if (ticksLived % ticks == 0) {
|
||||
index++
|
||||
if (index > colors.lastIndex) {
|
||||
index = 0
|
||||
}
|
||||
color = colors[index]
|
||||
}
|
||||
return getValue()
|
||||
override fun nextValue(): String {
|
||||
ticksLived++
|
||||
if (ticksLived % ticks == 0) {
|
||||
index++
|
||||
if (index > colors.lastIndex) {
|
||||
index = 0
|
||||
}
|
||||
color = colors[index]
|
||||
}
|
||||
return getValue()
|
||||
}
|
||||
}
|
||||
+59
-36
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.textanimation.animation
|
||||
|
||||
import net.kyori.adventure.text.format.TextColor
|
||||
@@ -5,46 +28,46 @@ import xyz.jpenilla.announcerplus.textanimation.TextAnimation
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class PulsingColor(colors: List<TextColor>, ticks: Int) : TextAnimation {
|
||||
private var index = 0
|
||||
private var colorIndex = 0
|
||||
private val colors = ArrayList(colors)
|
||||
private var index = 0
|
||||
private var colorIndex = 0
|
||||
private val colors = ArrayList(colors)
|
||||
|
||||
init {
|
||||
this.colors.add(this.colors[0])
|
||||
init {
|
||||
this.colors.add(this.colors[0])
|
||||
}
|
||||
|
||||
private var color = this.colors[0].asHexString()
|
||||
private val factorStep = 1.0f / ticks
|
||||
|
||||
override fun getValue(): String {
|
||||
return color
|
||||
}
|
||||
|
||||
override fun nextValue(): String {
|
||||
color = nextColor().asHexString()
|
||||
return getValue()
|
||||
}
|
||||
|
||||
private fun interpolate(color1: TextColor, color2: TextColor, factor: Float): TextColor {
|
||||
return TextColor.color(
|
||||
(color1.red() + factor * (color2.red() - color1.red())).roundToInt(),
|
||||
(color1.green() + factor * (color2.green() - color1.green())).roundToInt(),
|
||||
(color1.blue() + factor * (color2.blue() - color1.blue())).roundToInt()
|
||||
)
|
||||
}
|
||||
|
||||
private fun nextColor(): TextColor {
|
||||
if (factorStep * index > 1) {
|
||||
colorIndex++
|
||||
index = 0
|
||||
}
|
||||
|
||||
private var color = this.colors[0].asHexString()
|
||||
private val factorStep = 1.0f / ticks
|
||||
val factor = factorStep * index++
|
||||
|
||||
override fun getValue(): String {
|
||||
return color
|
||||
if (colorIndex + 1 > colors.lastIndex) {
|
||||
colorIndex = 0
|
||||
}
|
||||
|
||||
override fun nextValue(): String {
|
||||
color = nextColor().asHexString()
|
||||
return getValue()
|
||||
}
|
||||
|
||||
private fun interpolate(color1: TextColor, color2: TextColor, factor: Float): TextColor {
|
||||
return TextColor.color(
|
||||
(color1.red() + factor * (color2.red() - color1.red())).roundToInt(),
|
||||
(color1.green() + factor * (color2.green() - color1.green())).roundToInt(),
|
||||
(color1.blue() + factor * (color2.blue() - color1.blue())).roundToInt()
|
||||
)
|
||||
}
|
||||
|
||||
private fun nextColor(): TextColor {
|
||||
if (factorStep * index > 1) {
|
||||
colorIndex++
|
||||
index = 0
|
||||
}
|
||||
|
||||
val factor = factorStep * index++
|
||||
|
||||
if (colorIndex + 1 > colors.lastIndex) {
|
||||
colorIndex = 0
|
||||
}
|
||||
|
||||
return interpolate(colors[colorIndex], colors[colorIndex + 1], factor)
|
||||
}
|
||||
return interpolate(colors[colorIndex], colors[colorIndex + 1], factor)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.textanimation.animation
|
||||
|
||||
import net.kyori.adventure.text.format.TextColor
|
||||
@@ -5,42 +28,42 @@ import xyz.jpenilla.announcerplus.textanimation.TextAnimation
|
||||
import kotlin.random.Random
|
||||
|
||||
class RandomColor(type: Type, ticks: Int) : TextAnimation {
|
||||
private var animation = when (type) {
|
||||
Type.FLASH -> {
|
||||
FlashingText(getRandomColors(64).map { color -> color.asHexString() }, ticks)
|
||||
}
|
||||
Type.PULSE -> {
|
||||
PulsingColor(getRandomColors(64), ticks)
|
||||
}
|
||||
private var animation = when (type) {
|
||||
Type.FLASH -> {
|
||||
FlashingText(getRandomColors(64).map { color -> color.asHexString() }, ticks)
|
||||
}
|
||||
|
||||
override fun getValue(): String {
|
||||
return animation.getValue()
|
||||
Type.PULSE -> {
|
||||
PulsingColor(getRandomColors(64), ticks)
|
||||
}
|
||||
}
|
||||
|
||||
override fun nextValue(): String {
|
||||
return animation.nextValue()
|
||||
override fun getValue(): String {
|
||||
return animation.getValue()
|
||||
}
|
||||
|
||||
override fun nextValue(): String {
|
||||
return animation.nextValue()
|
||||
}
|
||||
|
||||
private fun getRandomColor(): TextColor {
|
||||
return TextColor.color(Random.nextInt(256), Random.nextInt(256), Random.nextInt(256))
|
||||
}
|
||||
|
||||
private fun getRandomColors(amount: Int): List<TextColor> {
|
||||
val randomColors = arrayListOf<TextColor>()
|
||||
for (i in 0 until amount) {
|
||||
randomColors.add(getRandomColor())
|
||||
}
|
||||
return randomColors
|
||||
}
|
||||
|
||||
private fun getRandomColor(): TextColor {
|
||||
return TextColor.color(Random.nextInt(256), Random.nextInt(256), Random.nextInt(256))
|
||||
}
|
||||
|
||||
private fun getRandomColors(amount: Int): List<TextColor> {
|
||||
val randomColors = arrayListOf<TextColor>()
|
||||
for (i in 0 until amount) {
|
||||
randomColors.add(getRandomColor())
|
||||
}
|
||||
return randomColors
|
||||
}
|
||||
|
||||
enum class Type {
|
||||
FLASH, PULSE;
|
||||
|
||||
companion object {
|
||||
fun of(text: String): Type {
|
||||
return valueOf(text.toUpperCase())
|
||||
}
|
||||
}
|
||||
enum class Type {
|
||||
FLASH, PULSE;
|
||||
|
||||
companion object {
|
||||
fun of(text: String): Type {
|
||||
return valueOf(text.toUpperCase())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
-13
@@ -1,23 +1,46 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.textanimation.animation
|
||||
|
||||
import xyz.jpenilla.announcerplus.textanimation.TextAnimation
|
||||
|
||||
class ScrollingGradient(private val increment: Float) : TextAnimation {
|
||||
companion object {
|
||||
private val GRADIENT_PHASE_RANGE = -1.0f..1.0f
|
||||
}
|
||||
companion object {
|
||||
private val GRADIENT_PHASE_RANGE = -1.0f..1.0f
|
||||
}
|
||||
|
||||
private var phase = -1f
|
||||
private var phase = -1f
|
||||
|
||||
override fun getValue(): String {
|
||||
return phase.coerceIn(GRADIENT_PHASE_RANGE).toString()
|
||||
}
|
||||
override fun getValue(): String {
|
||||
return phase.coerceIn(GRADIENT_PHASE_RANGE).toString()
|
||||
}
|
||||
|
||||
override fun nextValue(): String {
|
||||
if (phase >= 1f) {
|
||||
phase = -1f
|
||||
}
|
||||
phase += increment
|
||||
return getValue()
|
||||
override fun nextValue(): String {
|
||||
if (phase >= 1f) {
|
||||
phase = -1f
|
||||
}
|
||||
phase += increment
|
||||
return getValue()
|
||||
}
|
||||
}
|
||||
+55
-32
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.textanimation.animation
|
||||
|
||||
import org.bukkit.entity.Player
|
||||
@@ -6,43 +29,43 @@ import xyz.jpenilla.announcerplus.config.ConfigManager
|
||||
import xyz.jpenilla.announcerplus.textanimation.TextAnimation
|
||||
|
||||
class ScrollingText(
|
||||
private val player: Player?,
|
||||
text: String,
|
||||
private val windowSize: Int,
|
||||
private val ticks: Int
|
||||
private val player: Player?,
|
||||
text: String,
|
||||
private val windowSize: Int,
|
||||
private val ticks: Int
|
||||
) : TextAnimation {
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val spaces = getSpaces(windowSize)
|
||||
private val text = "$spaces$text$spaces"
|
||||
private var index = 0
|
||||
private var ticksLived = 0
|
||||
private val configManager: ConfigManager by inject()
|
||||
private val spaces = getSpaces(windowSize)
|
||||
private val text = "$spaces$text$spaces"
|
||||
private var index = 0
|
||||
private var ticksLived = 0
|
||||
|
||||
private fun getSpaces(amount: Int): String {
|
||||
val sb = StringBuilder()
|
||||
for (i in 1..amount) {
|
||||
sb.append(" ")
|
||||
}
|
||||
return sb.toString()
|
||||
private fun getSpaces(amount: Int): String {
|
||||
val sb = StringBuilder()
|
||||
for (i in 1..amount) {
|
||||
sb.append(" ")
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
override fun getValue(): String {
|
||||
return try {
|
||||
configManager.parse(player, text).substring(index, index + windowSize)
|
||||
} catch (e: Exception) {
|
||||
//if the placeholders changed in a way that causes us to out of bounds
|
||||
index = 0
|
||||
configManager.parse(player, text).substring(index, index + windowSize)
|
||||
}
|
||||
override fun getValue(): String {
|
||||
return try {
|
||||
configManager.parse(player, text).substring(index, index + windowSize)
|
||||
} catch (e: Exception) {
|
||||
//if the placeholders changed in a way that causes us to out of bounds
|
||||
index = 0
|
||||
configManager.parse(player, text).substring(index, index + windowSize)
|
||||
}
|
||||
}
|
||||
|
||||
override fun nextValue(): String {
|
||||
ticksLived++
|
||||
if (ticksLived % ticks == 0) {
|
||||
index++
|
||||
if (index > configManager.parse(player, text).length - windowSize) {
|
||||
index = 0
|
||||
}
|
||||
}
|
||||
return getValue()
|
||||
override fun nextValue(): String {
|
||||
ticksLived++
|
||||
if (ticksLived % ticks == 0) {
|
||||
index++
|
||||
if (index > configManager.parse(player, text).length - windowSize) {
|
||||
index = 0
|
||||
}
|
||||
}
|
||||
return getValue()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.textanimation.animation
|
||||
|
||||
import org.bukkit.entity.Player
|
||||
@@ -6,33 +29,33 @@ import xyz.jpenilla.announcerplus.config.ConfigManager
|
||||
import xyz.jpenilla.announcerplus.textanimation.TextAnimation
|
||||
|
||||
class Typewriter(private val player: Player?, private val text: String, private val ticks: Int) : TextAnimation {
|
||||
private val configManager: ConfigManager by inject()
|
||||
private var index = 0
|
||||
private var ticksLived = 0
|
||||
private var showUnderscore = true
|
||||
private val configManager: ConfigManager by inject()
|
||||
private var index = 0
|
||||
private var ticksLived = 0
|
||||
private var showUnderscore = true
|
||||
|
||||
override fun getValue(): String {
|
||||
val s = try {
|
||||
configManager.parse(player, text).substring(0, index)
|
||||
} catch (e: Exception) {
|
||||
//if the placeholders changed in a way that causes us to out of bounds
|
||||
index = 0
|
||||
configManager.parse(player, text).substring(0, index)
|
||||
}
|
||||
return "$s${if (showUnderscore) "_" else " "}"
|
||||
override fun getValue(): String {
|
||||
val s = try {
|
||||
configManager.parse(player, text).substring(0, index)
|
||||
} catch (e: Exception) {
|
||||
//if the placeholders changed in a way that causes us to out of bounds
|
||||
index = 0
|
||||
configManager.parse(player, text).substring(0, index)
|
||||
}
|
||||
return "$s${if (showUnderscore) "_" else " "}"
|
||||
}
|
||||
|
||||
override fun nextValue(): String {
|
||||
ticksLived++
|
||||
if (ticksLived % 5 == 0) {
|
||||
showUnderscore = !showUnderscore
|
||||
}
|
||||
if (ticksLived % ticks == 0) {
|
||||
index++
|
||||
if (index > configManager.parse(player, text).length) {
|
||||
index = 0
|
||||
}
|
||||
}
|
||||
return getValue()
|
||||
override fun nextValue(): String {
|
||||
ticksLived++
|
||||
if (ticksLived % 5 == 0) {
|
||||
showUnderscore = !showUnderscore
|
||||
}
|
||||
if (ticksLived % ticks == 0) {
|
||||
index++
|
||||
if (index > configManager.parse(player, text).length) {
|
||||
index = 0
|
||||
}
|
||||
}
|
||||
return getValue()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.util
|
||||
|
||||
import net.kyori.adventure.text.Component
|
||||
@@ -10,32 +33,32 @@ import net.kyori.adventure.text.format.TextColor.color
|
||||
import net.kyori.adventure.text.format.TextDecoration
|
||||
|
||||
object Constants {
|
||||
const val CONFIG_COMMENT_SOUNDS_LINE2: String =
|
||||
"Separate multiple sounds by commas, i.e. \"minecraft:entity.strider.happy,minecraft:entity.villager.ambient,minecraft:block.note_block.cow_bell\""
|
||||
const val CONFIG_COMMENT_SOUNDS_LINE2: String =
|
||||
"Separate multiple sounds by commas, i.e. \"minecraft:entity.strider.happy,minecraft:entity.villager.ambient,minecraft:block.note_block.cow_bell\""
|
||||
|
||||
const val CONFIG_COMMENT_SOUNDS_RANDOM: String =
|
||||
"Should a random join sound be chosen(true) or should all of them play(false)"
|
||||
const val CONFIG_COMMENT_SOUNDS_RANDOM: String =
|
||||
"Should a random join sound be chosen(true) or should all of them play(false)"
|
||||
|
||||
val CHAT_PREFIX: Component = text()
|
||||
.append(text("[", NamedTextColor.WHITE))
|
||||
.append(text("A", color(0x47EB46)))
|
||||
.append(text("P", color(0x2CF58B)))
|
||||
.append(text("]", NamedTextColor.WHITE))
|
||||
.append(space())
|
||||
.hoverEvent(
|
||||
text()
|
||||
.append(text("Announcer", color(0x47EB46)))
|
||||
.append(text("Plus", color(0x2CF58B), TextDecoration.ITALIC))
|
||||
.append(newline())
|
||||
.append(
|
||||
text(
|
||||
" Click for help",
|
||||
NamedTextColor.GRAY,
|
||||
TextDecoration.ITALIC
|
||||
)
|
||||
)
|
||||
.build()
|
||||
val CHAT_PREFIX: Component = text()
|
||||
.append(text("[", NamedTextColor.WHITE))
|
||||
.append(text("A", color(0x47EB46)))
|
||||
.append(text("P", color(0x2CF58B)))
|
||||
.append(text("]", NamedTextColor.WHITE))
|
||||
.append(space())
|
||||
.hoverEvent(
|
||||
text()
|
||||
.append(text("Announcer", color(0x47EB46)))
|
||||
.append(text("Plus", color(0x2CF58B), TextDecoration.ITALIC))
|
||||
.append(newline())
|
||||
.append(
|
||||
text(
|
||||
" Click for help",
|
||||
NamedTextColor.GRAY,
|
||||
TextDecoration.ITALIC
|
||||
)
|
||||
)
|
||||
.clickEvent(ClickEvent.runCommand("/announcerplus help"))
|
||||
.build()
|
||||
)
|
||||
.clickEvent(ClickEvent.runCommand("/announcerplus help"))
|
||||
.build()
|
||||
}
|
||||
@@ -1,5 +1,29 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.util
|
||||
|
||||
import cloud.commandframework.ArgumentDescription
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.plugin.Plugin
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
@@ -20,10 +44,18 @@ fun Plugin.runAsync(
|
||||
): BukkitTask =
|
||||
Bukkit.getScheduler().runTaskLaterAsynchronously(this, runnable, delay)
|
||||
|
||||
fun Plugin.asyncTimer(delay: Long, interval: Long, runnable: Runnable): BukkitTask =
|
||||
fun Plugin.asyncTimer(
|
||||
delay: Long,
|
||||
interval: Long,
|
||||
runnable: Runnable
|
||||
): BukkitTask =
|
||||
Bukkit.getScheduler().runTaskTimerAsynchronously(this, runnable, delay, interval)
|
||||
|
||||
fun Plugin.syncTimer(delay: Long, interval: Long, runnable: Runnable): BukkitTask =
|
||||
fun Plugin.syncTimer(
|
||||
delay: Long,
|
||||
interval: Long,
|
||||
runnable: Runnable
|
||||
): BukkitTask =
|
||||
Bukkit.getScheduler().runTaskTimer(this, runnable, delay, interval)
|
||||
|
||||
fun <T> Plugin.getOnMain(supplier: () -> T): T {
|
||||
@@ -31,3 +63,15 @@ fun <T> Plugin.getOnMain(supplier: () -> T): T {
|
||||
runSync { future.complete(supplier()) }
|
||||
return future.join()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a [ArgumentDescription], defaulting to [ArgumentDescription.empty]
|
||||
*
|
||||
* @param description description string
|
||||
* @return the description
|
||||
* @since 1.4.0
|
||||
*/
|
||||
fun description(
|
||||
description: String = ""
|
||||
): ArgumentDescription =
|
||||
if (description.isEmpty()) ArgumentDescription.empty() else ArgumentDescription.of(description)
|
||||
@@ -1,3 +1,26 @@
|
||||
/*
|
||||
* This file is part of AnnouncerPlus, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2020-2021 Jason Penilla
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package xyz.jpenilla.announcerplus.util
|
||||
|
||||
import com.google.common.base.Charsets
|
||||
@@ -9,34 +32,34 @@ import java.net.URL
|
||||
import java.util.LinkedList
|
||||
|
||||
class UpdateChecker(private val plugin: AnnouncerPlus, private val githubRepo: String) {
|
||||
private val parser = JsonParser()
|
||||
private val parser = JsonParser()
|
||||
|
||||
fun updateCheck() {
|
||||
plugin.runAsync {
|
||||
val result = try {
|
||||
parser.parse(InputStreamReader(URL("https://api.github.com/repos/$githubRepo/releases").openStream(), Charsets.UTF_8)).asJsonArray
|
||||
} catch (exception: IOException) {
|
||||
plugin.logger.info("Cannot look for updates: " + exception.message)
|
||||
return@runAsync
|
||||
}
|
||||
val versionMap = LinkedHashMap<String, String>()
|
||||
result.forEach { versionMap[it.asJsonObject["tag_name"].asString] = it.asJsonObject["html_url"].asString }
|
||||
val versionList = LinkedList(versionMap.keys)
|
||||
val currentVersion = "v" + plugin.description.version
|
||||
if (versionList[0] == currentVersion) {
|
||||
plugin.logger.info("You are running the latest version of ${plugin.name}! :)")
|
||||
return@runAsync
|
||||
}
|
||||
if (currentVersion.contains("SNAPSHOT")) {
|
||||
plugin.logger.info("You are running a development build of ${plugin.name}! ($currentVersion)")
|
||||
plugin.logger.info("The latest official release is " + versionList[0])
|
||||
return@runAsync
|
||||
}
|
||||
val versionsBehind = versionList.indexOf(currentVersion)
|
||||
plugin.logger.info("There is an update available for ${plugin.name}!")
|
||||
plugin.logger.info("You are running version $currentVersion, which is ${if (versionsBehind == -1) "many" else versionsBehind} versions outdated.")
|
||||
plugin.logger.info("Download the latest version, ${versionList[0]} from GitHub at the link below:")
|
||||
plugin.logger.info(versionMap[versionList[0]])
|
||||
}
|
||||
fun updateCheck() {
|
||||
plugin.runAsync {
|
||||
val result = try {
|
||||
parser.parse(InputStreamReader(URL("https://api.github.com/repos/$githubRepo/releases").openStream(), Charsets.UTF_8)).asJsonArray
|
||||
} catch (exception: IOException) {
|
||||
plugin.logger.info("Cannot look for updates: " + exception.message)
|
||||
return@runAsync
|
||||
}
|
||||
val versionMap = LinkedHashMap<String, String>()
|
||||
result.forEach { versionMap[it.asJsonObject["tag_name"].asString] = it.asJsonObject["html_url"].asString }
|
||||
val versionList = LinkedList(versionMap.keys)
|
||||
val currentVersion = "v" + plugin.description.version
|
||||
if (versionList[0] == currentVersion) {
|
||||
// Up to date, do nothing
|
||||
return@runAsync
|
||||
}
|
||||
if (currentVersion.contains("SNAPSHOT")) {
|
||||
plugin.logger.info("You are running a development build of ${plugin.name}! ($currentVersion)")
|
||||
plugin.logger.info("The latest official release is " + versionList[0])
|
||||
return@runAsync
|
||||
}
|
||||
val versionsBehind = versionList.indexOf(currentVersion)
|
||||
plugin.logger.info("There is an update available for ${plugin.name}!")
|
||||
plugin.logger.info("You are running version $currentVersion, which is ${if (versionsBehind == -1) "many" else versionsBehind} versions outdated.")
|
||||
plugin.logger.info("Download the latest version, ${versionList[0]} from GitHub at the link below:")
|
||||
plugin.logger.info(versionMap[versionList[0]])
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user