Skip to content

Commit 727111e

Browse files
authored
GH-4: Introduce sound support (#13)
* GH-4: Introduce sound support * Update README and config description
1 parent bdf0d86 commit 727111e

File tree

8 files changed

+146
-90
lines changed

8 files changed

+146
-90
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## [Unreleased]
44
### Added
5+
- GH-4: Sound support (@tajobe)
56
- GH-3: Title type announcement sender (@tajobe)
67
- MIT license
78

@@ -13,6 +14,7 @@
1314
- Config Auto-reload is now a repeating task as intended
1415
- Config actually created on first run
1516
- Copy updated default header when config is updated
17+
- Chat sender advancing the current message per player
1618

1719
### Removed
1820
- Offline variant is now the default jar, no longer producing an "online" version

README.md

Lines changed: 64 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,26 @@ Messages can be sent server-wide or controlled by permissions after a delay and
2525
- `random`(boolean, optional): if list of messages should be sent in random order
2626
- `delay`(duration*, optional - default 0): Delay after loading to send message
2727
- `repeat`(duration*, optional): time between sending/repeating each message
28+
- `sound`(SoundConfig, optional):
29+
- `sound`([Sound]): Sound to send with announcement
30+
- `volume`(float, optional): Volume of sound to send between 0 and 1, default 1
31+
- `pitch`(float, optional): Pitch of sound to send between 0.5 and 2, default 1
2832
- `includesPermissions`**(String list, optional): Only send announcement to players with these permissions
2933
- `excludesPermissions`**(String list, optional): Exclude players with these permissions from receiving the announcement
30-
- `<additional options depending on announcement type>`
34+
- ...additional options depending on announcement type
3135
- `Chat` type announcement:
32-
- `messages`(String list): Message(s) to send
36+
- `messages`(ChatMessage list): Message(s) to send
37+
- `message`(string): message string
38+
- `sound`(SoundConfig, optional): Override announcement SoundConfig
3339
- `Boss` type announcement:
3440
- `hold`(duration*): Time for boss bar to be on screen
35-
- `color`(BarColor): Color of bar, one of PINK, BLUE, RED, GREEN, YELLOW, PURPLE, WHITE
36-
- `style`(BarStyle): Style of bar, one of SOLID, SEGMENTED_6, SEGMENTED_10, SEGMENTED_12, SEGMENTED_20
41+
- `color`([BarColor]): Color of bar, one of PINK, BLUE, RED, GREEN, YELLOW, PURPLE, WHITE
42+
- `style`([BarStyle]): Style of bar, one of SOLID, SEGMENTED_6, SEGMENTED_10, SEGMENTED_12, SEGMENTED_20
3743
- `animate`(boolean): if bar should animate over hold time
3844
- `reverseAnimation`(boolean): if animation should be reversed
3945
- `messages`(BossBarMessage list):
4046
- `message`(string): message string
47+
- `sound`(SoundConfig, optional): Override announcement SoundConfig
4148
- ...boss bar config overrides per message eg hold, color, style, animate, etc...
4249
- `Title` type announcement:
4350
- `fadeIn`(duration*): Time it takes for title to fade in
@@ -46,6 +53,7 @@ Messages can be sent server-wide or controlled by permissions after a delay and
4653
- `messages`(TitleMessage list):
4754
- `title`(string): title string
4855
- `subtitle`(string): subtitle string, appears below title slightly smaller
56+
- `sound`(SoundConfig, optional): Override announcement SoundConfig
4957
- ...title config overrides eg fadeIn, stay, fadeOut...
5058
- `config-version`: **Internal use for configuration migrations, do not edit**
5159

@@ -61,47 +69,57 @@ Messages can be sent server-wide or controlled by permissions after a delay and
6169
```yaml
6270
autoReload: 10m
6371
announcements:
64-
- type: Chat
65-
delay: 30s
66-
repeat: 2m
67-
includesPermissions:
68-
- permissions.build
69-
- another.permission
70-
excludesPermissions:
71-
- permissions.admin
72-
messages:
73-
- hello
74-
- world
75-
- type: Chat
76-
repeat: 1m 40s
77-
messages:
78-
- abc
79-
- xyz
80-
- type: Title
81-
repeat: 30s
82-
messages:
83-
- title: Title!
84-
subtitle: Subtitle!
85-
- title: Title only custom durations
86-
fadeIn: 100ms
87-
stay: 10s
88-
fadeOut: 1s
89-
fadeIn: 500ms
90-
stay: 5s
91-
fadeOut: 500ms
92-
- type: Boss
93-
random: true
94-
repeat: 15s
95-
messages:
96-
- message: eyy
97-
- message: custom bar config
98-
hold: 10s
99-
color: GREEN
100-
style: SEGMENTED_20
101-
reverseAnimation: true
102-
hold: 5s
103-
color: PURPLE
104-
style: SOLID
105-
animate: true
72+
- type: Chat
73+
delay: 30s
74+
repeat: 2m
75+
includesPermissions:
76+
- permissions.build
77+
- another.permission
78+
excludesPermissions:
79+
- permissions.admin
80+
messages:
81+
- message: hello
82+
- message: world
83+
- type: Chat
84+
repeat: 1m 40s
85+
sound:
86+
sound: AMBIENT_CAVE
87+
volume: .5
88+
pitch: 2
89+
messages:
90+
- message: abc
91+
sound:
92+
sound: BLOCK_ENCHANTMENT_TABLE_USE
93+
- message: xyz
94+
- type: Title
95+
repeat: 30s
96+
messages:
97+
- title: Title!
98+
subtitle: Subtitle!
99+
- title: Title only custom durations
100+
fadeIn: 100ms
101+
stay: 10s
102+
fadeOut: 1s
103+
fadeIn: 500ms
104+
stay: 5s
105+
fadeOut: 500ms
106+
- type: Boss
107+
random: true
108+
repeat: 15s
109+
messages:
110+
- message: eyy
111+
- message: custom bar config
112+
hold: 10s
113+
color: GREEN
114+
style: SEGMENTED_20
115+
reverseAnimation: true
116+
hold: 5s
117+
color: PURPLE
118+
style: SOLID
119+
animate: true
106120
config-version: 1
107121
```
122+
123+
[Sound]: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Sound.html
124+
[BarColor]: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/boss/BarColor.html
125+
[BarStyle]: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/boss/BarStyle.html

src/main/kotlin/org/simplemc/simpleannounce/config/SimpleAnnounceConfig.kt

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import com.fasterxml.jackson.annotation.JsonAlias
44
import com.fasterxml.jackson.annotation.JsonIgnore
55
import com.fasterxml.jackson.annotation.JsonTypeInfo
66
import com.fasterxml.jackson.annotation.JsonUnwrapped
7+
import org.bukkit.Sound
78
import org.bukkit.boss.BarColor
89
import org.bukkit.boss.BarStyle
10+
import org.simplemc.simpleannounce.config.SimpleAnnounceConfig.AnnouncementConfig.Chat.ChatMessage
911
import org.simplemc.simpleannounce.inTicks
1012
import kotlin.time.Duration
1113
import kotlin.time.Duration.Companion.milliseconds
@@ -16,8 +18,8 @@ data class SimpleAnnounceConfig(
1618
val announcements: List<AnnouncementConfig<*>>,
1719
) {
1820
companion object {
19-
private fun Duration?.checkNullZeroOrPositive(name: String) {
20-
check(this == null || this == Duration.Companion.ZERO || this.isPositive()) {
21+
private fun Duration?.requireNullZeroOrPositive(name: String) {
22+
require(this == null || this == Duration.Companion.ZERO || this.isPositive()) {
2123
"When set, $name must be >= 0s"
2224
}
2325
}
@@ -27,53 +29,63 @@ data class SimpleAnnounceConfig(
2729
val autoReloadTicks = autoReload?.inTicks
2830

2931
init {
30-
check(autoReload == null || autoReload == Duration.Companion.ZERO || autoReload.inWholeMinutes >= 1) {
32+
require(autoReload == null || autoReload == Duration.Companion.ZERO || autoReload.inWholeMinutes >= 1) {
3133
"When set, Auto Reload Duration must be > 1 minute"
3234
}
3335
}
3436

3537
@JsonTypeInfo(use = JsonTypeInfo.Id.SIMPLE_NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
36-
sealed class AnnouncementConfig<T> {
38+
sealed class AnnouncementConfig<T : AnnouncementConfig.Message> {
3739
abstract val random: Boolean
3840
abstract val delay: Duration
3941
abstract val repeat: Duration?
42+
abstract val sound: SoundConfig?
4043
abstract val includesPermissions: List<String>
4144
abstract val excludesPermissions: List<String>
4245
abstract val messages: List<T>
4346

47+
interface Message {
48+
val sound: SoundConfig?
49+
}
50+
4451
@JsonIgnore
4552
val delayTicks = delay.inTicks.toInt()
4653

4754
@JsonIgnore
4855
val repeatTicks = repeat?.inTicks?.toInt()
4956

5057
init {
51-
delay.checkNullZeroOrPositive("delay")
52-
repeat.checkNullZeroOrPositive("repeat")
58+
delay.requireNullZeroOrPositive("delay")
59+
repeat.requireNullZeroOrPositive("repeat")
5360
}
5461

5562
data class Chat(
5663
override val random: Boolean = false,
5764
override val delay: Duration = Duration.Companion.ZERO,
5865
override val repeat: Duration? = null,
66+
override val sound: SoundConfig? = null,
5967
override val includesPermissions: List<String> = emptyList(),
6068
override val excludesPermissions: List<String> = emptyList(),
61-
@field:JsonAlias("message") override val messages: List<String>,
62-
) : AnnouncementConfig<String>()
69+
@field:JsonAlias("message") override val messages: List<ChatMessage>,
70+
) : AnnouncementConfig<ChatMessage>() {
71+
data class ChatMessage(val message: String, override val sound: SoundConfig? = null) : Message
72+
}
6373

6474
data class Boss(
6575
override val random: Boolean = false,
6676
override val delay: Duration = Duration.Companion.ZERO,
6777
override val repeat: Duration? = null,
78+
override val sound: SoundConfig? = null,
6879
override val includesPermissions: List<String> = emptyList(),
6980
override val excludesPermissions: List<String> = emptyList(),
7081
@field:JsonAlias("message") override val messages: List<BossBarMessage>,
7182
@field:JsonUnwrapped val barConfig: BarConfig = BarConfig(),
7283
) : AnnouncementConfig<Boss.BossBarMessage>() {
7384
data class BossBarMessage(
7485
val message: String,
86+
override val sound: SoundConfig? = null,
7587
@field:JsonUnwrapped val barConfig: BarConfig? = null,
76-
) {
88+
) : Message {
7789
init {
7890
require(message.length <= 64) { "Boss Bar text must be <= 64 characters" }
7991
}
@@ -90,7 +102,7 @@ data class SimpleAnnounceConfig(
90102
val holdTicks = hold.inTicks
91103

92104
init {
93-
hold.checkNullZeroOrPositive("hold")
105+
hold.requireNullZeroOrPositive("hold")
94106
}
95107
}
96108
}
@@ -99,6 +111,7 @@ data class SimpleAnnounceConfig(
99111
override val random: Boolean = false,
100112
override val delay: Duration = Duration.Companion.ZERO,
101113
override val repeat: Duration? = null,
114+
override val sound: SoundConfig? = null,
102115
override val includesPermissions: List<String> = emptyList(),
103116
override val excludesPermissions: List<String> = emptyList(),
104117
@field:JsonAlias("message") override val messages: List<TitleMessage>,
@@ -107,8 +120,9 @@ data class SimpleAnnounceConfig(
107120
data class TitleMessage(
108121
val title: String,
109122
val subtitle: String? = null,
123+
override val sound: SoundConfig? = null,
110124
@field:JsonUnwrapped val titleConfig: TitleConfig? = null,
111-
)
125+
) : Message
112126

113127
data class TitleConfig(
114128
val fadeIn: Duration = 500.milliseconds,
@@ -125,11 +139,18 @@ data class SimpleAnnounceConfig(
125139
val fadeOutTicks = fadeOut.inTicks.toInt()
126140

127141
init {
128-
fadeIn.checkNullZeroOrPositive("fadeIn")
129-
stay.checkNullZeroOrPositive("stay")
130-
fadeOut.checkNullZeroOrPositive("fadeOut")
142+
fadeIn.requireNullZeroOrPositive("fadeIn")
143+
stay.requireNullZeroOrPositive("stay")
144+
fadeOut.requireNullZeroOrPositive("fadeOut")
131145
}
132146
}
133147
}
148+
149+
data class SoundConfig(val sound: Sound, val volume: Float = 1F, val pitch: Float = 1F) {
150+
init {
151+
require(volume >= 0 && volume <= 1) { "Sound volume must be between 0 and 1" }
152+
require(pitch >= 0.5 && pitch <= 2) { "Sound pitch must be between 0.5 and 2" }
153+
}
154+
}
134155
}
135156
}

src/main/kotlin/org/simplemc/simpleannounce/sender/AnnouncementSender.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import io.github.oshai.kotlinlogging.KotlinLogging
44
import org.bukkit.Bukkit
55
import org.bukkit.entity.Player
66
import org.bukkit.plugin.Plugin
7-
import org.simplemc.simpleannounce.config.SimpleAnnounceConfig
7+
import org.simplemc.simpleannounce.config.SimpleAnnounceConfig.AnnouncementConfig
88
import org.simplemc.simpleannounce.inTicks
99
import java.util.concurrent.atomic.AtomicInteger
1010
import kotlin.random.Random
1111

1212
private val logger = KotlinLogging.logger("SimpleAnnounce AnnouncementSender")
1313

14-
abstract class AnnouncementSender<MessageType, ConfigType : SimpleAnnounceConfig.AnnouncementConfig<MessageType>>(
14+
abstract class AnnouncementSender<MessageType : AnnouncementConfig.Message, ConfigType : AnnouncementConfig<MessageType>>(
1515
internal val plugin: Plugin,
1616
internal val announcement: ConfigType,
1717
) : Runnable {
@@ -36,7 +36,15 @@ abstract class AnnouncementSender<MessageType, ConfigType : SimpleAnnounceConfig
3636
return hasAllRequiredPermissions && hasNoExcludedPermissions
3737
}
3838

39-
internal fun getNextAnnouncement(): MessageType = when {
39+
internal fun send(message: MessageType, messageAction: (Player) -> Unit) {
40+
val sound = message.sound ?: announcement.sound
41+
Bukkit.getOnlinePlayers().filterNotNull().filter(this::shouldSendTo).forEach {
42+
messageAction(it)
43+
sound?.let { sound -> it.playSound(it.location, sound.sound, sound.volume, sound.pitch) }
44+
}
45+
}
46+
47+
internal fun getNextMessage(): MessageType = when {
4048
announcement.messages.size == 1 -> announcement.messages[0]
4149
announcement.random -> announcement.messages[Random.nextInt(announcement.messages.size)]
4250
else -> {

src/main/kotlin/org/simplemc/simpleannounce/sender/BossBarSender.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ class BossBarSender(
1111
announcement: Boss,
1212
) : AnnouncementSender<Boss.BossBarMessage, Boss>(plugin, announcement) {
1313
override fun run() {
14-
val message = getNextAnnouncement()
14+
val message = getNextMessage()
1515
val barConfig = message.barConfig ?: announcement.barConfig
1616

1717
// create the bar
1818
val bar = Bukkit.createBossBar(message.message, barConfig.color, barConfig.style)
1919
bar.progress = if (barConfig.reverseAnimation) 1.0 else 0.0
2020

2121
// show bar to players
22-
Bukkit.getOnlinePlayers().filterNotNull().filter(this::shouldSendTo).forEach(bar::addPlayer)
22+
send(message, bar::addPlayer)
2323
bar.isVisible = true
2424

2525
// set up animation
Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
package org.simplemc.simpleannounce.sender
22

3-
import org.bukkit.Bukkit
43
import org.bukkit.plugin.Plugin
54
import org.simplemc.simpleannounce.config.SimpleAnnounceConfig.AnnouncementConfig.Chat
65

76
class ChatSender(
87
plugin: Plugin,
98
announcement: Chat,
10-
) : AnnouncementSender<String, Chat>(plugin, announcement) {
9+
) : AnnouncementSender<Chat.ChatMessage, Chat>(plugin, announcement) {
1110
override fun run() {
12-
Bukkit.getOnlinePlayers()
13-
.filterNotNull()
14-
.filter(this::shouldSendTo)
15-
.forEach { it.sendMessage(getNextAnnouncement()) }
11+
val message = getNextMessage()
12+
send(message) { it.sendMessage(message.message) }
1613
}
1714
}

0 commit comments

Comments
 (0)