Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@

## [Unreleased]
### Added
- GH-3: Title type announcement sender (@tajobe)
- MIT license

### Changed
- MC 1.21, Java 21, Kotlin 2.1
- **BREAKING**: New config format

### Fixed
- Config Auto-reload is now a repeating task as intended
- Config actually created on first run
- Copy updated default header when config is updated

### Removed
- Offline variant is now the default jar, no longer producing an "online" version
- debugMode option: log levels are controlled by the server's log4j configuration

## [1.0.0] - 2020-02-10
### Added
- CHANGELOG
Expand Down
143 changes: 84 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ Messages can be sent server-wide or controlled by permissions after a delay and

## Features

- Timed server-wide announcements/news messages
- Timed server-wide announcements/news messages sent as either a chat message, boss bar, or title/subtitle
- Easily configurable
- Configure one-time or repeating messages
- Configure one-time (per reload) or repeating/rotating messages
- Extensive Permissions support - configure messages to only send to users including or excluding certain permission nodes
- Optional debug mode to track down who is/isn't receiving messages and why
- Automatic config reloading to get new messages
Expand All @@ -17,66 +17,91 @@ Messages can be sent server-wide or controlled by permissions after a delay and

## Configuration

Format:
```yaml
config-version(int): **DO NOT EDIT**, used to migrate configurations as the format changes
auto-reloadconfig(int): <Time in minutes to check/reload config for message updates(0 for off)>
NOTE: When config is reloaded, will reset delays for messages and cause one-time messages to resend
debug-mode(boolean): <Should we pring debug to server.log(true/false)?>
NOTE: Look for fine and finer level log messages in server.log
announcements: Add announcements below to this section
<message label>(String, must be unique):
message(String, required) OR messages(String list, see sample config): <Message to send>
random-order(boolean, optional): <if list of messages should be sent in random order>
sender(String, optional): <Message Sender(chat or boss, default: chat)>
bar(section, optional):
hold(int, optional): <Time in sections for bar to be displayed on announce>
color(String, optional): <bar color(https://hub.spigotmc.org/javadocs/spigot/org/bukkit/boss/BarColor.html)>
style(String, optional): <bar style(https://hub.spigotmc.org/javadocs/spigot/org/bukkit/boss/BarStyle.html)>
animate(section, optional):
enable(boolean, optional): <if bar should animate hold time>
reverse(boolean, optional): <if animation should be reversed>
delay(int, optional - default 0): <Delay to send message on in seconds>
repeat(int, optional): <time between repeat sendings of the message in seconds>
includesperms(String list, optional):
- <only send to those with this perm>
- <and this one>
excludesperms(String list, optional):
- <don't send to those with this perm>
- <and this one>
```
**Note**: For permissions, includes are applied first, then excludes are taken out
- `autoReload`(duration*, optional): Time between automatically reloading plugin configuration, unset or `0m` for off
- `announcements`(Announcement list): list of announcement configurations, see below for detail
- General announcement configuration:
- `type`(Announcement type): Type of announcement: `Chat`, `Title`, or `Boss`
- `messages` OR `message`(Message list): Message(s) to send, depends on type (see sample and description below)
- `random`(boolean, optional): if list of messages should be sent in random order
- `delay`(duration*, optional - default 0): Delay after loading to send message
- `repeat`(duration*, optional): time between sending/repeating each message
- `includesPermissions`**(String list, optional): Only send announcement to players with these permissions
- `excludesPermissions`**(String list, optional): Exclude players with these permissions from receiving the announcement
- `<additional options depending on announcement type>`
- `Chat` type announcement:
- `messages`(String list): Message(s) to send
- `Boss` type announcement:
- `hold`(duration*): Time for boss bar to be on screen
- `color`(BarColor): Color of bar, one of PINK, BLUE, RED, GREEN, YELLOW, PURPLE, WHITE
- `style`(BarStyle): Style of bar, one of SOLID, SEGMENTED_6, SEGMENTED_10, SEGMENTED_12, SEGMENTED_20
- `animate`(boolean): if bar should animate over hold time
- `reverseAnimation`(boolean): if animation should be reversed
- `messages`(BossBarMessage list):
- `message`(string): message string
- ...boss bar config overrides per message eg hold, color, style, animate, etc...
- `Title` type announcement:
- `fadeIn`(duration*): Time it takes for title to fade in
- `stay`(duration*): Time for title to stay on screen
- `fadeOut`(duration*): Time it takes for title to fade out
- `messages`(TitleMessage list):
- `title`(string): title string
- `subtitle`(string): subtitle string, appears below title slightly smaller
- ...title config overrides eg fadeIn, stay, fadeOut...
- `config-version`: **Internal use for configuration migrations, do not edit**

<sub>
*Durations are in the form '10s', '5m', '1h', or ISO-8601 duration. See [parse](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.time/-duration/-companion/parse.html).

**For permissions, includes are applied first, then excludes are taken out
</sub>


### Example

