Skip to content

Commit 8c45cb6

Browse files
committed
add expectBlocking function
1 parent e09cc5e commit 8c45cb6

File tree

4 files changed

+154
-0
lines changed

4 files changed

+154
-0
lines changed

sample/src/main/kotlin/com/zp4rker/bukkot/sample/SamplePlugin.kt

+25
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.zp4rker.bukkot.sample
22

3+
import com.zp4rker.bukkot.api.BlockingFunction
4+
import com.zp4rker.bukkot.extensions.runTask
35
import com.zp4rker.bukkot.listener.expect
6+
import com.zp4rker.bukkot.listener.expectBlocking
47
import com.zp4rker.bukkot.listener.on
58
import org.bukkit.event.server.ServerCommandEvent
69
import org.bukkit.plugin.java.JavaPlugin
@@ -10,6 +13,7 @@ import java.util.concurrent.TimeUnit
1013
* @author zp4rker
1114
*/
1215
class SamplePlugin : JavaPlugin() {
16+
@OptIn(BlockingFunction::class)
1317
override fun onEnable() {
1418
try {
1519
Class.forName("com.zp4rker.bukkot.Bukkot")
@@ -18,6 +22,7 @@ class SamplePlugin : JavaPlugin() {
1822
server.pluginManager.disablePlugin(this)
1923
return
2024
}
25+
2126
// Inline listener - regular
2227
this.on<ServerCommandEvent> {
2328
logger.info("Console ran: /${it.command}")
@@ -44,5 +49,25 @@ class SamplePlugin : JavaPlugin() {
4449
}) {
4550
logger.info("You should see this if console issues a command within 10 seconds")
4651
}
52+
53+
// Inline listener - expectBlocking
54+
this.runTask(async = true) {
55+
logger.info("This is part 1")
56+
this@SamplePlugin.expectBlocking<ServerCommandEvent> {
57+
logger.info("This is part 2")
58+
}
59+
logger.info("This is part 3")
60+
}
61+
62+
// Inline listener - expectBlocking #2
63+
this.runTask(async = true) {
64+
logger.info("This is part 1 of 3")
65+
this@SamplePlugin.expectBlocking<ServerCommandEvent>(timeout = TimeUnit.SECONDS.toMillis(10), timeoutAction = {
66+
logger.info("This is part 2 of 3 - but as a timeout")
67+
}) {
68+
logger.info("This is part 2 of 3")
69+
}
70+
logger.info("This is part 3 of 3")
71+
}
4772
}
4873
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.zp4rker.bukkot.api
2+
3+
@RequiresOptIn("This function is blocking and should ideally be run in an async task")
4+
@Retention(AnnotationRetention.BINARY)
5+
@Target(AnnotationTarget.FUNCTION)
6+
annotation class BlockingFunction

src/main/kotlin/com/zp4rker/bukkot/listener/Inline.kt

+50
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.zp4rker.bukkot.listener
22

3+
import com.zp4rker.bukkot.api.BlockingFunction
34
import com.zp4rker.bukkot.extensions.unregister
5+
import kotlinx.coroutines.channels.Channel
6+
import kotlinx.coroutines.runBlocking
47
import org.bukkit.event.Event
58
import org.bukkit.event.EventPriority
69
import org.bukkit.plugin.Plugin
@@ -73,3 +76,50 @@ inline fun <reified T : Event> Plugin.expect(
7376
listener.register(this, priority, ignoreCancelled)
7477
}
7578

79+
/**
80+
* Register a limited listener which blocks the current thread
81+
*
82+
* Blocks until all calls are made or the listener times out
83+
*
84+
* @param T the event to listen to
85+
*
86+
* @see expect
87+
*/
88+
@BlockingFunction
89+
inline fun <reified T : Event> Plugin.expectBlocking(
90+
crossinline predicate: Predicate<T> = { true },
91+
amount: Int = 1,
92+
timeout: Long = 0,
93+
crossinline timeoutAction: () -> Unit = {},
94+
priority: EventPriority = EventPriority.NORMAL,
95+
ignoreCancelled: Boolean = false,
96+
crossinline action: AnonymousListener<T>.(T) -> Unit
97+
) {
98+
val channel = Channel<Boolean?>(1)
99+
100+
var calls = 0
101+
val listener = listener {
102+
if (predicate(it)) {
103+
action(it)
104+
if (++calls >= amount) {
105+
unregister()
106+
runBlocking { channel.send(null) }
107+
}
108+
}
109+
}
110+
111+
if (timeout > 0) {
112+
scheduler.schedule({
113+
if (calls < amount) {
114+
timeoutAction()
115+
listener.unregister()
116+
runBlocking { channel.send(null) }
117+
}
118+
}, timeout, TimeUnit.MILLISECONDS)
119+
}
120+
121+
listener.register(this, priority, ignoreCancelled)
122+
123+
runBlocking { channel.receive() }
124+
}
125+

src/main/kotlin/com/zp4rker/bukkot/listener/Specifics.kt

+73
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.zp4rker.bukkot.listener
22

3+
import com.zp4rker.bukkot.api.BlockingFunction
34
import org.bukkit.block.Block
45
import org.bukkit.entity.Entity
56
import org.bukkit.entity.Player
@@ -50,6 +51,30 @@ inline fun <reified T : EntityEvent> Entity.expect(
5051
}, amount, timeout, timeoutAction, priority, ignoreCancelled, action)
5152
}
5253

