Testing out JmonkeyEngine to make a game in Scala with Akka Actors within a pure FP layer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

139 lines
4.8 KiB

4 years ago
  1. package wow.doge.mygame.events
  2. // import akka.event.ActorEventBus
  3. // import akka.event.ManagedActorClassification
  4. // import akka.event.ActorClassifier
  5. import akka.actor.typed.ActorRef
  6. // import akka.actor.ActorSystem
  7. // import akka.event.EventBus
  8. // import akka.util.Subclassification
  9. // import java.util.concurrent.atomic.AtomicReference
  10. import akka.actor.typed.Behavior
  11. import akka.actor.typed.scaladsl.Behaviors
  12. import scala.reflect.ClassTag
  13. import akka.event.EventStream
  14. // private[events] final case class ClassificationMessage(ref: ActorRef, id: Int)
  15. // class ActorBusImpl(val system: ActorSystem, val busSize: Int)
  16. // extends ActorEventBus
  17. // with ActorClassifier
  18. // with ManagedActorClassification {
  19. // type Event = ClassificationMessage
  20. // // is used for extracting the classifier from the incoming events
  21. // override protected def classify(event: Event): ActorRef = event.ref
  22. // // determines the initial size of the index data structure
  23. // // used internally (i.e. the expected number of different classifiers)
  24. // override protected def mapSize: Int = busSize
  25. // }
  26. // class StartsWithSubclassification extends Subclassification[String] {
  27. // override def isEqual(x: String, y: String): Boolean =
  28. // x == y
  29. // override def isSubclass(x: String, y: String): Boolean =
  30. // x.startsWith(y)
  31. // }
  32. // import akka.event.SubchannelClassification
  33. // final case class MsgEnvelope(topic: String, payload: Any)
  34. // import akka.actor.typed.scaladsl.adapter._
  35. // /**
  36. // * Publishes the payload of the MsgEnvelope when the topic of the
  37. // * MsgEnvelope starts with the String specified when subscribing.
  38. // */
  39. // class SubchannelBusImpl extends EventBus with SubchannelClassification {
  40. // type Event = Any
  41. // type Classifier = Class[_]
  42. // type Subscriber = ActorRef
  43. // // Subclassification is an object providing `isEqual` and `isSubclass`
  44. // // to be consumed by the other methods of this classifier
  45. // // override protected val subclassification: Subclassification[Classifier] =
  46. // // new StartsWithSubclassification
  47. // private val initiallySubscribedOrUnsubscriber =
  48. // new AtomicReference[Either[Set[ActorRef], ActorRef]](Left(Set.empty))
  49. // override protected implicit val subclassification
  50. // : Subclassification[Classifier] = new Subclassification[Class[_]] {
  51. // def isEqual(x: Class[_], y: Class[_]) = x == y
  52. // def isSubclass(x: Class[_], y: Class[_]) = y.isAssignableFrom(x)
  53. // }
  54. // // is used for extracting the classifier from the incoming events
  55. // override protected def classify(event: Event): Classifier = event.getClass()
  56. // // will be invoked for each event for all subscribers which registered
  57. // // themselves for the event’s classifier
  58. // override protected def publish(event: Event, subscriber: Subscriber): Unit = {
  59. // // subscriber ! event.payload
  60. // subscriber ! event
  61. // }
  62. // }
  63. object EventBus {
  64. sealed trait Command[A]
  65. final case class Publish[A, E <: A](event: E, publisher: ActorRef[_])
  66. extends Command[A]
  67. /**
  68. * Subscribe a typed actor to listen for types or subtypes of E
  69. * by sending this command to the [[akka.actor.typed.ActorSystem.eventStream]].
  70. *
  71. * ==Simple example==
  72. * {{{
  73. * sealed trait A
  74. * case object A1 extends A
  75. * //listen for all As
  76. * def subscribe(actorSystem: ActorSystem[_], actorRef: ActorRef[A]) =
  77. * actorSystem.eventStream ! EventStream.Subscribe(actorRef)
  78. * //listen for A1s only
  79. * def subscribe(actorSystem: ActorSystem[_], actorRef: ActorRef[A]) =
  80. * actorSystem.eventStream ! EventStream.Subscribe[A1](actorRef)
  81. * }}}
  82. */
  83. final case class Subscribe[A, E <: A](subscriber: ActorRef[E])(implicit
  84. classTag: ClassTag[E]
  85. ) extends Command[A] {
  86. def topic: Class[_] = classTag.runtimeClass
  87. }
  88. /**
  89. * Unsubscribe an actor ref from the event stream
  90. * by sending this command to the [[akka.actor.typed.ActorSystem.eventStream]].
  91. */
  92. final case class Unsubscribe[A, E <: A](subscriber: ActorRef[E])
  93. extends Command[A]
  94. def apply[A](): Behavior[EventBus.Command[A]] =
  95. Behaviors.setup { ctx =>
  96. val eventStream = new EventStream(ctx.system.classicSystem)
  97. new EventBus().eventStreamBehavior(eventStream)
  98. }
  99. }
  100. class EventBus[B] {
  101. import akka.actor.typed.scaladsl.adapter._
  102. private def eventStreamBehavior(
  103. eventStream: akka.event.EventStream
  104. ): Behavior[EventBus.Command[B]] =
  105. Behaviors.receiveMessage {
  106. case EventBus.Publish(event, publisher) =>
  107. eventStream.publish(event)
  108. Behaviors.same
  109. case s @ EventBus.Subscribe(subscriber) =>
  110. eventStream.subscribe(subscriber.toClassic, s.topic)
  111. Behaviors.same
  112. case EventBus.Unsubscribe(subscriber) =>
  113. eventStream.unsubscribe(subscriber.toClassic)
  114. Behaviors.same
  115. }
  116. }