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.
 
 

135 lines
3.8 KiB

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
}
)
}