Archived
1
0
Fork 0

Add an option for EventTargetGroup to be thread-safe

This commit is contained in:
Moritz Ruth 2020-11-22 17:39:01 +01:00
parent 27cf3c5a50
commit f958b9c364
No known key found for this signature in database
GPG key ID: AFD57E23E753841B
6 changed files with 15 additions and 27 deletions

View file

@ -1,9 +1,10 @@
package space.blokk.event
abstract class EventTargetGroup<T : EventTarget<*>> : Iterable<T> {
// TODO: Allow using a different collection implementation (in order to allow concurrency)
private val targets: MutableCollection<T> = mutableSetOf()
private val listeners = mutableSetOf<Listener>()
import java.util.concurrent.CopyOnWriteArraySet
abstract class EventTargetGroup<T : EventTarget<*>>(threadSafe: Boolean = false) : Iterable<T> {
private val targets: MutableSet<T> = if (threadSafe) CopyOnWriteArraySet() else HashSet()
private val listeners: MutableSet<Listener> = if (threadSafe) CopyOnWriteArraySet() else HashSet()
/**
* Register a listener for all elements in this group.
@ -11,8 +12,8 @@ abstract class EventTargetGroup<T : EventTarget<*>> : Iterable<T> {
* because this may lead to strange behaviour.
*/
fun <T : Listener> registerListener(listener: T): T {
targets.forEach { it.eventBus.register(listener) }
listeners.add(listener)
targets.forEach { it.eventBus.register(listener) }
return listener
}
@ -28,15 +29,16 @@ abstract class EventTargetGroup<T : EventTarget<*>> : Iterable<T> {
override fun iterator(): Iterator<T> = targets.iterator()
protected fun addTarget(target: T) {
listeners.forEach { target.eventBus.register(it) }
targets.add(target)
listeners.forEach { target.eventBus.register(it) }
}
protected fun removeTarget(target: T) {
targets.remove(target)
listeners.forEach { target.eventBus.unregister(it) }
}
class Public<T : EventTarget<*>> : EventTargetGroup<T>() {
class Mutable<T : EventTarget<*>>(threadSafe: Boolean = false) : EventTargetGroup<T>(threadSafe) {
fun add(target: T) = addTarget(target)
fun remove(target: T) = removeTarget(target)
}

View file

@ -31,7 +31,7 @@ abstract class World(val uuid: UUID) {
/**
* All entities in this world. Use [spawnEntity] for spawning new ones.
*/
abstract val entities: EventTargetGroup.Public<Entity>
abstract val entities: EventTargetGroup.Mutable<Entity>
/**
* All currently loaded chunks of this world.

View file

@ -5,10 +5,11 @@ import com.sksamuel.hoplite.ConfigLoader
import com.sksamuel.hoplite.ConfigSource
import space.blokk.config.BlokkConfig
import space.blokk.event.EventBus
import space.blokk.event.EventTargetGroup
import space.blokk.logging.BlokkLoggingOutputProvider
import space.blokk.logging.Logger
import space.blokk.net.BlokkSocketServer
import space.blokk.player.PlayerGroup
import space.blokk.player.Player
import space.blokk.plugin.BlokkPluginManager
import space.blokk.server.Server
import space.blokk.server.event.ServerEvent
@ -27,7 +28,7 @@ class BlokkServer internal constructor() : Server {
override val eventBus = EventBus(ServerEvent::class, scope, logger)
override val sessions by socketServer::sessions
override val players = PlayerGroup()
override val players = EventTargetGroup.Mutable<Player>(true)
override val pluginManager = BlokkPluginManager(this)
val keyPair: KeyPair

View file

@ -11,6 +11,7 @@ import io.netty.channel.kqueue.KQueueServerSocketChannel
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioServerSocketChannel
import space.blokk.BlokkServer
import space.blokk.event.EventTargetGroup
import space.blokk.logging.Logger
class BlokkSocketServer(val server: BlokkServer) {
@ -31,7 +32,7 @@ class BlokkSocketServer(val server: BlokkServer) {
.childOption(ChannelOption.TCP_NODELAY, true)
.childHandler(BlokkChannelInitializer(this))
internal val sessions = SessionGroup()
internal val sessions = EventTargetGroup.Mutable<Session>(true)
fun bind() {
bootstrap.bind(server.config.host, server.config.port)

View file

@ -1,8 +0,0 @@
package space.blokk.net
import space.blokk.event.EventTargetGroup
class SessionGroup : EventTargetGroup<Session>() {
fun add(target: Session) = addTarget(target)
fun remove(target: Session) = removeTarget(target)
}

View file

@ -1,8 +0,0 @@
package space.blokk.player
import space.blokk.event.EventTargetGroup
class PlayerGroup : EventTargetGroup<Player>() {
fun add(target: Player) = addTarget(target)
fun remove(target: Player) = removeTarget(target)
}