diff --git a/build.sbt b/build.sbt index ad4bdaa..6072f63 100644 --- a/build.sbt +++ b/build.sbt @@ -74,7 +74,8 @@ lazy val root = (project in file(".")).settings( "org.typelevel" %% "cats-core" % "2.1.1", "org.typelevel" %% "cats-effect" % "2.1.4", "io.monix" %% "monix" % "3.2.2", - "io.monix" %% "monix-bio" % "1.0.0", + // "io.monix" %% "monix-bio" % "1.0.0", + "io.monix" %% "monix-bio" % "1.1.0", "io.circe" %% "circe-core" % "0.13.0", "io.circe" %% "circe-generic" % "0.13.0", "com.softwaremill.sttp.client" %% "core" % "2.2.5", @@ -91,7 +92,8 @@ lazy val root = (project in file(".")).settings( "org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.0-RC1", "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2", "io.circe" %% "circe-config" % "0.8.0", - "com.beachape" %% "enumeratum-circe" % "1.6.1" + "com.beachape" %% "enumeratum-circe" % "1.6.1", + "com.lihaoyi" %% "os-lib" % "0.7.1" ), // Determine OS version of JavaFX binaries @@ -104,12 +106,20 @@ lazy val root = (project in file(".")).settings( "UTF-8", "-deprecation", "-feature", + "-language:existentials", + "-language:experimental.macros", + "-language:higherKinds", + "-language:implicitConversions", "-unchecked", "-Xlint", "-Ywarn-numeric-widen", "-Ymacro-annotations", - "-Xlint:byname-implicit", + // "-Xlint:byname-implicit", // "utf-8", // Specify character encoding used by source files. + //silence warnings for by-name implicits + "-Wconf:cat=lint-byname-implicit:s", + //give errors on non exhaustive matches + "-Wconf:msg=match may not be exhaustive:e", "-explaintypes" // Explain type errors in more detail. ), javacOptions ++= Seq("-source", "11", "-target", "11"), @@ -199,3 +209,4 @@ initialCommands in (console) := """ammonite.Main.main(Array.empty)""" // To learn more about multi-project builds, head over to the official sbt // documentation at http://www.scala-sbt.org/documentation.html addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1") +ThisBuild / scalafixDependencies += "com.github.liancheng" %% "organize-imports" % "0.4.3" diff --git a/src/main/resources/dep.sc b/src/main/resources/dep.sc deleted file mode 100644 index c5c6b6c..0000000 --- a/src/main/resources/dep.sc +++ /dev/null @@ -1,2 +0,0 @@ -// println("hello from dep") -class Test(x: Int) diff --git a/src/main/resources/hello.groovy b/src/main/resources/hello.groovy deleted file mode 100644 index 546f358..0000000 --- a/src/main/resources/hello.groovy +++ /dev/null @@ -1,3 +0,0 @@ -println "hello" - -this \ No newline at end of file diff --git a/src/main/resources/hello.main.kts b/src/main/resources/hello.main.kts deleted file mode 100644 index 75d8050..0000000 --- a/src/main/resources/hello.main.kts +++ /dev/null @@ -1,36 +0,0 @@ -// @file:Import("src/main/resources/hello2.main.kts") -@file:DependsOn("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.0-M1") -@file:DependsOn("/home/rohan/.m2/repository/wow/doge/game/1.0-SNAPSHOT/game-1.0-SNAPSHOT.jar") -@file:DependsOn("/home/rohan/.ivy2/local/wow.doge/mygame_2.13/1.0-SNAPSHOT/jars/mygame_2.13.jar") - -import wow.doge.game.types.GameScript - -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlin.random.Random - -import wow.doge.mygame.components.Test - - -//println(x * 2) - -println("hello from main script") - -class GameScriptImpl : GameScript { - override fun start() = runBlocking { - for(x in 0 until 5) { - launch { - val del = Random.nextLong(20, 100) - - delay(del) - println("hello from start $x, delay is $del") - } - } - } - override fun stop() {println("hello from stop")} -} - -GameScriptImpl() - -class MyTest : Test() \ No newline at end of file diff --git a/src/main/resources/hello.sc b/src/main/resources/hello.sc deleted file mode 100644 index 2b69a50..0000000 --- a/src/main/resources/hello.sc +++ /dev/null @@ -1,35 +0,0 @@ -// #!/usr/bin/env amm - -// import coursierapi.MavenRepository - -// interp.repositories.update( -// interp.repositories() ::: List( -// MavenRepository.of("file://home/rohan/.m2/repository") -// ) -// ) - -// @ -// import $repo.`https://jcenter.bintray.com` -// // import $repo.`https://bintray.com/jmonkeyengine/com.jme3` -// import $file.dep -// import $ivy.`org.jmonkeyengine:jme3-core:3.2.4-stable` -// import $ivy.`wow.doge:game:1.0-SNAPSHOT` -// import wow.doge.game.types.GameScript -// import com.jme3.scene.control.Control - -// println("hello from script") - -// class Scr extends GameScript { -// def start(): Unit = println("hello from start") - -// def stop(): Unit = println("hello from stop") -// } - -// // class SomeClass extends Control {} - -// @main -// def main(): GameScript = new Scr() -import $file.dep -import dep.Test - -new Test(1) diff --git a/src/main/resources/hello2.main.kts b/src/main/resources/hello2.main.kts deleted file mode 100644 index 6fdb380..0000000 --- a/src/main/resources/hello2.main.kts +++ /dev/null @@ -1,5 +0,0 @@ -println("hello from dep") - -class Test(val x: Int) - -var x = 2 \ No newline at end of file diff --git a/src/main/resources/hello2.sc b/src/main/resources/hello2.sc deleted file mode 100644 index 740501c..0000000 --- a/src/main/resources/hello2.sc +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env amm -// scala 2.13.3 - -// import coursierapi.MavenRepository - -// interp.repositories.update( -// interp.repositories() ::: List( -// MavenRepository.of("file://home/rohan/.m2/repository") -// ) -// ) - -// @ -import $repo.`https://jcenter.bintray.com` -// import $repo.`https://bintray.com/jmonkeyengine/com.jme3` -// import $file.dep -import $ivy.`org.jmonkeyengine:jme3-core:3.2.4-stable` -// import $ivy.`wow.doge:game:1.0-SNAPSHOT` -import $ivy.`wow.doge::mygame:1.0-SNAPSHOT` -// import wow.doge.game.types.GameScript -import com.jme3.scene.control.Control - -// println("hello from script") - -// class Scr extends GameScript { -// def start(): Unit = println("hello from start") - -// def stop(): Unit = println("hello from stop") -// } - -// // class SomeClass extends Control {} - -// @main -// def main(): GameScript = new Scr() -import com.simsilica.es.base.DefaultEntityData -import com.simsilica.es.EntityData -import com.jme3.app.Application -import wow.doge.mygame.game.Implicits._ -import wow.doge.mygame.components.TestComponent -import com.jme3.scene.shape.Box -import com.jme3.scene.Geometry -import com.jme3.material.Material -import com.jme3.math.ColorRGBA -import com.jme3.asset.AssetManager -import com.jme3.math.Vector3f -import wow.doge.mygame.state._ -class TestAppState( - // private var _entity: Option[EntityData] = Some(new DefaultEntityData()) -) extends MyBaseState { - protected lazy val b = new Box(1, 1, 1) - protected lazy val geom = new Geometry("Box", b) - protected lazy val mat = Material( - assetManager = assetManager, - path = "Common/MatDefs/Misc/Unshaded.j3md" - ) - -// def entity = _entity - // override def initialize(app: Application): Unit = { - // super.initialize(app) - - // } - - override def init() = { - entityData - .createEntity() - .withComponents(TestComponent()) - // entityData.setComponents(x, TestComponent()) - val es = entityData.getEntities(classOf[TestComponent]) - println(es) - geom.setMaterial(mat) - rootNode.attachChild(geom) - - // geom.foreach(e => { - - // }) - } - - override def update(tpf: Float) = { - geom.rotate(0, 0.5f * tpf, 0) - geom.move(new Vector3f(0, 1 * tpf, 0)) - } - - override def cleanup(app: Application): Unit = { - // _entity.map(_.close()) - // _entity = None - } - - override def onEnable(): Unit = {} - - override def onDisable(): Unit = {} - -} - -object Material { - def apply( - color: String = "Color", - colorType: com.jme3.math.ColorRGBA = ColorRGBA.Blue, - assetManager: AssetManager, - path: String - ): Material = { - val mat = - new Material(assetManager, path) - mat.setColor(color, colorType) - mat - } -} - -@main -def main(): MyBaseState = new TestAppState() diff --git a/src/main/scala/com/jme3/input/package.scala b/src/main/scala/com/jme3/input/package.scala index 48ddc07..fff855f 100644 --- a/src/main/scala/com/jme3/input/package.scala +++ b/src/main/scala/com/jme3/input/package.scala @@ -1,6 +1,7 @@ package com.jme3 -import com.jme3.input.controls.{InputListener, Trigger} +import com.jme3.input.controls.InputListener +import com.jme3.input.controls.Trigger /** * Created by Brandon Barker on 6/21/17. diff --git a/src/main/scala/com/jme3/syntax/package.scala b/src/main/scala/com/jme3/syntax/package.scala index a3532da..be6c318 100644 --- a/src/main/scala/com/jme3/syntax/package.scala +++ b/src/main/scala/com/jme3/syntax/package.scala @@ -1,13 +1,12 @@ package com.jme3 - /** * Created by Brandon Barker on 6/21/17. */ package object syntax { @specialized def discard[A](evaluateForSideEffectOnly: A): Unit = { - val _: A = evaluateForSideEffectOnly + val _ = evaluateForSideEffectOnly () //Return unit to prevent warning due to discarding value } diff --git a/src/main/scala/org/slf4j/impl/StaticLoggerBuilder.scala b/src/main/scala/org/slf4j/impl/StaticLoggerBuilder.scala index 5e4dbf3..529ee98 100644 --- a/src/main/scala/org/slf4j/impl/StaticLoggerBuilder.scala +++ b/src/main/scala/org/slf4j/impl/StaticLoggerBuilder.scala @@ -1,18 +1,22 @@ package org.slf4j.impl -import cats.effect.{ContextShift, Clock, Effect, IO, Timer} -import io.odin._ -import io.odin.slf4j.OdinLoggerBinder -import cats.implicits._ - +import scala.collection.immutable.ArraySeq import scala.concurrent.ExecutionContext +import scala.concurrent.duration._ + import _root_.monix.execution.Scheduler -import cats.arrow.FunctionK import _root_.monix.execution.Scheduler.Implicits.global -import io.odin.syntax._ -import scala.concurrent.duration._ -import scala.collection.immutable.ArraySeq +import cats.arrow.FunctionK +import cats.effect.Clock +import cats.effect.ContextShift +import cats.effect.Effect +import cats.effect.IO +import cats.effect.Timer +import cats.implicits._ +import io.odin._ import io.odin.json.Formatter +import io.odin.slf4j.OdinLoggerBinder +import io.odin.syntax._ //effect type should be specified inbefore //log line will be recorded right after the call with no suspension diff --git a/src/main/scala/wow/doge/mygame/ActorSystemModule.scala b/src/main/scala/wow/doge/mygame/ActorSystemModule.scala deleted file mode 100644 index ec94405..0000000 --- a/src/main/scala/wow/doge/mygame/ActorSystemModule.scala +++ /dev/null @@ -1,27 +0,0 @@ -package wow.doge.mygame - -import akka.actor.typed.ActorSystem -import cats.effect.Resource -import monix.bio.Task -import io.odin.Logger -import wow.doge.mygame.game.GameApp -import wow.doge.mygame.executors.Schedulers - -trait ActorSystemModule { - - def logger: Logger[Task] - def app: GameApp - def schedulers: Schedulers - - lazy val actorsResource = - Resource.make(logger.info("Creating Actor System") >> Task { - ActorSystem( - RootActor(app, schedulers, logger = logger), - name = "GameActorSystem" - ) - })(sys => - logger.info("Shutting down actor system") >> Task( - sys.terminate() - ) - ) -} diff --git a/src/main/scala/wow/doge/mygame/Main.scala b/src/main/scala/wow/doge/mygame/Main.scala index f4c66a2..e4c89d1 100644 --- a/src/main/scala/wow/doge/mygame/Main.scala +++ b/src/main/scala/wow/doge/mygame/Main.scala @@ -1,24 +1,21 @@ package wow.doge.mygame -import cats.effect.Resource -import io.odin.syntax._ +import scala.concurrent.duration._ +import _root_.monix.bio.Task +import akka.util.Timeout import cats.effect.ExitCode import cats.implicits._ import com.softwaremill.macwire._ -import scala.concurrent.duration._ -import monix.bio.BIOApp -import monix.bio.UIO import io.odin._ -import wow.doge.mygame.game.GameAppResource import io.odin.json.Formatter -import wow.doge.mygame.game.GameSystemsInitializer -import wow.doge.mygame.subsystems.events.EventsModule2 -import wow.doge.mygame.implicits._ -import com.jme3.bullet.BulletAppState -import akka.util.Timeout +import io.odin.syntax._ +import wow.doge.mygame.game.GameAppResource import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource -import ammonite.runtime.tools.time +import _root_.monix.bio.BIOApp +import _root_.monix.bio.UIO +import cats.effect.Resource + object Main extends BIOApp with MainModule { import java.util.logging.{Logger => JLogger, Level} JLogger.getLogger("").setLevel(Level.SEVERE) @@ -41,19 +38,36 @@ object Main extends BIOApp with MainModule { // akkaScheduler = actorSystemResource2.scheduler // consoleTextArea <- Resource.liftF(Task(new TextArea())) // consoleStream <- wireWith(JFXConsoleStream.textAreaStream _) - (gameApp, gameAppFib) <- { + (gameApp) <- { // new BulletAppState() // bas.setThreadingType(Thr) // gameAppResource(new StatsAppState()) - wire[GameAppResource].get + wire[GameAppResource].get2 } - app = gameApp - inputManager = gameApp.inputManager - assetManager = gameApp.assetManager - bulletAppState = new BulletAppState() - (playerMovementEventBus, playerCameraEventBus) <- new EventsModule2( - actorSystem - ).resource + _ <- Resource.liftF( + new MainApp(logger, gameApp, actorSystem, jmeScheduler)( + timeout, + actorSystem.scheduler + ).gameInit + ) + // fib <- Resource.liftF( + // gameApp + // .enqueueL(() => + // new MainApp(logger, gameApp, actorSystem, jmeScheduler)( + // timeout, + // actorSystem.scheduler + // ) + // ) + // .start + // ) + // _ <- Resource.liftF(fib.join.flatMap(_.gameInit) + // app = gameApp + // inputManager = gameApp.inputManager + // assetManager = gameApp.assetManager + // bulletAppState = new BulletAppState() + // (playerMovementEventBus, playerCameraEventBus) <- new EventsModule2( + // actorSystem + // ).resource // b1 = playerMovementEventBus // b2 = playerCameraEventBus @@ -67,62 +81,15 @@ object Main extends BIOApp with MainModule { // ) // } - // _ <- Resource.liftF(IO(JMERunner.runner = gameApp)) - // _ <- Resource.liftF(IO { - // new ActorSystemModule {} - // }) - // actorSystem <- wireWith(actorSystemResource _) - - // rootActor <- rootActorResource(logger, gameApp, schedulers, as2) - // _ <- Resource.liftF( - // gameApp.enqueueT(actorSystem ! RootActor.Start(actorSystem.scheduler)) - // ) - // gameSystemsInitializer = new GameSystemsInitializer( - // actorSystem, - // logger, - // playerMovementEventBus, - // playerCameraEventBus - // )(gameApp) - - gameSystemsInitializerFib <- Resource.make( - logger.info("creating game systems initializer") >> - gameApp - .enqueueL(() => wire[GameSystemsInitializer]) - .start - )(c => logger.info("destroying game systems initializer") >> c.cancel) - _ <- Resource.liftF(gameSystemsInitializerFib.join.flatMap(_.init)) - - // .runAsync { - // case Left(err) => println(err) - // case _ => - // }(schedulers.async) + // gameSystemsInitializerFib <- Resource.make( + // logger.info("creating game systems initializer") >> + // gameApp + // .enqueueL(() => wire[GameSystemsInitializer]) + // .start + // )(c => logger.info("destroying game systems initializer") >> c.cancel) + // _ <- Resource.liftF(gameSystemsInitializerFib.join.flatMap(_.init)) - // _ <- Resource.liftF { - // Task { - // implicit val sched = actorSystem.scheduler - // implicit val timeout = Timeout(2.seconds) - // // val module = new EventsModule {} - // } - // } - // actorSystem <- wireWith(actorSystemResource2 _) - // (tickEventBus, playerMovementEventBus) <- wireWith(eventBusesResource _) - // rootActor <- wireWith(rootActorResource _) - // inputSystemHandler <- { - // inputHandlerSystemResource( - // GameInputHandler.Props(gameApp.inputManager, playerMovementEventBus) - // ) - // } - // gameSystemsInitializer <- - // gameSystemsResource(actorSystem, inputSystemHandler) - // _ <- Resource.liftF( - // gameApp.enqueueT(rootActor ! RootActor.Start(actorSystem.scheduler)) - // ) - // _ <- Resource.liftF { - // IO(gameApp.start()) - // .executeOn(jmeScheduler) - // } - // (_ => IO(gameApp.stop(() => actorSystem ! RootActor.Stop))) - } yield (gameAppFib) + } yield () // def createPlayerController( // playerMovementEventBus: ActorRef[ @@ -145,7 +112,7 @@ object Main extends BIOApp with MainModule { // ) // )(()) appResource - .use(_.join) + .use(_ => Task.unit) .onErrorHandle(_.printStackTrace()) .as(ExitCode.Success) } diff --git a/src/main/scala/wow/doge/mygame/MainApp.scala b/src/main/scala/wow/doge/mygame/MainApp.scala new file mode 100644 index 0000000..5bed4f7 --- /dev/null +++ b/src/main/scala/wow/doge/mygame/MainApp.scala @@ -0,0 +1,139 @@ +package wow.doge.mygame + +import akka.actor.typed.ActorRef +import akka.actor.typed.ActorSystem +import akka.actor.typed.Scheduler +import akka.actor.typed.SpawnProtocol +import akka.util.Timeout +import cats.effect.concurrent.Ref +import com.jme3.app.state.AppStateManager +import com.jme3.asset.AssetManager +import com.jme3.asset.plugins.ZipLocator +import com.jme3.bullet.BulletAppState +import com.jme3.input.InputManager +import com.jme3.renderer.Camera +import com.jme3.scene.Node +import com.softwaremill.macwire._ +import com.softwaremill.tagging._ +import io.odin.Logger +import monix.bio.IO +import monix.bio.Task +import wow.doge.mygame.events.EventBus +import wow.doge.mygame.game.GameApp2 +import wow.doge.mygame.game.nodes.Player +import wow.doge.mygame.game.nodes.PlayerController +import wow.doge.mygame.game.subsystems.input.GameInputHandler +import wow.doge.mygame.implicits._ +import wow.doge.mygame.math.ImVector3f +import wow.doge.mygame.subsystems.events.EntityMovementEvent +import wow.doge.mygame.subsystems.events.EventsModule2 +import wow.doge.mygame.subsystems.events.PlayerCameraEvent +import wow.doge.mygame.game.subsystems.level.DefaultGameLevel +import com.jme3.renderer.ViewPort +import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource +import wow.doge.mygame.subsystems.scriptsystem.ScriptInitMode + +class MainApp( + logger: Logger[Task], + gameApp: GameApp2, + spawnProtocol: ActorSystem[SpawnProtocol.Command], + jmeThread: monix.execution.Scheduler +)(implicit + @annotation.unused timeout: Timeout, + @annotation.unused scheduler: Scheduler +) { + + lazy val scriptSystemInit = + new ScriptSystemResource(os.pwd, spawnProtocol, ScriptInitMode.Eager).init + + lazy val gameInit: Task[Unit] = for { + eventsModule <- Task(new EventsModule2(spawnProtocol)) + playerMovementEventBus <- eventsModule.playerMovementEventBusTask + playerCameraEventBus <- eventsModule.playerCameraEventBusTask + gameAppFib <- gameApp.start.executeOn(jmeThread).start + /** + * schedule a fiber to run on the JME thread and wait for it's completion + * before proceeding forward, as a signal that JME thread has been + * initialized, otherwise we'll get NPEs trying to access the fields + * of the game app + */ + initFib <- gameApp.enqueueL(() => Task("done")).start + _ <- initFib.join + inputManager <- gameApp.inputManager + assetManager <- gameApp.assetManager + stateManager <- gameApp.stateManager + camera <- gameApp.camera + rootNode <- gameApp.rootNode + enqueueR <- Task(gameApp.enqueue _) + viewPort <- gameApp.viewPort + bulletAppState <- Task(new BulletAppState()) + appScheduler <- Task(gameApp.scheduler) + // enqueueL <- Task(gameApp.enqueueL _) + _ <- wire[MainAppDelegate].init(gameApp.scheduler) + _ <- gameAppFib.join + } yield () + + lazy val program = for { + scriptSystem <- scriptSystemInit + game <- gameInit + } yield () +} + +class MainAppDelegate( + gameApp: GameApp2, + spawnProtocol: ActorSystem[SpawnProtocol.Command], + loggerL: Logger[Task], + // eventBuses: EventsModule2 + playerMovementEventBus: ActorRef[ + EventBus.Command[EntityMovementEvent.PlayerMovementEvent] + ], + playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]], + inputManager: InputManager, + assetManager: AssetManager, + stateManager: AppStateManager, + camera: Camera, + viewPort: ViewPort, + enqueueR: Function1[() => Unit, Unit], + rootNode: Ref[Task, Node], + bulletAppState: BulletAppState +)(implicit + @annotation.unused timeout: Timeout, + @annotation.unused scheduler: Scheduler +) { + + def init(appScheduler: monix.execution.Scheduler) = + for { + _ <- loggerL.info("Initializing Systems") + _ <- Task(stateManager.attach(bulletAppState)) + _ <- Task( + assetManager.registerLocator( + (os.rel / "assets" / "town.zip"), + classOf[ZipLocator] + ) + ) + _ <- DefaultGameLevel(assetManager, viewPort) + .addToGame( + rootNode, + bulletAppState.physicsSpace + ) + .executeOn(appScheduler) + _ <- createPlayerController(appScheduler).startAndForget.onErrorRestart(3) + _ <- wire[GameInputHandler.Props].begin.onErrorRestart(3) + } yield () + + def createPlayerController( + appScheduler: monix.execution.Scheduler + // playerMovementEventBus: ActorRef[ + // EventBus.Command[PlayerMovementEvent] + // ], + // playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]] + ): IO[PlayerController.Error, Unit] = { + @annotation.unused + val playerPos = ImVector3f.ZERO + @annotation.unused + val playerNode = None.taggedWith[Player] + @annotation.unused + val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o" + wire[PlayerController.Props].create + } +} diff --git a/src/main/scala/wow/doge/mygame/MainModule.scala b/src/main/scala/wow/doge/mygame/MainModule.scala index 7b2c2bb..87f51b5 100644 --- a/src/main/scala/wow/doge/mygame/MainModule.scala +++ b/src/main/scala/wow/doge/mygame/MainModule.scala @@ -1,41 +1,13 @@ 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 akka.actor.typed.SpawnProtocol +import cats.effect.Resource +import io.odin.Logger 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._ +import wow.doge.mygame.game.GameModule 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] @@ -43,93 +15,11 @@ trait MainModule extends GameModule with ExecutorsModule { Resource.make(logger.info("Creating Actor System") >> Task { ActorSystem( SpawnProtocol(), - name = "GameActorSystem2" + name = "GameActorSystem" ) })(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 - - } - ) } diff --git a/src/main/scala/wow/doge/mygame/executors/ExecutorsModule.scala b/src/main/scala/wow/doge/mygame/executors/ExecutorsModule.scala index d607079..d88745f 100644 --- a/src/main/scala/wow/doge/mygame/executors/ExecutorsModule.scala +++ b/src/main/scala/wow/doge/mygame/executors/ExecutorsModule.scala @@ -1,7 +1,7 @@ package wow.doge.mygame.executors -import monix.bio.Task import cats.effect.Resource +import monix.bio.Task import monix.execution.Scheduler trait ExecutorsModule { diff --git a/src/main/scala/wow/doge/mygame/executors/GUIExecutor.scala b/src/main/scala/wow/doge/mygame/executors/GUIExecutor.scala index f1f78d0..8738128 100644 --- a/src/main/scala/wow/doge/mygame/executors/GUIExecutor.scala +++ b/src/main/scala/wow/doge/mygame/executors/GUIExecutor.scala @@ -1,23 +1,21 @@ package wow.doge.mygame.executors -import akka.dispatch.{ - DispatcherPrerequisites, - ExecutorServiceFactory, - ExecutorServiceConfigurator -} -import com.typesafe.config.Config -import java.util.concurrent.{ - ExecutorService, - AbstractExecutorService, - ThreadFactory, - TimeUnit -} import java.util.Collections +import java.util.concurrent.AbstractExecutorService +import java.util.concurrent.Executor +import java.util.concurrent.ExecutorService +import java.util.concurrent.ThreadFactory +import java.util.concurrent.TimeUnit import javax.swing.SwingUtilities + +import scala.concurrent.ExecutionContext + +import akka.dispatch.DispatcherPrerequisites +import akka.dispatch.ExecutorServiceConfigurator +import akka.dispatch.ExecutorServiceFactory +import com.typesafe.config.Config import javafx.application.Platform import monix.execution.Scheduler -import scala.concurrent.ExecutionContext -import java.util.concurrent.Executor // First we wrap invokeLater/runLater as an ExecutorService trait GUIExecutorService extends AbstractExecutorService { diff --git a/src/main/scala/wow/doge/mygame/executors/Schedulers.scala b/src/main/scala/wow/doge/mygame/executors/Schedulers.scala index 7c982f4..bd1d4d3 100644 --- a/src/main/scala/wow/doge/mygame/executors/Schedulers.scala +++ b/src/main/scala/wow/doge/mygame/executors/Schedulers.scala @@ -1,8 +1,8 @@ package wow.doge.mygame.executors +import com.typesafe.scalalogging.Logger import monix.execution.Scheduler import monix.execution.UncaughtExceptionReporter -import com.typesafe.scalalogging.Logger final case class Schedulers( blockingIO: Scheduler = Scheduler diff --git a/src/main/scala/wow/doge/mygame/game/GameApp.scala b/src/main/scala/wow/doge/mygame/game/GameApp.scala index 2a2d939..b364403 100644 --- a/src/main/scala/wow/doge/mygame/game/GameApp.scala +++ b/src/main/scala/wow/doge/mygame/game/GameApp.scala @@ -1,18 +1,18 @@ package wow.doge.mygame.game -import com.jme3.app.SimpleApplication +import scala.collection.immutable.Queue +import com.jme3.app.SimpleApplication import com.jme3.app.state.AppState -import monix.execution.{CancelablePromise => Promise} -import monix.execution.CancelableFuture import monix.bio.Task +import monix.execution.CancelableFuture import monix.execution.Scheduler -import wow.doge.mygame.executors.GUIExecutorService -import monix.reactive.subjects.ConcurrentSubject +import monix.execution.atomic.Atomic +import monix.execution.{CancelablePromise => Promise} import monix.reactive.MulticastStrategy import monix.reactive.Observable -import monix.execution.atomic.Atomic -import scala.collection.immutable.Queue +import monix.reactive.subjects.ConcurrentSubject +import wow.doge.mygame.executors.GUIExecutorService import wow.doge.mygame.executors.Schedulers class GameApp( diff --git a/src/main/scala/wow/doge/mygame/game/GameApp2.scala b/src/main/scala/wow/doge/mygame/game/GameApp2.scala new file mode 100644 index 0000000..e3c231f --- /dev/null +++ b/src/main/scala/wow/doge/mygame/game/GameApp2.scala @@ -0,0 +1,35 @@ +package wow.doge.mygame.game + +import cats.effect.concurrent.Ref +import com.jme3.app.state.AppStateManager +import com.jme3.asset.AssetManager +import com.jme3.input.InputManager +import monix.bio.IO +import monix.bio.Task + +sealed trait Error +case object FlyCamNotExists extends Error + +class GameApp2(app: GameApp) { + def stateManager: Task[AppStateManager] = Task(app.getStateManager()) + def inputManager: Task[InputManager] = Task(app.getInputManager()) + def assetManager: Task[AssetManager] = Task(app.getAssetManager()) + def guiNode = Ref[Task].of(app.getGuiNode()) + def flyCam = + IO(app.getFlyByCamera()).onErrorHandleWith(_ => + IO.raiseError(FlyCamNotExists) + ) + def camera = Task(app.getCamera()) + def viewPort = Task(app.getViewPort()) + def rootNode = Ref[Task].of(app.getRootNode()) + def enqueue(cb: () => Unit) = + app.enqueue(new Runnable { + override def run() = cb() + }) + def enqueueL[T](cb: () => T): Task[T] = app.enqueueL(cb) + + def start = Task(app.start()) + def stop = Task(app.stop()) + def scheduler = app.scheduler + +} diff --git a/src/main/scala/wow/doge/mygame/game/GameAppActor.scala b/src/main/scala/wow/doge/mygame/game/GameAppActor.scala index 340aca4..89d3fbd 100644 --- a/src/main/scala/wow/doge/mygame/game/GameAppActor.scala +++ b/src/main/scala/wow/doge/mygame/game/GameAppActor.scala @@ -1,27 +1,15 @@ package wow.doge.mygame.game -import akka.actor.typed.scaladsl.Behaviors -import com.jme3.scene.Geometry - -import wow.doge.mygame.events.Events -import com.jme3.scene.CameraNode -import com.jme3.scene.Node -import com.jme3.renderer.Camera -import wow.doge.mygame.executors.Schedulers -import com.softwaremill.macwire._ - -import wow.doge.mygame.implicits._ -import akka.actor.typed.SpawnProtocol import akka.actor.typed.ActorRef +import akka.actor.typed.Scheduler +import akka.actor.typed.SpawnProtocol +import akka.actor.typed.scaladsl.Behaviors import io.odin.Logger import monix.bio.Task -import akka.actor.typed.Scheduler -import scala.util.Failure -import scala.util.Success -import com.jme3.app.StatsAppState +import wow.doge.mygame.events.Events +import wow.doge.mygame.executors.Schedulers object GameAppActor { - import Methods._ sealed trait Command case object ApplicationStarted extends Command @@ -39,22 +27,6 @@ object GameAppActor { Behaviors.setup[Command] { ctx => ctx.log.info("Hello from GameAppActor") - // { - // implicit val s = schedulers.async - - // val initializer: GameSystemsInitializer = wire[GameSystemsInitializer] - - // schedulers.async.execute(() => initializer.init.runAsyncAndForget) - - // // ctx.pipeToSelf(application.timed.runToFuture) { - // // case Failure(exception) => - // // ApplicationStartFailed(exception.getMessage()) - // // case Success(value) => - // // println("here applications started") - // // ApplicationStarted - // // } - // } - Behaviors.receiveMessage { msg => msg match { case Stop => diff --git a/src/main/scala/wow/doge/mygame/game/GameModule.scala b/src/main/scala/wow/doge/mygame/game/GameModule.scala index bb74081..7aabcdc 100644 --- a/src/main/scala/wow/doge/mygame/game/GameModule.scala +++ b/src/main/scala/wow/doge/mygame/game/GameModule.scala @@ -1,28 +1,28 @@ package wow.doge.mygame.game +import akka.actor.typed.ActorRef +import akka.actor.typed.SpawnProtocol import cats.effect.Resource +import com.jme3.app.StatsAppState import com.jme3.system.AppSettings -import monix.bio.Task import io.odin.Logger -import akka.actor.typed.ActorRef -import akka.actor.typed.SpawnProtocol -import wow.doge.mygame.game.subsystems.input.GameInputHandler -import monix.bio.IO import monix.bio.Fiber +import monix.bio.IO +import monix.bio.Task import monix.execution.Scheduler -import com.jme3.app.StatsAppState import wow.doge.mygame.executors.Schedulers +import wow.doge.mygame.game.subsystems.input.GameInputHandler class GameAppResource( logger: Logger[Task], jmeScheduler: Scheduler, schedulers: Schedulers ) { - def get: Resource[Task, (GameApp, Fiber[Throwable, Unit])] = + def get: Resource[Task, (GameApp2, Fiber[Throwable, Unit])] = Resource.make( for { _ <- logger.info("Creating game app") app <- Task(new GameApp(schedulers, new StatsAppState())) - _ <- Task { + app2 <- Task { val settings = new AppSettings(true) settings.setVSync(true) settings.setUseInput(true) @@ -30,11 +30,31 @@ class GameAppResource( // settings.setFrameRate(250) app.setSettings(settings) // JMERunner.runner = app - app + // app + new GameApp2(app) } - fib <- Task(app.start()).executeOn(jmeScheduler).start - } yield (app -> fib) + fib <- app2.start.executeOn(jmeScheduler).start + } yield (app2 -> fib) )(logger.info("Closing game app") >> _._2.cancel) + + def get2: Resource[Task, GameApp2] = + Resource.make( + for { + _ <- logger.info("Creating game app") + app <- Task(new GameApp(schedulers, new StatsAppState())) + app2 <- Task { + val settings = new AppSettings(true) + settings.setVSync(true) + settings.setUseInput(true) + // new FlyCamAppState + // settings.setFrameRate(250) + app.setSettings(settings) + // JMERunner.runner = app + new GameApp2(app) + } + // fib <- app2.start.executeOn(jmeScheduler).start + } yield (app2) + )(_ => logger.info("Closing game app")) } trait GameModule { diff --git a/src/main/scala/wow/doge/mygame/game/GameSystemsInitializer.scala b/src/main/scala/wow/doge/mygame/game/GameSystemsInitializer.scala index 11de59b..90f1dc7 100644 --- a/src/main/scala/wow/doge/mygame/game/GameSystemsInitializer.scala +++ b/src/main/scala/wow/doge/mygame/game/GameSystemsInitializer.scala @@ -3,30 +3,34 @@ package wow.doge.mygame.game import scala.concurrent.duration._ import akka.actor.typed.ActorRef +import akka.actor.typed.ActorSystem import akka.actor.typed.Scheduler import akka.actor.typed.SpawnProtocol import akka.util.Timeout +import cats.effect.concurrent.Ref +import com.jme3.app.state.AppStateManager +import com.jme3.asset.AssetManager import com.jme3.asset.plugins.ZipLocator import com.jme3.bullet.BulletAppState +import com.jme3.input.InputManager +import com.jme3.renderer.Camera +import com.jme3.scene.Node import com.softwaremill.macwire._ import com.softwaremill.tagging._ import io.odin.Logger +import monix.bio.IO import monix.bio.Task import monix.reactive.Consumer import wow.doge.mygame.events.EventBus import wow.doge.mygame.game.nodes.Player import wow.doge.mygame.game.nodes.PlayerController import wow.doge.mygame.game.subsystems.input.GameInputHandler -import wow.doge.mygame.game.subsystems.level.DefaultGameLevel import wow.doge.mygame.implicits._ -import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent -import wow.doge.mygame.subsystems.movement.ImMovementActor -import wow.doge.mygame.utils.IOUtils import wow.doge.mygame.math.ImVector3f -import monix.bio.IO import wow.doge.mygame.subsystems.events.EntityMovementEvent -import akka.actor.typed.ActorSystem import wow.doge.mygame.subsystems.events.PlayerCameraEvent +import wow.doge.mygame.subsystems.movement.ImMovementActor +import wow.doge.mygame.utils.IOUtils class GameSystemsInitializer( spawnProtocol: ActorSystem[SpawnProtocol.Command], @@ -35,15 +39,22 @@ class GameSystemsInitializer( playerMovementEventBus: ActorRef[ EventBus.Command[EntityMovementEvent.PlayerMovementEvent] ], - playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]] -)(app: GameApp) { + playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]], + inputManager: InputManager, + assetManager: AssetManager, + stateManager: AppStateManager, + camera: Camera, + enqueueR: Function1[() => Unit, Unit], + appScheduler: monix.execution.Scheduler, + rootNode: Ref[Task, Node] +) { implicit val timeout: Timeout = Timeout(1.second) import GameSystemsInitializer._ implicit val akkaScheduler: Scheduler = spawnProtocol.scheduler - lazy val inputManager = app.inputManager - lazy val assetManager = app.assetManager + // lazy val inputManager = app.inputManager + // lazy val assetManager = app.assetManager lazy val bulletAppState = new BulletAppState() // lazy val playerMovementEventBus = eventBuses.playerMovementEventBusTask @@ -51,15 +62,16 @@ class GameSystemsInitializer( for { _ <- loggerL.info("Initializing Systems") // playerMovementEventBus <- playerMovementEventBusTask - _ <- Task(app.stateManager.attach(bulletAppState)) + _ <- Task(stateManager.attach(bulletAppState)) _ <- Task( - app.assetManager.registerLocator( + assetManager.registerLocator( // "src/main/resources/assets/town.zip", - (os.rel / "src" / "main" / "resources" / "assets" / "town.zip"), + (os.rel / "assets" / "town.zip"), classOf[ZipLocator] ) ) - _ <- app.enqueueL(() => DefaultGameLevel(app, bulletAppState)) + + // _ <- app.enqueueL(() => DefaultGameLevel(app, bulletAppState)) _ <- wireWith(createPlayerController _).startAndForget _ <- wire[GameInputHandler.Props].begin @@ -71,8 +83,11 @@ class GameSystemsInitializer( // ], // playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]] ): IO[PlayerController.Error, Unit] = { + @annotation.unused val playerPos = ImVector3f.ZERO + @annotation.unused val playerNode = None.taggedWith[Player] + @annotation.unused val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o" wire[PlayerController.Props].create } diff --git a/src/main/scala/wow/doge/mygame/game/appstates/MyBaseState.scala b/src/main/scala/wow/doge/mygame/game/appstates/MyBaseState.scala index fbf147a..4d93a3f 100644 --- a/src/main/scala/wow/doge/mygame/game/appstates/MyBaseState.scala +++ b/src/main/scala/wow/doge/mygame/game/appstates/MyBaseState.scala @@ -3,11 +3,11 @@ package wow.doge.mygame.state import com.jme3.app.Application import com.jme3.app.SimpleApplication import com.jme3.app.state.AppState -import com.jme3.scene.Node import com.jme3.app.state.BaseAppState +import com.jme3.scene.Node +import com.jme3.scene.Spatial import com.simsilica.es.EntityData import com.simsilica.es.base.DefaultEntityData -import com.jme3.scene.Spatial trait MyBaseState extends BaseAppState { diff --git a/src/main/scala/wow/doge/mygame/game/appstates/PlayerMovementState.scala b/src/main/scala/wow/doge/mygame/game/appstates/PlayerMovementState.scala index 862a4cb..ead9db2 100644 --- a/src/main/scala/wow/doge/mygame/game/appstates/PlayerMovementState.scala +++ b/src/main/scala/wow/doge/mygame/game/appstates/PlayerMovementState.scala @@ -2,18 +2,16 @@ package wow.doge.mygame.state import scala.concurrent.duration.DurationInt +import akka.actor.typed.ActorRef +import akka.actor.typed.Behavior +import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors +import akka.actor.typed.scaladsl.TimerScheduler import com.jme3.input.InputManager import com.jme3.input.KeyInput import com.jme3.input.controls.KeyTrigger import com.jme3.math.Vector3f - -import akka.actor.typed.scaladsl.ActorContext -import akka.actor.typed.scaladsl.Behaviors -import akka.actor.typed.Behavior -import akka.actor.typed.ActorRef import com.jme3.scene.Geometry -import akka.actor.typed.scaladsl.TimerScheduler - import wow.doge.mygame.implicits._ import wow.doge.mygame.subsystems.movement.ImMovementActor diff --git a/src/main/scala/wow/doge/mygame/game/appstates/ScriptingEngineState.scala b/src/main/scala/wow/doge/mygame/game/appstates/ScriptingEngineState.scala index f4c2ad1..c9008eb 100644 --- a/src/main/scala/wow/doge/mygame/game/appstates/ScriptingEngineState.scala +++ b/src/main/scala/wow/doge/mygame/game/appstates/ScriptingEngineState.scala @@ -1,17 +1,18 @@ package wow.doge.mygame.state -import ammonite.runtime.Storage.Folder -import ammonite.main.Defaults -import ammonite.Main import javax.script.ScriptEngine -import com.jme3.app.state.AppState + +import akka.actor.typed.ActorRef +import akka.actor.typed.Behavior +import akka.actor.typed.SpawnProtocol import akka.actor.typed.scaladsl.AbstractBehavior import akka.actor.typed.scaladsl.ActorContext -import akka.actor.typed.Behavior -import akka.actor.typed.ActorRef -import ammonite.util.Res.Success import akka.actor.typed.scaladsl.Behaviors -import akka.actor.typed.SpawnProtocol +import ammonite.Main +import ammonite.main.Defaults +import ammonite.runtime.Storage.Folder +import ammonite.util.Res.Success +import com.jme3.app.state.AppState class ScriptingEngineState( sse: ScalaScriptingEngine, diff --git a/src/main/scala/wow/doge/mygame/game/appstates/TestAppState.scala b/src/main/scala/wow/doge/mygame/game/appstates/TestAppState.scala index b89678a..8f5e804 100644 --- a/src/main/scala/wow/doge/mygame/game/appstates/TestAppState.scala +++ b/src/main/scala/wow/doge/mygame/game/appstates/TestAppState.scala @@ -1,13 +1,13 @@ package wow.doge.mygame.state -import wow.doge.mygame.implicits._ -import wow.doge.mygame.components.TestComponent -import com.jme3.scene.shape.Box -import com.jme3.scene.Geometry +import com.jme3.asset.AssetManager import com.jme3.material.Material import com.jme3.math.ColorRGBA -import com.jme3.asset.AssetManager import com.jme3.math.Vector3f +import com.jme3.scene.Geometry +import com.jme3.scene.shape.Box +import wow.doge.mygame.components.TestComponent +import wow.doge.mygame.implicits._ class TestAppState( // private var _entity: Option[EntityData] = Some(new DefaultEntityData()) ) extends MyBaseState { diff --git a/src/main/scala/wow/doge/mygame/game/components/Position.scala b/src/main/scala/wow/doge/mygame/game/components/Position.scala index 1dbe781..8b7fb67 100644 --- a/src/main/scala/wow/doge/mygame/game/components/Position.scala +++ b/src/main/scala/wow/doge/mygame/game/components/Position.scala @@ -1,6 +1,6 @@ package wow.doge.mygame.components -import com.simsilica.es.EntityComponent; +import com.simsilica.es.EntityComponent import wow.doge.mygame.math.ImVector3f final case class Position(location: ImVector3f) extends EntityComponent diff --git a/src/main/scala/wow/doge/mygame/game/nodes/PlayerActorSupervisor.scala b/src/main/scala/wow/doge/mygame/game/nodes/PlayerActorSupervisor.scala index f8d94e6..1648ea4 100644 --- a/src/main/scala/wow/doge/mygame/game/nodes/PlayerActorSupervisor.scala +++ b/src/main/scala/wow/doge/mygame/game/nodes/PlayerActorSupervisor.scala @@ -1,30 +1,29 @@ package wow.doge.mygame.game.nodes -import akka.actor.typed.scaladsl.Behaviors -import akka.actor.typed.scaladsl.ActorContext -import wow.doge.mygame.subsystems.movement.ImMovementActor -import wow.doge.mygame.game.GameApp +import scala.concurrent.duration._ + import akka.actor.typed.ActorRef -import wow.doge.mygame.events.EventBus -import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent -import wow.doge.mygame.subsystems.events.EntityMovementEvent -import akka.actor.typed.scaladsl.TimerScheduler import akka.actor.typed.Behavior -import scala.concurrent.duration._ import akka.actor.typed.LogOptions -import org.slf4j.event.Level -import com.typesafe.scalalogging.Logger import akka.actor.typed.SupervisorStrategy +import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors +import akka.actor.typed.scaladsl.TimerScheduler import com.jme3.scene.CameraNode -import wow.doge.mygame.subsystems.events.PlayerCameraEvent +import com.typesafe.scalalogging.Logger +import org.slf4j.event.Level +import wow.doge.mygame.events.EventBus import wow.doge.mygame.game.subsystems.movement.CanMove -import wow.doge.mygame.implicits._ +import wow.doge.mygame.subsystems.events.EntityMovementEvent +import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent +import wow.doge.mygame.subsystems.events.PlayerCameraEvent +import wow.doge.mygame.subsystems.movement.ImMovementActor object PlayerActorSupervisor { sealed trait Command final case class Props( - app: GameApp, + enqueueR: Function1[() => Unit, Unit], camNode: CameraNode, playerMovementEventBus: ActorRef[ EventBus.Command[PlayerMovementEvent] @@ -47,7 +46,7 @@ object PlayerActorSupervisor { Behaviors .supervise( ImMovementActor - .Props(app, movable, playerMovementEventBus) + .Props(enqueueR, movable, playerMovementEventBus) .create ) .onFailure[Exception](SupervisorStrategy.restart), @@ -70,7 +69,7 @@ object PlayerActorSupervisor { ctx.spawn( Behaviors .supervise( - PlayerCameraEventListener(camNode, app.enqueueR) + PlayerCameraEventListener(camNode, enqueueR) ) .onFailure[Exception](SupervisorStrategy.restart), "playerCameraHandler" diff --git a/src/main/scala/wow/doge/mygame/game/nodes/PlayerCameraActor.scala b/src/main/scala/wow/doge/mygame/game/nodes/PlayerCameraActor.scala index 8047e75..5b3657f 100644 --- a/src/main/scala/wow/doge/mygame/game/nodes/PlayerCameraActor.scala +++ b/src/main/scala/wow/doge/mygame/game/nodes/PlayerCameraActor.scala @@ -1,7 +1,7 @@ package wow.doge.mygame.game.nodes -import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors object PlayerCameraActor { sealed trait Command diff --git a/src/main/scala/wow/doge/mygame/game/nodes/PlayerController.scala b/src/main/scala/wow/doge/mygame/game/nodes/PlayerController.scala index a6d5f60..7a69d92 100644 --- a/src/main/scala/wow/doge/mygame/game/nodes/PlayerController.scala +++ b/src/main/scala/wow/doge/mygame/game/nodes/PlayerController.scala @@ -1,33 +1,34 @@ package wow.doge.mygame.game.nodes -import com.jme3.scene.Node +import akka.actor.typed.ActorRef +import akka.actor.typed.Props +import akka.actor.typed.Scheduler +import akka.actor.typed.SpawnProtocol +import akka.util.Timeout +import cats.effect.concurrent.Ref +import cats.implicits._ +import com.jme3.asset.AssetManager +import com.jme3.bullet.BulletAppState +import com.jme3.bullet.control.BetterCharacterControl +import com.jme3.math.FastMath +import com.jme3.renderer.Camera import com.jme3.scene.CameraNode import com.jme3.scene.Geometry -import com.jme3.renderer.Camera -import com.jme3.asset.AssetManager -import wow.doge.mygame.state.MyMaterial +import com.jme3.scene.Node import com.jme3.scene.control.CameraControl.ControlDirection import com.jme3.scene.shape.Box -import com.jme3.bullet.control.BetterCharacterControl -import com.jme3.bullet.BulletAppState +import com.softwaremill.tagging._ +import io.odin.Logger +import monix.bio.IO +import monix.bio.Task +import wow.doge.mygame.events.EventBus import wow.doge.mygame.game.GameApp import wow.doge.mygame.implicits._ import wow.doge.mygame.math.ImVector3f -import com.jme3.math.FastMath -import monix.bio.IO -import cats.implicits._ -import akka.actor.typed.ActorRef -import wow.doge.mygame.events.EventBus -import akka.actor.typed.SpawnProtocol +import wow.doge.mygame.state.MyMaterial import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent -import wow.doge.mygame.subsystems.movement.ImMovementActor -import io.odin.Logger -import akka.util.Timeout -import monix.bio.Task -import akka.actor.typed.Scheduler -import akka.actor.typed.Props -import com.softwaremill.tagging._ import wow.doge.mygame.subsystems.events.PlayerCameraEvent +import wow.doge.mygame.subsystems.movement.ImMovementActor import wow.doge.mygame.utils.AkkaUtils // class PlayerNode(val name: String) extends Node(name) {} @@ -39,7 +40,9 @@ object PlayerController { case class GenericError(reason: String) extends Error class Props( - app: GameApp, + enqueueR: Function1[() => Unit, Unit], + rootNode: Ref[Task, Node], + camera: Camera, loggerL: Logger[Task], assetManager: AssetManager, bulletAppState: BulletAppState, @@ -52,15 +55,15 @@ object PlayerController { playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]], _playerPhysicsControl: Option[BetterCharacterControl], _playerNode: Option[Node with Player] = None, - _cameraNode: Option[CameraNode with PlayerCameraNode] = None + _cameraNode: Option[CameraNode with PlayerCameraNode] = None, + appScheduler: monix.execution.Scheduler )(implicit timeout: Timeout, scheduler: Scheduler) { import Defaults._ - import Methods._ val create: IO[Error, Unit] = // IO.raiseError(GenericError("not implemented yet")) (for { camNode <- IO( - _cameraNode.getOrElse(defaultCamerNode(app.camera, initialPlayerPos)) + _cameraNode.getOrElse(defaultCamerNode(camera, initialPlayerPos)) ) playerPhysicsControl <- IO( _playerPhysicsControl @@ -82,7 +85,7 @@ object PlayerController { spawnProtocol, "playerActorSupervisor", new PlayerActorSupervisor.Props( - app, + enqueueR, camNode, playerMovementEventBus, playerCameraEventBus @@ -92,11 +95,10 @@ object PlayerController { bulletAppState.physicsSpace += playerNode bulletAppState.physicsSpace += playerPhysicsControl } - _ <- IO(app.rootNode += playerNode) + _ <- rootNode.update(_ :+ playerNode) } yield ()) .onErrorHandleWith(e => IO.raiseError(GenericError(e.getMessage()))) - .executeOn(app.scheduler) - + .executeOn(appScheduler) } def apply( @@ -175,7 +177,7 @@ object Defaults { object Methods { def spawnMovementActor( - app: GameApp, + enqueueR: Function1[() => Unit, Unit], spawnProtocol: ActorRef[SpawnProtocol.Command], movable: BetterCharacterControl @@ Player, playerMovementEventBus: ActorRef[ @@ -185,7 +187,7 @@ object Methods { )(implicit timeout: Timeout, scheduler: Scheduler) = spawnProtocol.askL[ActorRef[ImMovementActor.Command]]( SpawnProtocol.Spawn( - ImMovementActor.Props(app, movable, playerMovementEventBus).create, + ImMovementActor.Props(enqueueR, movable, playerMovementEventBus).create, "imMovementActor", Props.empty, _ diff --git a/src/main/scala/wow/doge/mygame/game/nodes/PlayerEventListeners.scala b/src/main/scala/wow/doge/mygame/game/nodes/PlayerEventListeners.scala index 72ef5b9..1b9f7f6 100644 --- a/src/main/scala/wow/doge/mygame/game/nodes/PlayerEventListeners.scala +++ b/src/main/scala/wow/doge/mygame/game/nodes/PlayerEventListeners.scala @@ -1,18 +1,16 @@ package wow.doge.mygame.game.nodes import akka.actor.typed.ActorRef +import akka.actor.typed.LogOptions import akka.actor.typed.scaladsl.Behaviors -import wow.doge.mygame.subsystems.movement.ImMovementActor +import com.jme3.scene.CameraNode +import com.typesafe.scalalogging.Logger import org.slf4j.event.Level -import akka.actor.typed.LogOptions import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent -import com.typesafe.scalalogging.Logger import wow.doge.mygame.subsystems.events.PlayerCameraEvent -import wow.doge.mygame.subsystems.events.PlayerCameraEvent.CameraMovedUp import wow.doge.mygame.subsystems.events.PlayerCameraEvent.CameraMovedDown -import com.jme3.scene.CameraNode -import wow.doge.mygame.game.GameApp -import wow.doge.mygame.implicits._ +import wow.doge.mygame.subsystems.events.PlayerCameraEvent.CameraMovedUp +import wow.doge.mygame.subsystems.movement.ImMovementActor object PlayerMovementEventListener { import PlayerMovementEvent._ diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala b/src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala index 43dd24e..ca82781 100644 --- a/src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala +++ b/src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala @@ -1,23 +1,19 @@ package wow.doge.mygame.game.subsystems.input -import com.jme3.input.InputManager -import wow.doge.mygame.implicits._ +import scala.concurrent.duration._ + import akka.actor.typed.ActorRef -import wow.doge.mygame.events.EventBus +import com.jme3.input.InputManager import com.jme3.input.KeyInput +import com.jme3.input.MouseInput import com.jme3.input.controls.KeyTrigger +import com.jme3.input.controls.MouseAxisTrigger import monix.bio.UIO -import wow.doge.mygame.utils.IOUtils._ +import wow.doge.mygame.events.EventBus +import wow.doge.mygame.implicits._ import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent -import scala.concurrent.duration._ -import com.jme3.input.controls.MouseAxisTrigger -import com.jme3.input.MouseInput import wow.doge.mygame.subsystems.events.PlayerCameraEvent - -// class GameInputHandler( -// inputManager: InputManager -// // inputEventBus: InputEventBus -// ) {} +import wow.doge.mygame.utils.IOUtils._ object GameInputHandler { @@ -30,6 +26,7 @@ object GameInputHandler { ) { def begin = for { + _ <- UIO(setupMovementKeys(inputManager)) _ <- UIO(setupKeys(inputManager)) _ <- toIO( generateMovementInputEvents( @@ -49,40 +46,49 @@ object GameInputHandler { playerCameraEventBus ).completedL.startAndForget ) - _ <- toIO( - myTest( - inputManager - ).completedL.startAndForget - ) } yield () } + def setupMovementKeys(inputManager: InputManager) = + inputManager.withEnumMappings(PlayerMovementInput) { + case PlayerMovementInput.WalkRight => + Seq(new KeyTrigger(KeyInput.KEY_D)) + case PlayerMovementInput.WalkLeft => + Seq(new KeyTrigger(KeyInput.KEY_A)) + case PlayerMovementInput.WalkForward => + Seq(new KeyTrigger(KeyInput.KEY_W)) + case PlayerMovementInput.WalkBackward => + Seq(new KeyTrigger(KeyInput.KEY_S)) + case PlayerMovementInput.Jump => + Seq(new KeyTrigger(KeyInput.KEY_SPACE)) + } + def setupKeys(inputManager: InputManager) = inputManager - .withMapping( - PlayerMovementInput.WalkLeft.entryName, - new KeyTrigger(KeyInput.KEY_A) - // new KeyTrigger(KeyInput.KEY_LEFT) - ) - .withMapping( - PlayerMovementInput.WalkRight.entryName, - new KeyTrigger(KeyInput.KEY_D) - // new KeyTrigger(KeyInput.KEY_RIGHT) - ) - .withMapping( - PlayerMovementInput.WalkForward.entryName, - new KeyTrigger(KeyInput.KEY_W) - // new KeyTrigger(KeyInput.KEY_UP) - ) - .withMapping( - PlayerMovementInput.WalkBackward.entryName, - new KeyTrigger(KeyInput.KEY_S) - // new KeyTrigger(KeyInput.KEY_DOWN) - ) - .withMapping( - "Jump", - new KeyTrigger(KeyInput.KEY_SPACE) - ) + // .withMapping( + // PlayerMovementInput.WalkLeft.entryName, + // new KeyTrigger(KeyInput.KEY_A) + // // new KeyTrigger(KeyInput.KEY_LEFT) + // ) + // .withMapping( + // PlayerMovementInput.WalkRight.entryName, + // new KeyTrigger(KeyInput.KEY_D) + // // new KeyTrigger(KeyInput.KEY_RIGHT) + // ) + // .withMapping( + // PlayerMovementInput.WalkForward.entryName, + // new KeyTrigger(KeyInput.KEY_W) + // // new KeyTrigger(KeyInput.KEY_UP) + // ) + // .withMapping( + // PlayerMovementInput.WalkBackward.entryName, + // new KeyTrigger(KeyInput.KEY_S) + // // new KeyTrigger(KeyInput.KEY_DOWN) + // ) + // .withMapping( + // PlayerMovementInput.Jump.entryName, + // new KeyTrigger(KeyInput.KEY_SPACE) + // ) .withMapping( PlayerAnalogInput.TurnRight.entryName, new KeyTrigger(KeyInput.KEY_RIGHT), @@ -145,33 +151,19 @@ object GameInputHandler { name ) ) - // case "Jump" if action.value => - // toTask( - // playerMovementEventBus !! EventBus.Publish( - // PlayerMovementEvent.PlayerJumped, - // name - // ) - // ) - - // case _ => monix.eval.Task.unit + case PlayerMovementInput.Jump => + if (action.value) { + toTask( + playerMovementEventBus !! EventBus.Publish( + PlayerMovementEvent.PlayerJumped, + name + ) + ) + } else monix.eval.Task.unit } } } - def myTest(inputManager: InputManager) = { - inputManager - .enumObservableAction(PlayerMovementEnum) - .sample(1.millis) - .mapEval(action => - action.binding match { - case PlayerMovementEnum.MOVE_RIGHT => - monix.eval.Task(println("move right")) >> monix.eval.Task.unit - case PlayerMovementEnum.MOVE_LEFT => - monix.eval.Task(println("move left")) - } - ) - } - def generateRotateEvents( inputManager: InputManager, playerMovementEventBus: ActorRef[ @@ -182,7 +174,7 @@ object GameInputHandler { inputManager .enumAnalogObservable(PlayerAnalogInput) .sample(1.millis) - .map(e => e) + // .map(e => e) .doOnNext(analogEvent => analogEvent.binding match { case PlayerAnalogInput.TurnRight => @@ -231,17 +223,4 @@ object GameInputHandler { } ) } - - // def bindMappings(inputManager: InputManager, mappings: ActionMapping*) = { - // inputManager - // .observableAction(mappings.map(_.name): _*) - // .doOnNext(action => - // mappings.map(m => - // if (action.binding.name == m.name) toTask(m.cb(action)) - // else monix.eval.Task.unit - // ) - // ) - // } } - -// case class ActionMapping(name: String, cb: ActionEvent => Task[Unit]) diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/input/InputEnums.scala b/src/main/scala/wow/doge/mygame/game/subsystems/input/InputEnums.scala index a69efa4..327ffca 100644 --- a/src/main/scala/wow/doge/mygame/game/subsystems/input/InputEnums.scala +++ b/src/main/scala/wow/doge/mygame/game/subsystems/input/InputEnums.scala @@ -1,6 +1,6 @@ package wow.doge.mygame.game.subsystems.input -import enumeratum._ import enumeratum.EnumEntry._ +import enumeratum._ sealed trait PlayerMovementInput extends EnumEntry with UpperSnakecase object PlayerMovementInput extends Enum[PlayerMovementInput] { @@ -9,6 +9,7 @@ object PlayerMovementInput extends Enum[PlayerMovementInput] { case object WalkRight extends PlayerMovementInput case object WalkLeft extends PlayerMovementInput case object WalkBackward extends PlayerMovementInput + case object Jump extends PlayerMovementInput } sealed trait PlayerAnalogInput extends EnumEntry with UpperSnakecase diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/level/DefaultGameLevel.scala b/src/main/scala/wow/doge/mygame/game/subsystems/level/DefaultGameLevel.scala index 7f98903..fb55178 100644 --- a/src/main/scala/wow/doge/mygame/game/subsystems/level/DefaultGameLevel.scala +++ b/src/main/scala/wow/doge/mygame/game/subsystems/level/DefaultGameLevel.scala @@ -1,36 +1,20 @@ package wow.doge.mygame.game.subsystems.level -import com.jme3.bullet.BulletAppState -import com.jme3.bullet.collision.shapes.CapsuleCollisionShape -import com.jme3.bullet.control.CharacterControl +import com.jme3.asset.AssetManager import com.jme3.bullet.control.RigidBodyControl import com.jme3.bullet.util.CollisionShapeFactory -import com.jme3.scene.Spatial -import wow.doge.mygame.implicits._ -import wow.doge.mygame.game.GameApp -import com.jme3.syntax._ -import com.jme3.math.ColorRGBA +import com.jme3.light.AmbientLight import com.jme3.light.DirectionalLight +import com.jme3.math.ColorRGBA import com.jme3.math.Vector3f -import com.jme3.light.AmbientLight +import com.jme3.renderer.ViewPort +import com.jme3.scene.Spatial object DefaultGameLevel { -// lazy valbulletAppState: BulletAppState - // bulletAppState.setThreadingType(ThreadingType.SEQUENTIAL) - - // We set up collision detection for the scene by creating a - // compound collision shape and a static RigidBodyControl with mass zero. - - // We set up collision detection for the player by creating - // a capsule collision shape and a CharacterControl. - // The CharacterControl offers extra settings for - // size, stepheight, jumping, falling, and gravity. - // We also put the player in its starting position. - lazy val capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1) - - lazy val player: CharacterControl = - new CharacterControl(capsuleShape, 0.05f) - def apply(app: GameApp, bulletAppState: BulletAppState) = { - lazy val sceneModel: Spatial = app.assetManager.loadModel("main.scene") + def apply( + assetManager: AssetManager, + viewPort: ViewPort + ) = { + lazy val sceneModel: Spatial = assetManager.loadModel("main.scene") lazy val sceneShape = CollisionShapeFactory.createMeshShape( sceneModel.toNode match { case util.Right(node) => node @@ -41,23 +25,26 @@ object DefaultGameLevel { lazy val landscape: RigidBodyControl = new RigidBodyControl(sceneShape, 0) - // // discard { app.stateManager.attach(bulletAppState) } - - app.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f)) + viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f)) sceneModel.setLocalScale(2f) sceneModel.addControl(landscape) - discard { app.rootNode.attachChild(sceneModel) } - bulletAppState.getPhysicsSpace.add(landscape) - bulletAppState.getPhysicsSpace.add(player) + // discard { rootNode.attachChild(sceneModel) } + // bulletAppState.getPhysicsSpace.add(landscape) + // bulletAppState.getPhysicsSpace.add(player) val al = new AmbientLight(); al.setColor(ColorRGBA.White.mult(1.3f)); - app.rootNode.addLight(al); + // app.rootNode.addLight(al); val dl = new DirectionalLight(); dl.setColor(ColorRGBA.White); dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal()); - app.rootNode.addLight(dl); - + // app.rootNode.addLight(dl); + new Level( + model = sceneModel, + physicsControl = landscape, + ambientLight = al, + directionalLight = dl + ) } } diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/level/Level.scala b/src/main/scala/wow/doge/mygame/game/subsystems/level/Level.scala new file mode 100644 index 0000000..a5ca94e --- /dev/null +++ b/src/main/scala/wow/doge/mygame/game/subsystems/level/Level.scala @@ -0,0 +1,34 @@ +package wow.doge.mygame.game.subsystems.level + +import com.jme3.bullet.control.RigidBodyControl +import com.jme3.light.AmbientLight +import com.jme3.light.DirectionalLight +import com.jme3.scene.Spatial +import com.jme3.bullet.PhysicsSpace +import cats.effect.concurrent.Ref +import monix.bio.Task +import com.jme3.scene.Node +import wow.doge.mygame.implicits._ + +class Level( + model: Spatial, + physicsControl: RigidBodyControl, + ambientLight: AmbientLight, + directionalLight: DirectionalLight +) { + def addToGame(rootNode: Ref[Task, Node], physicsSpace: PhysicsSpace) = { + for { + _ <- rootNode.update(_ :+ model) + _ <- rootNode.update { r => + r.addLight(ambientLight) + r + } + _ <- rootNode.update { r => + r.addLight(directionalLight) + r + } + _ <- Task(physicsSpace += model) + _ <- Task(physicsSpace += physicsControl) + } yield () + } +} diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/movement/CanMove.scala b/src/main/scala/wow/doge/mygame/game/subsystems/movement/CanMove.scala index 2c0ff02..8485c5f 100644 --- a/src/main/scala/wow/doge/mygame/game/subsystems/movement/CanMove.scala +++ b/src/main/scala/wow/doge/mygame/game/subsystems/movement/CanMove.scala @@ -4,11 +4,11 @@ import com.jme3.bullet.control.BetterCharacterControl import com.jme3.math.FastMath import com.jme3.math.Quaternion import com.jme3.math.Vector3f -import wow.doge.mygame.math.ImVector3f -import wow.doge.mygame.subsystems.movement.RotateDir -import wow.doge.mygame.implicits._ import com.jme3.scene.Spatial import com.typesafe.scalalogging.LazyLogging +import wow.doge.mygame.implicits._ +import wow.doge.mygame.math.ImVector3f +import wow.doge.mygame.subsystems.movement.RotateDir trait CanMove[-A] { // def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/movement/MovementActor.scala b/src/main/scala/wow/doge/mygame/game/subsystems/movement/MovementActor.scala index 6e4492a..9688f45 100644 --- a/src/main/scala/wow/doge/mygame/game/subsystems/movement/MovementActor.scala +++ b/src/main/scala/wow/doge/mygame/game/subsystems/movement/MovementActor.scala @@ -1,19 +1,17 @@ package wow.doge.mygame.subsystems.movement -import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.ActorRef import akka.actor.typed.Behavior +import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.Behaviors +import com.jme3.math.Vector3f +import com.softwaremill.quicklens._ +import wow.doge.mygame.events.EventBus +import wow.doge.mygame.game.subsystems.movement.CanMove import wow.doge.mygame.implicits._ import wow.doge.mygame.math.ImVector3f -import wow.doge.mygame.game.GameApp - -import akka.actor.typed.ActorRef -import wow.doge.mygame.events.EventBus -import com.jme3.math.Vector3f import wow.doge.mygame.state.CardinalDirection import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent -import wow.doge.mygame.game.subsystems.movement.CanMove -import com.softwaremill.quicklens._ sealed trait RotateDir object RotateDir { @@ -36,7 +34,7 @@ object ImMovementActor { final case object RotateLeft extends Movement final case class Props[T: CanMove]( - app: GameApp, + enqueueR: Function1[() => Unit, Unit], movable: T, playerMovementEventBus: ActorRef[ EventBus.Command[PlayerMovementEvent] @@ -90,25 +88,25 @@ class ImMovementActor[T]( case m: Movement => m match { case MovedLeft(pressed) => - props.app.enqueueR(() => stopIfNotPressed(pressed, props.movable)) + props.enqueueR(() => stopIfNotPressed(pressed, props.movable)) receive(state = state.modify(_.cardinalDir.left).setTo(pressed)) case MovedUp(pressed) => - props.app.enqueueR(() => stopIfNotPressed(pressed, props.movable)) + props.enqueueR(() => stopIfNotPressed(pressed, props.movable)) receive(state = state.modify(_.cardinalDir.up).setTo(pressed)) case MovedRight(pressed) => - props.app.enqueueR(() => stopIfNotPressed(pressed, props.movable)) + props.enqueueR(() => stopIfNotPressed(pressed, props.movable)) receive(state = state.modify(_.cardinalDir.right).setTo(pressed)) case MovedDown(pressed) => - props.app.enqueueR(() => stopIfNotPressed(pressed, props.movable)) + props.enqueueR(() => stopIfNotPressed(pressed, props.movable)) receive(state = state.modify(_.cardinalDir.down).setTo(pressed)) case Jump => - props.app.enqueueR(() => cm.jump(props.movable)) + props.enqueueR(() => cm.jump(props.movable)) Behaviors.same case RotateLeft => - props.app.enqueueR(() => cm.rotate(props.movable, RotateDir.Left)) + props.enqueueR(() => cm.rotate(props.movable, RotateDir.Left)) Behaviors.same case RotateRight => - props.app.enqueueR(() => cm.rotate(props.movable, RotateDir.Right)) + props.enqueueR(() => cm.rotate(props.movable, RotateDir.Right)) Behaviors.same } @@ -117,7 +115,7 @@ class ImMovementActor[T]( getDirection(state.cardinalDir, ctx.log.trace) if (walkDir != ImVector3f.ZERO) { val tmp = walkDir * 25f * (1f / 144) - props.app.enqueueR { () => + props.enqueueR { () => cm.move(props.movable, tmp) } } diff --git a/src/main/scala/wow/doge/mygame/implicits/EntityQuery.scala b/src/main/scala/wow/doge/mygame/implicits/EntityQuery.scala index af6e8cd..5120168 100644 --- a/src/main/scala/wow/doge/mygame/implicits/EntityQuery.scala +++ b/src/main/scala/wow/doge/mygame/implicits/EntityQuery.scala @@ -1,12 +1,13 @@ package wow.doge.mygame.implicits +import scala.reflect.ClassTag +import scala.util.Try + import com.simsilica.es.ComponentFilter import com.simsilica.es.EntityComponent import com.simsilica.es.EntityData import com.simsilica.es.EntitySet import com.simsilica.es.Filters -import scala.reflect.ClassTag -import scala.util.Try class EntityQuery(ed: EntityData) { private var cfilter: Option[ComponentFilter[_ <: EntityComponent]] = None diff --git a/src/main/scala/wow/doge/mygame/implicits/package.scala b/src/main/scala/wow/doge/mygame/implicits/package.scala index 09d982b..0d76f9b 100644 --- a/src/main/scala/wow/doge/mygame/implicits/package.scala +++ b/src/main/scala/wow/doge/mygame/implicits/package.scala @@ -1,52 +1,54 @@ package wow.doge.mygame -import com.jme3.app.SimpleApplication -import com.jme3.app.state.AppStateManager +import scala.jdk.CollectionConverters._ import scala.reflect.ClassTag -import com.jme3.app.state.AppState -import com.jme3.scene.Node -import com.jme3.scene.Spatial -import com.simsilica.es.EntityData -import com.simsilica.es.EntityComponent -import com.simsilica.es.EntityId + import akka.actor.typed.ActorRef -import akka.util.Timeout import akka.actor.typed.Scheduler -import monix.bio.Task +import akka.util.Timeout +import cats.effect.concurrent.Ref +import com.jme3.app.Application +import com.jme3.app.SimpleApplication +import com.jme3.app.state.AppState +import com.jme3.app.state.AppStateManager +import com.jme3.asset.AssetLocator +import com.jme3.asset.AssetManager +import com.jme3.bullet.BulletAppState +import com.jme3.bullet.PhysicsSpace +import com.jme3.bullet.PhysicsTickListener +import com.jme3.bullet.collision.PhysicsCollisionEvent +import com.jme3.bullet.collision.PhysicsCollisionListener +import com.jme3.bullet.control.BetterCharacterControl +import com.jme3.input.Action import com.jme3.input.InputManager -import com.jme3.input.controls.Trigger +import com.jme3.input.controls.ActionListener +import com.jme3.input.controls.AnalogListener import com.jme3.input.controls.InputListener +import com.jme3.input.controls.Trigger import com.jme3.math.Vector3f -import wow.doge.mygame.math.ImVector3f +import com.jme3.scene.CameraNode import com.jme3.scene.Geometry -import scala.jdk.CollectionConverters._ -import com.jme3.app.Application +import com.jme3.scene.Node import com.jme3.scene.SceneGraphVisitor -import monix.reactive.Observable -import com.jme3.asset.AssetManager -import com.jme3.asset.AssetLocator -import com.jme3.input.controls.ActionListener -import monix.reactive.OverflowStrategy +import com.jme3.scene.Spatial +import com.jme3.scene.control.CameraControl.ControlDirection +import com.jme3.scene.control.Control +import com.simsilica.es.EntityComponent +import com.simsilica.es.EntityData +import com.simsilica.es.EntityId +import enumeratum._ +import monix.bio.Task +import monix.bio.UIO import monix.execution.Ack +import monix.execution.Ack.Continue +import monix.execution.Ack.Stop import monix.execution.Cancelable import monix.execution.cancelables.SingleAssignCancelable -import com.jme3.input.Action -import com.jme3.bullet.PhysicsSpace -import com.jme3.bullet.collision.PhysicsCollisionListener -import com.jme3.bullet.collision.PhysicsCollisionEvent -import com.jme3.bullet.PhysicsTickListener +import monix.reactive.Observable +import monix.reactive.OverflowStrategy import monix.reactive.observers.Subscriber -import monix.execution.Ack.Continue -import monix.execution.Ack.Stop -import com.jme3.bullet.BulletAppState +import wow.doge.mygame.math.ImVector3f import wow.doge.mygame.state.MyBaseState -import monix.bio.UIO -import com.jme3.bullet.control.BetterCharacterControl -import com.jme3.scene.CameraNode -import com.jme3.scene.control.CameraControl.ControlDirection -import com.jme3.scene.control.Control -import com.jme3.input.controls.AnalogListener -import enumeratum._ case class ActionEvent(binding: Action, value: Boolean, tpf: Float) case class EnumActionEvent[T <: EnumEntry]( @@ -76,10 +78,12 @@ package object implicits { }) } - implicit class StateManagerExt(private val sm: AppStateManager) + implicit class StateManagerExt(private val asm: AppStateManager) extends AnyVal { def state[S <: AppState]()(implicit c: ClassTag[S]): S = - sm.getState(c.runtimeClass.asInstanceOf[Class[S]]) + asm.getState(c.runtimeClass.asInstanceOf[Class[S]]) + + // def appStates = asm.getStates() } @@ -117,6 +121,38 @@ package object implicits { } } + implicit class AssetManagerExt(private val am: AssetManager) extends AnyVal { + def registerLocator( + assetPath: os.RelPath, + locator: Class[_ <: AssetLocator] + ): Unit = { + am.registerLocator(assetPath.toString(), locator) + } + + def loadModel(assetPath: os.RelPath): Spatial = { + am.loadModel(assetPath.toString()) + } + } + + implicit class BulletAppStateExt(private val bas: BulletAppState) + extends AnyVal { + def physicsSpace = bas.getPhysicsSpace() + def speed = bas.getSpeed() + } + + implicit class BetterCharacterControlExt( + private val bcc: BetterCharacterControl + ) { + def withJumpForce(force: ImVector3f) = { + bcc.setJumpForce(force.mutable) + bcc + } + } + + implicit class SpatialExt[T <: Spatial](private val spat: T) extends AnyVal { + def asRef = Ref[Task].of(spat) + } + implicit class NodeExt[T <: Node](private val n: T) extends AnyVal { /** @@ -139,6 +175,11 @@ package object implicits { def observableChildren = Observable.fromIterable(n.getChildren().asScala) + /** + * A copy of the list of children of this node as a lazy list + * + * @return + */ def children = LazyList.from(n.getChildren().asScala) /** @@ -147,12 +188,24 @@ package object implicits { * @param lst */ def withChildren(lst: Spatial*): Node = { - for (c <- lst) n.withChild(c) + for (c <- lst) n.attachChild(c) n } def +=(spatial: Spatial) = n.attachChild(spatial) + def :+(spatial: Spatial) = { + n += spatial + n + } + + def -=(spatial: Spatial) = n.detachChild(spatial) + + def :-(spatial: Spatial) = { + n -= spatial + n + } + def depthFirst(cb: Spatial => Unit) = n.depthFirstTraversal(new SceneGraphVisitor() { override def visit(s: Spatial) = cb(s) @@ -333,6 +386,16 @@ package object implicits { inputManager } + def withEnumMappings[T <: EnumEntry]( + mappingEnum: Enum[T] + )(mappingFn: T => Seq[Trigger]): InputManager = { + for (entry <- mappingEnum.values) { + val mappings = mappingFn(entry) + inputManager.addMapping(entry.entryName, mappings: _*) + } + inputManager + } + def observableAction(mappingNames: String*): Observable[ActionEvent] = { Observable.create(OverflowStrategy.DropOld(10)) { sub => @@ -388,12 +451,6 @@ package object implicits { } } - // def enumObservableAction[T <: enumeratum.EnumEntry]( - // mappingNames: Enum[T] - // ): Observable[ActionEvent] = { - // observableAction2(mappingNames).doOnNext() - // } - def analogObservable(mappingNames: String*): Observable[AnalogEvent] = { Observable.create(OverflowStrategy.DropOld(50)) { sub => @@ -509,60 +566,60 @@ package object implicits { //TODO Create a typeclass for this def +=(anyObject: Any) = space.add(anyObject) - def +=(spatial: Spatial) = space.addAll(spatial) + def :+(anyObject: Any) = { + space.add(anyObject) + space + } + def :-(anyObject: Any) = { + space.remove(anyObject) + space + } - } + def +=(spatial: Spatial) = space.addAll(spatial) - implicit class AssetManagerExt(private val am: AssetManager) extends AnyVal { - def registerLocator( - assetPath: os.RelPath, - locator: Class[_ <: AssetLocator] - ): Unit = { - am.registerLocator(assetPath.toString(), locator) + def :+(spatial: Spatial) = { + space.addAll(spatial) + space } - def loadModel(assetPath: os.RelPath): Spatial = { - am.loadModel(assetPath.toString()) + def :-(spatial: Spatial) = { + space.removeAll(spatial) + space } - } - - implicit class BulletAppStateExt(private val bas: BulletAppState) - extends AnyVal { - def physicsSpace = bas.getPhysicsSpace() - def speed = bas.getSpeed() - } - implicit class BetterCharacterControlExt( - private val bcc: BetterCharacterControl - ) { - def withJumpForce(force: ImVector3f) = { - bcc.setJumpForce(force.mutable) - bcc - } } implicit class Vector3fExt(private val v: Vector3f) extends AnyVal { //TODO add more operations def +=(that: Vector3f) = v.addLocal(that) + def +=(f: Float) = v.addLocal(f, f, f) def +=(that: ImVector3f) = v.addLocal(that.x, that.y, that.z) def +=:(that: ImVector3f) = v += that def *=(that: Vector3f) = v.multLocal(that) + def *=(that: ImVector3f) = v.multLocal(that.x, that.y, that.z) + def *=:(that: ImVector3f) = v *= that def -=(that: Vector3f) = v.subtractLocal(that) + def -=(that: ImVector3f) = v.subtractLocal(that.x, that.y, that.z) + def -=:(that: ImVector3f) = v *= that def /=(that: Vector3f) = v.divideLocal(that) + def /=(that: ImVector3f) = v.divideLocal(that.mutable) + def /=:(that: ImVector3f) = v *= that def unary_- = v.negateLocal() def immutable = ImVector3f(v.x, v.y, v.z) } implicit class ImVector3fExt(private val v: ImVector3f) extends AnyVal { def +(that: ImVector3f) = v.copy(v.x + that.x, v.y + that.y, v.z + that.z) + def +(f: Float): ImVector3f = v.copy(v.x + f, v.y + f, v.z + f) def *(that: ImVector3f) = v.copy(v.x * that.x, v.y * that.y, v.z * that.z) def *(f: Float): ImVector3f = v.copy(v.x * f, v.y * f, v.z * f) // v * ImVector3f(f, f, f) def -(that: ImVector3f) = v.copy(v.x - that.x, v.y - that.y, v.z - that.z) + def -(f: Float): ImVector3f = v.copy(v.x - f, v.y - f, v.z - f) def /(that: ImVector3f) = v.copy(v.x / that.x, v.y / that.y, v.z / that.z) + def /(f: Float): ImVector3f = v.copy(v.x / f, v.y / f, v.z / f) def unary_- = v.copy(-v.x, -v.y, -v.z) - // def unary_-(that: ImVector3f) = this.copy(this.x, this.y, this.z) def mutable = new Vector3f(v.x, v.y, v.z) } @@ -572,18 +629,3 @@ package object implicits { // } } - -// Observable.create(OverflowStrategy.Unbounded) { sub => -// // val c = SingleAssignCancelable() -// val visitor = new SceneGraphVisitor { -// override def visit(s: Spatial): Unit = { -// sub.onNext(s) -// // if (sub.onNext(s) == Ack.Stop) -// // c.cancel() - -// } -// } -// n.depthFirstTraversal(visitor) -// // c := Cancelable(() => ???) -// // c -// Cancelable.empty diff --git a/src/main/scala/wow/doge/mygame/subsystems/events/EventBus.scala b/src/main/scala/wow/doge/mygame/subsystems/events/EventBus.scala index 3d8af9e..6c1696d 100644 --- a/src/main/scala/wow/doge/mygame/subsystems/events/EventBus.scala +++ b/src/main/scala/wow/doge/mygame/subsystems/events/EventBus.scala @@ -1,9 +1,10 @@ package wow.doge.mygame.events +import scala.reflect.ClassTag + import akka.actor.typed.ActorRef import akka.actor.typed.Behavior import akka.actor.typed.scaladsl.Behaviors -import scala.reflect.ClassTag import akka.event.EventStream /** diff --git a/src/main/scala/wow/doge/mygame/subsystems/events/EventsModule.scala b/src/main/scala/wow/doge/mygame/subsystems/events/EventsModule.scala index fb27dd1..8ab4495 100644 --- a/src/main/scala/wow/doge/mygame/subsystems/events/EventsModule.scala +++ b/src/main/scala/wow/doge/mygame/subsystems/events/EventsModule.scala @@ -1,35 +1,45 @@ -package wow.doge.mygame.events +package wow.doge.mygame.subsystems.events + +import scala.concurrent.duration._ import akka.actor.typed.ActorRef -import akka.actor.typed.SpawnProtocol -import wow.doge.mygame.implicits._ -import akka.actor.typed.scaladsl.AskPattern._ +import akka.actor.typed.ActorSystem +import akka.actor.typed.LogOptions import akka.actor.typed.Props +import akka.actor.typed.SpawnProtocol +import akka.actor.typed.SupervisorStrategy +import akka.actor.typed.scaladsl.Behaviors import akka.util.Timeout -import akka.actor.typed.Scheduler -import akka.actor.typed.LogOptions +import cats.effect.Resource import com.typesafe.scalalogging.{Logger => SLLogger} +import monix.bio.Task +import org.slf4j.event.Level import wow.doge.mygame.events.EventBus -import akka.actor.typed.scaladsl.Behaviors +import wow.doge.mygame.implicits._ import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent -import akka.actor.typed.SupervisorStrategy -trait EventsModule { - def spawnProtocol: ActorRef[SpawnProtocol.Command] - implicit def akkaScheduler: Scheduler - implicit def timeout: Timeout - def eventBusLogger = SLLogger[EventBus[_]] +class EventsModule2( + spawnProtocol: ActorSystem[SpawnProtocol.Command] +) { + implicit lazy val s = spawnProtocol.scheduler - lazy val tickEventBusTask = createEventBus[Events.Tick]("tickEventBus") + implicit lazy val timeout = Timeout(1.second) + + lazy val eventBusLogger = SLLogger[EventBus[_]] lazy val playerMovementEventBusTask = createEventBus[PlayerMovementEvent]("movementEventBus") - def createEventBus[T](busName: String) = + lazy val playerCameraEventBusTask = + createEventBus[PlayerCameraEvent]("playerCameraEventBus", Level.DEBUG) + + def createEventBus[T](busName: String, logLevel: Level = Level.DEBUG) = spawnProtocol.askL( SpawnProtocol.Spawn[EventBus.Command[T]]( Behaviors.logMessages( - logOptions = LogOptions().withLogger(eventBusLogger.underlying), + logOptions = LogOptions() + .withLevel(logLevel) + .withLogger(eventBusLogger.underlying), Behaviors .supervise(EventBus[T]()) .onFailure[Exception](SupervisorStrategy.restart) @@ -39,17 +49,17 @@ trait EventsModule { _ ) ) -} -object EventTypes { - type EventBus[T] = ActorRef[EventBus.Command[T]] -} -// val subscribingActor = -// spawnProtocol.askT( -// SpawnProtocol.Spawn[Events.PhysicsTick.type]( -// SubscribingActor(), -// "subscriber-1", -// Props.empty, -// _ -// ) -// ) + type EventBuses = ( + ActorRef[ + EventBus.Command[EntityMovementEvent.PlayerMovementEvent], + ], + ActorRef[EventBus.Command[PlayerCameraEvent]] + ) + + val resource: Resource[Task, EventBuses] = + Resource.liftF(for { + playerMovementEventBus <- playerMovementEventBusTask + playerCameraEventBus <- playerCameraEventBusTask + } yield (playerMovementEventBus, playerCameraEventBus)) +} diff --git a/src/main/scala/wow/doge/mygame/subsystems/events/EventsModule2.scala b/src/main/scala/wow/doge/mygame/subsystems/events/EventsModule2.scala deleted file mode 100644 index 448db21..0000000 --- a/src/main/scala/wow/doge/mygame/subsystems/events/EventsModule2.scala +++ /dev/null @@ -1,64 +0,0 @@ -package wow.doge.mygame.subsystems.events - -import akka.actor.typed.ActorRef -import akka.actor.typed.SpawnProtocol -import wow.doge.mygame.implicits._ -import akka.actor.typed.Props -import akka.actor.typed.LogOptions -import com.typesafe.scalalogging.{Logger => SLLogger} -import wow.doge.mygame.events.EventBus -import akka.actor.typed.scaladsl.Behaviors -import scala.concurrent.duration._ -import akka.util.Timeout -import akka.actor.typed.SupervisorStrategy -import cats.effect.Resource -import akka.actor.typed.ActorSystem -import monix.bio.Task -import org.slf4j.event.Level -import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent - -class EventsModule2( - spawnProtocol: ActorSystem[SpawnProtocol.Command] -) { - private implicit lazy val s = spawnProtocol.scheduler - - private implicit lazy val timeout = Timeout(1.second) - - private lazy val eventBusLogger = SLLogger[EventBus[_]] - - private lazy val playerMovementEventBusTask = - createEventBus[PlayerMovementEvent]("movementEventBus") - - private lazy val playerCameraEventBusTask = - createEventBus[PlayerCameraEvent]("playerCameraEventBus", Level.DEBUG) - - def createEventBus[T](busName: String, logLevel: Level = Level.DEBUG) = - spawnProtocol.askL( - SpawnProtocol.Spawn[EventBus.Command[T]]( - Behaviors.logMessages( - logOptions = LogOptions() - .withLevel(logLevel) - .withLogger(eventBusLogger.underlying), - Behaviors - .supervise(EventBus[T]()) - .onFailure[Exception](SupervisorStrategy.restart) - ), - busName, - Props.empty, - _ - ) - ) - - type EventBuses = ( - ActorRef[ - EventBus.Command[EntityMovementEvent.PlayerMovementEvent], - ], - ActorRef[EventBus.Command[PlayerCameraEvent]] - ) - - val resource: Resource[Task, EventBuses] = - Resource.liftF(for { - playerMovementEventBus <- playerMovementEventBusTask - playerCameraEventBus <- playerCameraEventBusTask - } yield (playerMovementEventBus, playerCameraEventBus)) -} diff --git a/src/main/scala/wow/doge/mygame/subsystems/moddingsystem/ModdingSystem.scala b/src/main/scala/wow/doge/mygame/subsystems/moddingsystem/ModdingSystem.scala index 983477a..e225134 100644 --- a/src/main/scala/wow/doge/mygame/subsystems/moddingsystem/ModdingSystem.scala +++ b/src/main/scala/wow/doge/mygame/subsystems/moddingsystem/ModdingSystem.scala @@ -1,5 +1,6 @@ package wow.doge.mygame.subsystems.moddingsystem import java.io.FileNotFoundException +import java.nio.file.NoSuchFileException import scala.collection.View import scala.collection.immutable.ArraySeq @@ -11,7 +12,9 @@ import io.circe.generic.semiauto._ import io.circe.parser._ import monix.bio.IO import monix.bio.UIO -import java.nio.file.NoSuchFileException +import monix.reactive.Consumer +import monix.reactive.Observable +import wow.doge.mygame.utils.IOUtils import io.circe.generic.JsonCodec @JsonCodec @@ -20,6 +23,9 @@ final case class Test1(hello1: String, hello2: String) final case class Test2(hello1: String) final case class Plugin(name: String, priority: Int) object Plugin { + // @annotation.nowarn( + // "msg=Block result was adapted via implicit conversion" + // ) implicit val pluginFormat: Decoder[Plugin] = deriveDecoder } @@ -90,16 +96,29 @@ object ModdingSystem { case (p, Right(value)) => Right(p -> value) } - def mergePluginData(plugins: View[(Plugin, Json)]) = { - plugins.foldLeft(Json.fromString("empty")) { - case (json, that) => - that match { - case (p, io.circe.Json.Null) => json //ignore null values - case (p, value) => json.deepMerge(value) - } + def foldMerge(iterable: Iterable[Json]) = + iterable.foldLeft(Json.fromString("empty")) { + case (json, io.circe.Json.Null) => json //ignore null values + case (json, value) => json.deepMerge(value) } + + def mergePluginData(plugins: View[(Plugin, Json)]) = { + foldMerge(plugins.map { + case (p, json) => json + }) } + def mergePluginDataConsumer = + Consumer.foldLeft[Json, Json](Json.fromString("empty")) { + case (json, io.circe.Json.Null) => json + case (json, that) => json.deepMerge(that) + } + + def loadBalancedPluginDataMerger = + Consumer + .loadBalance(parallelism = 2, mergePluginDataConsumer) + .map(foldMerge) + // def test = // for { // filePaths <- Task(findPluginFiles(os.pwd)) @@ -118,7 +137,16 @@ object ModdingSystem { plugins <- IO.fromTryEither(readPluginsList(wd)) (readFailures, readSuccesses) <- UIO(findAndReadPluginFiles(wd, plugins)) (parseFailures, parseSuccesses) <- UIO(parsePluginFiles(readSuccesses)) - res <- UIO(mergePluginData(parseSuccesses)) + // res <- UIO(mergePluginData(parseSuccesses)) + res <- + IOUtils + .toIO( + Observable + .fromIterable(parseSuccesses) + .map { case (p, json) => json } + .consumeWith(loadBalancedPluginDataMerger) + ) + .onErrorHandle(e => GenericError) _ <- UIO { println(s"Read Successes = ${readSuccesses.to(Seq)}") println(s"Read Failures = ${readFailures.to(Seq)}") @@ -138,5 +166,4 @@ object ModdingSystem { // def test3(wd: os.Path = os.pwd) = { // (readPluginsList(os.pwd).toValidatedNec) // } - ; } diff --git a/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptActor.scala b/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptActor.scala index 3d114e3..f330603 100644 --- a/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptActor.scala +++ b/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptActor.scala @@ -1,21 +1,22 @@ package wow.doge.mygame.state -import akka.actor.typed.scaladsl.Behaviors -import ammonite.Main +import javax.script.ScriptEngine +import javax.script.ScriptEngineManager + import akka.actor.typed.ActorRef -import ammonite.runtime.Storage.Folder -import ammonite.main.Defaults import akka.actor.typed.Behavior +import akka.actor.typed.LogOptions import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors +import ammonite.Main +import ammonite.main.Defaults +import ammonite.runtime.Storage.Folder import ammonite.util.Res.Success -import javax.script.ScriptEngine -import javax.script.ScriptEngineManager -import groovy.util.GroovyScriptEngine import cats.implicits._ -import akka.actor.typed.LogOptions -import org.slf4j.event.Level -import com.typesafe.scalalogging.Logger import com.softwaremill.tagging._ +import com.typesafe.scalalogging.Logger +import groovy.util.GroovyScriptEngine +import org.slf4j.event.Level object ScriptActor { trait Kotlin diff --git a/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptCachingActor.scala b/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptCachingActor.scala index 6205320..7e6e3c6 100644 --- a/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptCachingActor.scala +++ b/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptCachingActor.scala @@ -1,19 +1,20 @@ package wow.doge.mygame.scriptsystem +import scala.util.Failure +import scala.util.Success + +import akka.actor.typed.ActorRef +import akka.actor.typed.Behavior +import akka.actor.typed.LogOptions +import akka.actor.typed.SupervisorStrategy +import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.PoolRouter import akka.actor.typed.scaladsl.Routers -import wow.doge.mygame.state.ScriptActor -import akka.actor.typed.ActorRef -import akka.actor.typed.scaladsl.ActorContext -import akka.actor.typed.Behavior import akka.util.Timeout -import scala.util.Success -import scala.util.Failure -import akka.actor.typed.SupervisorStrategy -import akka.actor.typed.LogOptions -import org.slf4j.event.Level import com.typesafe.scalalogging.Logger +import org.slf4j.event.Level +import wow.doge.mygame.state.ScriptActor object ScriptCachingActor { diff --git a/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptSystemModule.scala b/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptSystemModule.scala index b574f4d..04e3171 100644 --- a/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptSystemModule.scala +++ b/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptSystemModule.scala @@ -1,23 +1,65 @@ package wow.doge.mygame.subsystems.scriptsystem -import wow.doge.mygame.utils.AkkaUtils -import cats.effect.Resource -import wow.doge.mygame.scriptsystem.ScriptCachingActor import akka.actor.typed.ActorRef +import akka.actor.typed.Scheduler import akka.actor.typed.SpawnProtocol import akka.util.Timeout -import akka.actor.typed.Scheduler +import cats.effect.Resource +import wow.doge.mygame.scriptsystem.ScriptCachingActor +import wow.doge.mygame.utils.AkkaUtils +import monix.bio.Task +/** + * Scripts can either be searched and compiled at startup (Eager mode) + * or compiled on demand (Lazy mode) + */ +sealed trait ScriptInitMode +object ScriptInitMode { + case object Eager extends ScriptInitMode + case object Lazy extends ScriptInitMode +} class ScriptSystemResource( path: os.Path, - spawnProtocol: ActorRef[SpawnProtocol.Command] + spawnProtocol: ActorRef[SpawnProtocol.Command], + mode: ScriptInitMode = ScriptInitMode.Lazy )(implicit timeout: Timeout, scheduler: Scheduler) { - def make = - Resource.liftF( - AkkaUtils.spawnActorL( - spawnProtocol, - "scriptCachingActor", - ScriptCachingActor() - ) + val make = { + // throw new Exception("boom") + findScriptFiles(os.pwd / "assets" / "scripts") + + lazy val scriptCacheActor = AkkaUtils.spawnActorL( + spawnProtocol, + "scriptCachingActor", + ScriptCachingActor() + ) + + Resource.liftF(scriptCacheActor) + } + + val init = for { + scriptFiles <- Task(findScriptFiles(os.pwd / "assets" / "scripts")) + scriptCacheActor <- AkkaUtils.spawnActorL( + spawnProtocol, + "scriptCachingActor", + ScriptCachingActor() ) + } yield (scriptCacheActor) + + def findScriptFiles(wd: os.Path) = + os.walk + .stream(wd) + .filter(p => + os.isFile(p) && + (p.ext == "sc" || (p.baseName + "." + p.ext) + .contains(".main.kts") || p.ext == "groovy") + ) + .toList + + // def findExternalScriptFiles = + // findScriptFiles(os.pwd / "assets" / "scripts") + // def findInternalScriptFiles = + // findScriptFiles((os.resource / "assets" / "scripts")) + + // def finalInternalScriptFiles = } +// pwd / 'src / 'main / 'resources / 'assets / 'scripts diff --git a/src/main/scala/wow/doge/mygame/utils/AkkaUtils.scala b/src/main/scala/wow/doge/mygame/utils/AkkaUtils.scala index df41940..d36c913 100644 --- a/src/main/scala/wow/doge/mygame/utils/AkkaUtils.scala +++ b/src/main/scala/wow/doge/mygame/utils/AkkaUtils.scala @@ -1,11 +1,11 @@ package wow.doge.mygame.utils +import akka.actor.typed.ActorRef +import akka.actor.typed.Behavior import akka.actor.typed.Props -import akka.util.Timeout import akka.actor.typed.Scheduler -import akka.actor.typed.ActorRef import akka.actor.typed.SpawnProtocol -import akka.actor.typed.Behavior +import akka.util.Timeout import wow.doge.mygame.implicits._ object AkkaUtils { diff --git a/src/main/scala/wow/doge/mygame/utils/JFXConsoleStream.scala b/src/main/scala/wow/doge/mygame/utils/JFXConsoleStream.scala index c4c21eb..e2c5546 100644 --- a/src/main/scala/wow/doge/mygame/utils/JFXConsoleStream.scala +++ b/src/main/scala/wow/doge/mygame/utils/JFXConsoleStream.scala @@ -1,11 +1,12 @@ package wow.doge.mygame.utils -import java.io.PrintStream -import java.io.OutputStream import java.io.ByteArrayOutputStream -import scalafx.scene.control.TextArea +import java.io.OutputStream +import java.io.PrintStream + import cats.effect.Resource import monix.bio.Task +import scalafx.scene.control.TextArea trait JFXConsoleStreamable[T] { def println(inst: T, text: String): Unit