Created
September 2, 2020 07:39
-
-
Save abueide/12999bae4f7ed33047a69d2429702b5c to your computer and use it in GitHub Desktop.
pubsub system
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.abysl.gdxcrawler.ecs.events | |
import com.abysl.gdxcrawler.ecs.events.input.MoveEvent | |
import java.util.* | |
class EventManager { | |
// has to be public because of inline fun, would rather be private | |
// Have to do a MutableList<Any>, then do unsafe cast later. Couldn't think of another way to do it | |
val subscriptions: MutableMap<Class<out Event>, MutableList<Any>> = mutableMapOf() | |
private val events: Queue<Event> = LinkedList() | |
// don't really understand inline and reified, intellij just told me I need it, otherwise error | |
inline fun <reified T: Event> subscribe(noinline subscriber: (T) -> Unit) { | |
val event = T::class.java | |
if(subscriptions[event] == null){ | |
subscriptions[event] = mutableListOf() | |
} | |
subscriptions[event]!!.add(subscriber) | |
} | |
fun publish(event: Event){ | |
events.add(event) | |
} | |
private fun <T: Event> processEvent(event: T){ | |
subscriptions[event.javaClass]?.forEach { | |
(it as ((T) -> Unit)).invoke(event) | |
} | |
} | |
// Clear out the event queue | |
fun process(){ | |
while(events.size > 0){ | |
processEvent(events.poll()) | |
} | |
} | |
} | |
// ------------------------------------------ EXAMPLE USAGE ----------------------------------------------- | |
data class MoveEvent(val entityId: Int, val direction: Vector2) : Event() | |
val manager = EventManager() | |
manager.subscribe<MoveEvent>{ | |
println("${it.entityId}, ${it.direction}") | |
} | |
manager.publish(MoveEvent(0, Vector2(0f, 0f)); | |
manager.process() | |
output: | |
0, (0.0,0.0) | |
Thanks, for the first suggestion, I didn't know that existed, much nicer.
The problem with the second suggestion is that it breaks the subscribe function and forces me to also change the subscribe parameter from (T) -> Unit to (Event) -> Unit, which is bad because then every time you use the subscribe function you have to cast the parameter thats being passed.
For example the move event example becomes this
eventmanager.subscribe<MoveEvent>{
val move = it as MoveEvent
println("${move.entityId}, ${move.direction}")
}
No problem.
- Oh, didn't think of it... OK
val subscriptions
can be marked @PublishedApi internal
to reduce its visibility. I don't think the function type casting can be avoided.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I see the following improvements:
to
subscriptions.getOrPut(event) { mutableListOf() }.add(subscriber)
subscriptions: MutableMap<Class<out Event>, MutableList<(Event) -> Unit>>
(instead ofsubscriptions: MutableMap<Class<out Event>, MutableList<Any>>
).After it, you are able to change
to