54+
/**
55+
* Registers limited listener which blocks the current thread where this entity is the subject
56+
*
57+
* Blocks until all calls are made or the listener times out
58+
*
59+
* @see org.bukkit.plugin.Plugin.expectBlocking
60+
*/
61+
@BlockingFunction
62+
inline fun <reified T : EntityEvent> Entity.expectBlocking(
63+
plugin: JavaPlugin,
64+
crossinline predicate: Predicate<T> = { true },
65+
amount: Int = 1,
66+
timeout: Long = 0,
67+
crossinline timeoutAction: () -> Unit = {},
68+
priority: EventPriority = EventPriority.NORMAL,
69+
ignoreCancelled: Boolean = false,
70+
crossinline action: AnonymousListener<T>.(T) -> Unit
71+
) {
72+
plugin.expectBlocking<T>({
73+
if (it.entity.uniqueId == this.uniqueId) predicate(it)
74+
else false
75+
}, amount, timeout, timeoutAction, priority, ignoreCancelled, action)
76+
}
77+
5378
/**
5479
* Registers continuous listener where this player is the subject
5580
*
@@ -91,6 +116,30 @@ inline fun <reified T : PlayerEvent> Player.expect(
91116
}, amount, timeout, timeoutAction, priority, ignoreCancelled, action)
92117
}
93118

119+
/**
120+
* Registers limited listener which blocks the current thread where this player is the subject
121+
*
122+
* Blocks until all calls are made or the listener times out
123+
*
124+
* @see org.bukkit.plugin.Plugin.expectBlocking
125+
*/
126+
@BlockingFunction
127+
inline fun <reified T : PlayerEvent> Player.expectBlocking(
128+
plugin: JavaPlugin,
129+
crossinline predicate: Predicate<T> = { true },
130+
amount: Int = 1,
131+
timeout: Long = 0,
132+
crossinline timeoutAction: () -> Unit = {},
133+
priority: EventPriority = EventPriority.NORMAL,
134+
ignoreCancelled: Boolean = false,
135+
crossinline action: AnonymousListener<T>.(T) -> Unit
136+
) {
137+
plugin.expectBlocking<T>({
138+
if (it.player.uniqueId == this.uniqueId) predicate(it)
139+
else false
140+
}, amount, timeout, timeoutAction, priority, ignoreCancelled, action)
141+
}
142+
94143
/**
95144
* Registers continuous listener where this block is the subject
96145
*
@@ -130,4 +179,28 @@ inline fun <reified T : BlockEvent> Block.expect(
130179
if (it.block.location == this.location && it.block.blockData.asString == this.blockData.asString) predicate(it)
131180
else false
132181
}, amount, timeout, timeoutAction, priority, ignoreCancelled, action)
182+
}
183+
184+
/**
185+
* Registers limited listener which blocks the current thread where this block is the subject
186+
*
187+
* Blocks until all calls are made or the listener times out
188+
*
189+
* @see org.bukkit.plugin.Plugin.expectBlocking
190+
*/
191+
@BlockingFunction
192+
inline fun <reified T : BlockEvent> Block.expectBlocking(
193+
plugin: JavaPlugin,
194+
crossinline predicate: Predicate<T> = { true },
195+
amount: Int = 1,
196+
timeout: Long = 0,
197+
crossinline timeoutAction: () -> Unit = {},
198+
priority: EventPriority = EventPriority.NORMAL,
199+
ignoreCancelled: Boolean = false,
200+
crossinline action: AnonymousListener<T>.(T) -> Unit
201+
) {
202+
plugin.expectBlocking<T>({
203+
if (it.block.location == this.location && it.block.blockData.asString == this.blockData.asString) predicate(it)
204+
else false
205+
}, amount, timeout, timeoutAction, priority, ignoreCancelled, action)
133206
}

0 commit comments

Comments
 (0)