```yaml
config-version: 1
auto-reloadconfig: 20
debug-mode: false
autoReload: 10m
announcements:
repeating-example:
messages:
- This is an automatically generated repeating message!
delay: 15
repeat: 60
permissions-example:
messages:
- This is another automatically generated repeating message for people with build permission!
delay: 30
repeat: 60
includesperms:
- permissions.build
one-time-example:
messages:
- This is an automatically generated one-time message!
delay: 45
message-group-example:
messages:
- This is an automatically generated sequential message group (1 of 3)!
- This is an automatically generated sequential message group (2 of 3)!
- This is an automatically generated sequential message group (3 of 3)!
delay: 30
repeat: 30
sender: bossbar
random-order: false
- type: Chat
delay: 30s
repeat: 2m
includesPermissions:
- permissions.build
- another.permission
excludesPermissions:
- permissions.admin
messages:
- hello
- world
- type: Chat
repeat: 1m 40s
messages:
- abc
- xyz
- type: Title
repeat: 30s
messages:
- title: Title!
subtitle: Subtitle!
- title: Title only custom durations
fadeIn: 100ms
stay: 10s
fadeOut: 1s
fadeIn: 500ms
stay: 5s
fadeOut: 500ms
- type: Boss
random: true
repeat: 15s
messages:
- message: eyy
- message: custom bar config
hold: 10s
color: GREEN
style: SEGMENTED_20
reverseAnimation: true
hold: 5s
color: PURPLE
style: SOLID
animate: true
config-version: 1
```
36 changes: 28 additions & 8 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,17 @@ kotlin {
jvmToolchain(21)
}

val shadowJarOnly: Boolean = project.property("shadowJarOnly")?.toString()?.toBoolean() ?: false
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't anticipate this being something that gets toggled on and off in this plugin, but I wanted this to be something I could move into the template (which actually should in part be a Gradle plugin...)

val runtimeClasspath by configurations.runtimeClasspath

dependencies {
compileOnly(libs.spigot)
implementation(libs.kotlinLogger)
implementation(libs.jacksonKotlin)
implementation(libs.jacksonDataformatYaml)
implementation(kotlin("stdlib"))

testImplementation(libs.spigot)
}

tasks {
Expand All @@ -70,8 +78,10 @@ tasks {
}

processResources {
// inject runtime libraries into online plugin variant
val libraries = configurations.runtimeClasspath.get().resolvedConfiguration.resolvedArtifacts
inputs.property("shadowJarOnly", shadowJarOnly)

// inject "online" libraries into online plugin variant
val libraries = runtimeClasspath.resolvedConfiguration.resolvedArtifacts
.joinToString("\n - ", prefix = "\n - ") { artifact ->
val id = artifact.moduleVersion.id
"${id.group}:${id.name}:${id.version}"
Expand Down Expand Up @@ -102,19 +112,29 @@ tasks {
}
}

jar {
exclude("offline-plugin.yml")
}

// offline jar should be ready to go with all dependencies
shadowJar {
minimize()
archiveClassifier.set("offline")
mergeServiceFiles()
minimize {
// if present, kotlin-reflect must be excluded from minimization
exclude(dependency("org.jetbrains.kotlin:kotlin-reflect"))
}
archiveClassifier.set(if (shadowJarOnly) "" else "offline")
exclude("plugin.yml")
rename("offline-plugin.yml", "plugin.yml")

// avoid classpath conflicts/pollution via relocation
isEnableRelocation = true
relocationPrefix = "${project.group}.${project.name.lowercase()}.libraries"

// if using reflection, don't relocate kotlin:
// shadow relocation doesn't relocate certain metadata breaking some synthetic classes in the case of reflection (used by jackson, for example)
// see also: https://github.com/JetBrains/Exposed/issues/1353
if (runtimeClasspath.resolvedConfiguration.resolvedArtifacts.any { it.name == "kotlin-reflect" }) {
logger.warn("Detected kotlin-reflect in runtime classpath, not relocating kotlin! Proceed with caution.")
relocate("kotlin", "kotlin")
}
}

build { dependsOn(shadowJar) }
}
2 changes: 2 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
kotlin.code.style=official
# only produce an "offline" jar due to classpath challenges with jackson and reflection
shadowJarOnly=true
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[versions]
axionRelease = "1.18.18"
jackson = "2.19.0"
kotlin = "2.1.21"
kotlinLogger = "7.0.7"
ktlintGradle = "12.2.0"
Expand All @@ -14,5 +15,7 @@ ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlintGradle"}
shadow = { id = "com.gradleup.shadow", version.ref = "shadow"}

[libraries]
jacksonKotlin = { group = "com.fasterxml.jackson.module", name = "jackson-module-kotlin", version.ref = "jackson" }
jacksonDataformatYaml = { group = "com.fasterxml.jackson.dataformat", name = "jackson-dataformat-yaml", version.ref = "jackson" }
kotlinLogger = { group = "io.github.oshai", name = "kotlin-logging", version.ref = "kotlinLogger" }
spigot = { group = "org.spigotmc", name = "spigot-api", version.ref = "spigot" }
3 changes: 3 additions & 0 deletions src/main/kotlin/org/simplemc/simpleannounce/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.simplemc.simpleannounce
import org.bukkit.configuration.ConfigurationSection
import org.bukkit.configuration.file.FileConfigurationOptions
import org.bukkit.configuration.file.YamlConfiguration
import kotlin.time.Duration

fun String.oneOf(ignoreCase: Boolean, vararg values: String): Boolean =
values.any { it.equals(this, ignoreCase = ignoreCase) }
Expand All @@ -11,6 +12,8 @@ fun String.oneOf(vararg values: String): Boolean = oneOf(false, *values)

fun String.oneOfIgnoreCase(vararg values: String): Boolean = oneOf(true, *values)

val Duration.inTicks: Long get() = this.inWholeMilliseconds / 50

/**
* Get a string list if and only if it exists in the config (ignoring defaults).
* If the path does not exist, returns empty list
Expand Down
Loading