package wow.doge.mygame import akka.actor.typed.scaladsl.Behaviors import wow.doge.mygame.game.GameApp import akka.actor.typed.Behavior import wow.doge.mygame.game.GameAppActor import cats.effect.Resource import akka.actor.typed.ActorSystem import monix.bio.Task import wow.doge.mygame.game.GameModule import io.odin._ import io.odin.syntax._ import wow.doge.mygame.executors.ExecutorsModule import akka.actor.typed.scaladsl.ActorContext import wow.doge.mygame.executors.Schedulers import com.softwaremill.macwire._ import akka.actor.typed.SpawnProtocol import akka.actor.typed.Scheduler import wow.doge.mygame.utils.AkkaUtils import scala.concurrent.duration._ import akka.actor.typed.ActorRef import wow.doge.mygame.implicits._ trait MainModule extends GameModule with ExecutorsModule { def actorSystemResource( logger: Logger[Task], app: GameApp, schedulers: Schedulers ): Resource[Task, ActorSystem[RootActor.Command]] = Resource.make(logger.info("Creating Actor System") >> Task { ActorSystem( wire[RootActor.Props].create(RootActor.State.empty), name = "GameActorSystem" ) })(sys => logger.info("Shutting down actor system") >> Task( sys.terminate() ) ) def actorSystemResource2( logger: Logger[Task] ): Resource[Task, ActorSystem[SpawnProtocol.Command]] = Resource.make(logger.info("Creating Actor System") >> Task { ActorSystem( SpawnProtocol(), name = "GameActorSystem2" ) })(sys => logger.info("Shutting down actor system") >> Task( sys.terminate() ) ) def rootActorResource( loggerL: Logger[Task], app: GameApp, schedulers: Schedulers, spawnProtocol: ActorSystem[SpawnProtocol.Command] ): Resource[Task, ActorRef[RootActor.Command]] = Resource.make( loggerL.info("Creating Root Actor") >> AkkaUtils.spawnActorL( behavior = RootActor(app, schedulers, logger = loggerL), actorName = "RootActor", spawnProtocol = spawnProtocol )(1.seconds, spawnProtocol.scheduler) )(actor => loggerL.info("Shutting down root actor") >> (actor !! RootActor.Stop) ) } object RootActor { sealed trait Command final case class Start(akkaScheduler: Scheduler) extends Command final case object Stop extends Command final case class Props( app: GameApp, schedulers: Schedulers, logger: Logger[Task] ) { def create(state: State): Behavior[Command] = Behaviors.setup { ctx => ctx.log.info("Hello from root actor") wire[RootActor].receive(State.empty) } } final case class State(initialized: Boolean = false) object State { val empty = State() } def apply( app: GameApp, schedulers: Schedulers, state: State = State.empty, logger: Logger[Task] ): Behavior[Command] = Behaviors.setup { ctx => ctx.log.info("Hello from root actor") wire[RootActor].receive(state) } } class RootActor( ctx: ActorContext[RootActor.Command], app: GameApp, schedulers: Schedulers, logger: Logger[Task] ) { import RootActor._ def receive(state: State): Behavior[Command] = Behaviors.receiveMessage(msg => msg match { case Start(akkaScheduler) => if (!state.initialized) { ctx.log.info("Starting GameAppActor") val spawnProtocol = ctx.spawn(SpawnProtocol(), "spawnProtocol") val _ = ctx.spawn( wire[GameAppActor.Props].create, "gameAppActor" // DispatcherSelector.fromConfig("jme-dispatcher") ) receive(state.copy(initialized = true)) } else { ctx.log.warn("Already Initialized") Behaviors.same } case Stop => ctx.log.info("Stopping") Behaviors.stopped } ) }