Browse Source

many changes

master
Rohan Sircar 4 years ago
parent
commit
c93d0704b5
  1. 17
      build.sbt
  2. 2
      src/main/resources/dep.sc
  3. 3
      src/main/resources/hello.groovy
  4. 36
      src/main/resources/hello.main.kts
  5. 35
      src/main/resources/hello.sc
  6. 5
      src/main/resources/hello2.main.kts
  7. 108
      src/main/resources/hello2.sc
  8. 3
      src/main/scala/com/jme3/input/package.scala
  9. 3
      src/main/scala/com/jme3/syntax/package.scala
  10. 22
      src/main/scala/org/slf4j/impl/StaticLoggerBuilder.scala
  11. 27
      src/main/scala/wow/doge/mygame/ActorSystemModule.scala
  12. 121
      src/main/scala/wow/doge/mygame/Main.scala
  13. 139
      src/main/scala/wow/doge/mygame/MainApp.scala
  14. 120
      src/main/scala/wow/doge/mygame/MainModule.scala
  15. 2
      src/main/scala/wow/doge/mygame/executors/ExecutorsModule.scala
  16. 26
      src/main/scala/wow/doge/mygame/executors/GUIExecutor.scala
  17. 2
      src/main/scala/wow/doge/mygame/executors/Schedulers.scala
  18. 14
      src/main/scala/wow/doge/mygame/game/GameApp.scala
  19. 35
      src/main/scala/wow/doge/mygame/game/GameApp2.scala
  20. 38
      src/main/scala/wow/doge/mygame/game/GameAppActor.scala
  21. 42
      src/main/scala/wow/doge/mygame/game/GameModule.scala
  22. 43
      src/main/scala/wow/doge/mygame/game/GameSystemsInitializer.scala
  23. 4
      src/main/scala/wow/doge/mygame/game/appstates/MyBaseState.scala
  24. 12
      src/main/scala/wow/doge/mygame/game/appstates/PlayerMovementState.scala
  25. 17
      src/main/scala/wow/doge/mygame/game/appstates/ScriptingEngineState.scala
  26. 10
      src/main/scala/wow/doge/mygame/game/appstates/TestAppState.scala
  27. 2
      src/main/scala/wow/doge/mygame/game/components/Position.scala
  28. 31
      src/main/scala/wow/doge/mygame/game/nodes/PlayerActorSupervisor.scala
  29. 2
      src/main/scala/wow/doge/mygame/game/nodes/PlayerCameraActor.scala
  30. 60
      src/main/scala/wow/doge/mygame/game/nodes/PlayerController.scala
  31. 12
      src/main/scala/wow/doge/mygame/game/nodes/PlayerEventListeners.scala
  32. 135
      src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala
  33. 3
      src/main/scala/wow/doge/mygame/game/subsystems/input/InputEnums.scala
  34. 57
      src/main/scala/wow/doge/mygame/game/subsystems/level/DefaultGameLevel.scala
  35. 34
      src/main/scala/wow/doge/mygame/game/subsystems/level/Level.scala
  36. 6
      src/main/scala/wow/doge/mygame/game/subsystems/movement/CanMove.scala
  37. 32
      src/main/scala/wow/doge/mygame/game/subsystems/movement/MovementActor.scala
  38. 5
      src/main/scala/wow/doge/mygame/implicits/EntityQuery.scala
  39. 208
      src/main/scala/wow/doge/mygame/implicits/package.scala
  40. 3
      src/main/scala/wow/doge/mygame/subsystems/events/EventBus.scala
  41. 68
      src/main/scala/wow/doge/mygame/subsystems/events/EventsModule.scala
  42. 64
      src/main/scala/wow/doge/mygame/subsystems/events/EventsModule2.scala
  43. 47
      src/main/scala/wow/doge/mygame/subsystems/moddingsystem/ModdingSystem.scala
  44. 21
      src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptActor.scala
  45. 19
      src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptCachingActor.scala
  46. 66
      src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptSystemModule.scala
  47. 6
      src/main/scala/wow/doge/mygame/utils/AkkaUtils.scala
  48. 7
      src/main/scala/wow/doge/mygame/utils/JFXConsoleStream.scala

17
build.sbt

@ -74,7 +74,8 @@ lazy val root = (project in file(".")).settings(
"org.typelevel" %% "cats-core" % "2.1.1", "org.typelevel" %% "cats-core" % "2.1.1",
"org.typelevel" %% "cats-effect" % "2.1.4", "org.typelevel" %% "cats-effect" % "2.1.4",
"io.monix" %% "monix" % "3.2.2", "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-core" % "0.13.0",
"io.circe" %% "circe-generic" % "0.13.0", "io.circe" %% "circe-generic" % "0.13.0",
"com.softwaremill.sttp.client" %% "core" % "2.2.5", "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", "org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.0-RC1",
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.2", "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
"io.circe" %% "circe-config" % "0.8.0", "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 // Determine OS version of JavaFX binaries
@ -104,12 +106,20 @@ lazy val root = (project in file(".")).settings(
"UTF-8", "UTF-8",
"-deprecation", "-deprecation",
"-feature", "-feature",
"-language:existentials",
"-language:experimental.macros",
"-language:higherKinds",
"-language:implicitConversions",
"-unchecked", "-unchecked",
"-Xlint", "-Xlint",
"-Ywarn-numeric-widen", "-Ywarn-numeric-widen",
"-Ymacro-annotations", "-Ymacro-annotations",
"-Xlint:byname-implicit",
// "-Xlint:byname-implicit",
// "utf-8", // Specify character encoding used by source files. // "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. "-explaintypes" // Explain type errors in more detail.
), ),
javacOptions ++= Seq("-source", "11", "-target", "11"), 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 // To learn more about multi-project builds, head over to the official sbt
// documentation at http://www.scala-sbt.org/documentation.html // documentation at http://www.scala-sbt.org/documentation.html
addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1") addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1")
ThisBuild / scalafixDependencies += "com.github.liancheng" %% "organize-imports" % "0.4.3"

2
src/main/resources/dep.sc

@ -1,2 +0,0 @@
// println("hello from dep")
class Test(x: Int)

3
src/main/resources/hello.groovy

@ -1,3 +0,0 @@
println "hello"
this

36
src/main/resources/hello.main.kts

@ -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()

35
src/main/resources/hello.sc

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

5
src/main/resources/hello2.main.kts

@ -1,5 +0,0 @@
println("hello from dep")
class Test(val x: Int)
var x = 2

108
src/main/resources/hello2.sc

@ -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()

3
src/main/scala/com/jme3/input/package.scala

@ -1,6 +1,7 @@
package com.jme3 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. * Created by Brandon Barker on 6/21/17.

3
src/main/scala/com/jme3/syntax/package.scala

@ -1,13 +1,12 @@
package com.jme3 package com.jme3
/** /**
* Created by Brandon Barker on 6/21/17. * Created by Brandon Barker on 6/21/17.
*/ */
package object syntax { package object syntax {
@specialized def discard[A](evaluateForSideEffectOnly: A): Unit = { @specialized def discard[A](evaluateForSideEffectOnly: A): Unit = {
val _: A = evaluateForSideEffectOnly
val _ = evaluateForSideEffectOnly
() //Return unit to prevent warning due to discarding value () //Return unit to prevent warning due to discarding value
} }

22
src/main/scala/org/slf4j/impl/StaticLoggerBuilder.scala

@ -1,18 +1,22 @@
package org.slf4j.impl 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.ExecutionContext
import scala.concurrent.duration._
import _root_.monix.execution.Scheduler import _root_.monix.execution.Scheduler
import cats.arrow.FunctionK
import _root_.monix.execution.Scheduler.Implicits.global 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.json.Formatter
import io.odin.slf4j.OdinLoggerBinder
import io.odin.syntax._
//effect type should be specified inbefore //effect type should be specified inbefore
//log line will be recorded right after the call with no suspension //log line will be recorded right after the call with no suspension

27
src/main/scala/wow/doge/mygame/ActorSystemModule.scala

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

121
src/main/scala/wow/doge/mygame/Main.scala

@ -1,24 +1,21 @@
package wow.doge.mygame 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.effect.ExitCode
import cats.implicits._ import cats.implicits._
import com.softwaremill.macwire._ import com.softwaremill.macwire._
import scala.concurrent.duration._
import monix.bio.BIOApp
import monix.bio.UIO
import io.odin._ import io.odin._
import wow.doge.mygame.game.GameAppResource
import io.odin.json.Formatter 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 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 { object Main extends BIOApp with MainModule {
import java.util.logging.{Logger => JLogger, Level} import java.util.logging.{Logger => JLogger, Level}
JLogger.getLogger("").setLevel(Level.SEVERE) JLogger.getLogger("").setLevel(Level.SEVERE)
@ -41,19 +38,36 @@ object Main extends BIOApp with MainModule {
// akkaScheduler = actorSystemResource2.scheduler // akkaScheduler = actorSystemResource2.scheduler
// consoleTextArea <- Resource.liftF(Task(new TextArea())) // consoleTextArea <- Resource.liftF(Task(new TextArea()))
// consoleStream <- wireWith(JFXConsoleStream.textAreaStream _) // consoleStream <- wireWith(JFXConsoleStream.textAreaStream _)
(gameApp, gameAppFib) <- {
(gameApp) <- {
// new BulletAppState() // new BulletAppState()
// bas.setThreadingType(Thr) // bas.setThreadingType(Thr)
// gameAppResource(new StatsAppState()) // 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 // b1 = playerMovementEventBus
// b2 = playerCameraEventBus // 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( // def createPlayerController(
// playerMovementEventBus: ActorRef[ // playerMovementEventBus: ActorRef[
@ -145,7 +112,7 @@ object Main extends BIOApp with MainModule {
// ) // )
// )(()) // )(())
appResource appResource
.use(_.join)
.use(_ => Task.unit)
.onErrorHandle(_.printStackTrace()) .onErrorHandle(_.printStackTrace())
.as(ExitCode.Success) .as(ExitCode.Success)
} }

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

120
src/main/scala/wow/doge/mygame/MainModule.scala

@ -1,41 +1,13 @@
package wow.doge.mygame 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.ActorSystem
import akka.actor.typed.SpawnProtocol
import cats.effect.Resource
import io.odin.Logger
import monix.bio.Task import monix.bio.Task
import wow.doge.mygame.game.GameModule
import io.odin._
import io.odin.syntax._
import wow.doge.mygame.executors.ExecutorsModule 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 { 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( def actorSystemResource2(
logger: Logger[Task] logger: Logger[Task]
@ -43,93 +15,11 @@ trait MainModule extends GameModule with ExecutorsModule {
Resource.make(logger.info("Creating Actor System") >> Task { Resource.make(logger.info("Creating Actor System") >> Task {
ActorSystem( ActorSystem(
SpawnProtocol(), SpawnProtocol(),
name = "GameActorSystem2"
name = "GameActorSystem"
) )
})(sys => })(sys =>
logger.info("Shutting down actor system") >> Task( logger.info("Shutting down actor system") >> Task(
sys.terminate() 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
}
)
} }

2
src/main/scala/wow/doge/mygame/executors/ExecutorsModule.scala

@ -1,7 +1,7 @@
package wow.doge.mygame.executors package wow.doge.mygame.executors
import monix.bio.Task
import cats.effect.Resource import cats.effect.Resource
import monix.bio.Task
import monix.execution.Scheduler import monix.execution.Scheduler
trait ExecutorsModule { trait ExecutorsModule {

26
src/main/scala/wow/doge/mygame/executors/GUIExecutor.scala

@ -1,23 +1,21 @@
package wow.doge.mygame.executors 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.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 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 javafx.application.Platform
import monix.execution.Scheduler import monix.execution.Scheduler
import scala.concurrent.ExecutionContext
import java.util.concurrent.Executor
// First we wrap invokeLater/runLater as an ExecutorService // First we wrap invokeLater/runLater as an ExecutorService
trait GUIExecutorService extends AbstractExecutorService { trait GUIExecutorService extends AbstractExecutorService {

2
src/main/scala/wow/doge/mygame/executors/Schedulers.scala

@ -1,8 +1,8 @@
package wow.doge.mygame.executors package wow.doge.mygame.executors
import com.typesafe.scalalogging.Logger
import monix.execution.Scheduler import monix.execution.Scheduler
import monix.execution.UncaughtExceptionReporter import monix.execution.UncaughtExceptionReporter
import com.typesafe.scalalogging.Logger
final case class Schedulers( final case class Schedulers(
blockingIO: Scheduler = Scheduler blockingIO: Scheduler = Scheduler

14
src/main/scala/wow/doge/mygame/game/GameApp.scala

@ -1,18 +1,18 @@
package wow.doge.mygame.game 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 com.jme3.app.state.AppState
import monix.execution.{CancelablePromise => Promise}
import monix.execution.CancelableFuture
import monix.bio.Task import monix.bio.Task
import monix.execution.CancelableFuture
import monix.execution.Scheduler 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.MulticastStrategy
import monix.reactive.Observable 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 import wow.doge.mygame.executors.Schedulers
class GameApp( class GameApp(

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

38
src/main/scala/wow/doge/mygame/game/GameAppActor.scala

@ -1,27 +1,15 @@
package wow.doge.mygame.game 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.ActorRef
import akka.actor.typed.Scheduler
import akka.actor.typed.SpawnProtocol
import akka.actor.typed.scaladsl.Behaviors
import io.odin.Logger import io.odin.Logger
import monix.bio.Task 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 { object GameAppActor {
import Methods._
sealed trait Command sealed trait Command
case object ApplicationStarted extends Command case object ApplicationStarted extends Command
@ -39,22 +27,6 @@ object GameAppActor {
Behaviors.setup[Command] { ctx => Behaviors.setup[Command] { ctx =>
ctx.log.info("Hello from GameAppActor") 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 => Behaviors.receiveMessage { msg =>
msg match { msg match {
case Stop => case Stop =>

42
src/main/scala/wow/doge/mygame/game/GameModule.scala

@ -1,28 +1,28 @@
package wow.doge.mygame.game package wow.doge.mygame.game
import akka.actor.typed.ActorRef
import akka.actor.typed.SpawnProtocol
import cats.effect.Resource import cats.effect.Resource
import com.jme3.app.StatsAppState
import com.jme3.system.AppSettings import com.jme3.system.AppSettings
import monix.bio.Task
import io.odin.Logger 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.Fiber
import monix.bio.IO
import monix.bio.Task
import monix.execution.Scheduler import monix.execution.Scheduler
import com.jme3.app.StatsAppState
import wow.doge.mygame.executors.Schedulers import wow.doge.mygame.executors.Schedulers
import wow.doge.mygame.game.subsystems.input.GameInputHandler
class GameAppResource( class GameAppResource(
logger: Logger[Task], logger: Logger[Task],
jmeScheduler: Scheduler, jmeScheduler: Scheduler,
schedulers: Schedulers schedulers: Schedulers
) { ) {
def get: Resource[Task, (GameApp, Fiber[Throwable, Unit])] =
def get: Resource[Task, (GameApp2, Fiber[Throwable, Unit])] =
Resource.make( Resource.make(
for { for {
_ <- logger.info("Creating game app") _ <- logger.info("Creating game app")
app <- Task(new GameApp(schedulers, new StatsAppState())) app <- Task(new GameApp(schedulers, new StatsAppState()))
_ <- Task {
app2 <- Task {
val settings = new AppSettings(true) val settings = new AppSettings(true)
settings.setVSync(true) settings.setVSync(true)
settings.setUseInput(true) settings.setUseInput(true)
@ -30,11 +30,31 @@ class GameAppResource(
// settings.setFrameRate(250) // settings.setFrameRate(250)
app.setSettings(settings) app.setSettings(settings)
// JMERunner.runner = app // 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) )(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 { trait GameModule {

43
src/main/scala/wow/doge/mygame/game/GameSystemsInitializer.scala

@ -3,30 +3,34 @@ package wow.doge.mygame.game
import scala.concurrent.duration._ import scala.concurrent.duration._
import akka.actor.typed.ActorRef import akka.actor.typed.ActorRef
import akka.actor.typed.ActorSystem
import akka.actor.typed.Scheduler import akka.actor.typed.Scheduler
import akka.actor.typed.SpawnProtocol import akka.actor.typed.SpawnProtocol
import akka.util.Timeout 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.asset.plugins.ZipLocator
import com.jme3.bullet.BulletAppState 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.macwire._
import com.softwaremill.tagging._ import com.softwaremill.tagging._
import io.odin.Logger import io.odin.Logger
import monix.bio.IO
import monix.bio.Task import monix.bio.Task
import monix.reactive.Consumer import monix.reactive.Consumer
import wow.doge.mygame.events.EventBus import wow.doge.mygame.events.EventBus
import wow.doge.mygame.game.nodes.Player import wow.doge.mygame.game.nodes.Player
import wow.doge.mygame.game.nodes.PlayerController import wow.doge.mygame.game.nodes.PlayerController
import wow.doge.mygame.game.subsystems.input.GameInputHandler 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.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 wow.doge.mygame.math.ImVector3f
import monix.bio.IO
import wow.doge.mygame.subsystems.events.EntityMovementEvent import wow.doge.mygame.subsystems.events.EntityMovementEvent
import akka.actor.typed.ActorSystem
import wow.doge.mygame.subsystems.events.PlayerCameraEvent import wow.doge.mygame.subsystems.events.PlayerCameraEvent
import wow.doge.mygame.subsystems.movement.ImMovementActor
import wow.doge.mygame.utils.IOUtils
class GameSystemsInitializer( class GameSystemsInitializer(
spawnProtocol: ActorSystem[SpawnProtocol.Command], spawnProtocol: ActorSystem[SpawnProtocol.Command],
@ -35,15 +39,22 @@ class GameSystemsInitializer(
playerMovementEventBus: ActorRef[ playerMovementEventBus: ActorRef[
EventBus.Command[EntityMovementEvent.PlayerMovementEvent] 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) implicit val timeout: Timeout = Timeout(1.second)
import GameSystemsInitializer._ import GameSystemsInitializer._
implicit val akkaScheduler: Scheduler = spawnProtocol.scheduler 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 bulletAppState = new BulletAppState()
// lazy val playerMovementEventBus = eventBuses.playerMovementEventBusTask // lazy val playerMovementEventBus = eventBuses.playerMovementEventBusTask
@ -51,15 +62,16 @@ class GameSystemsInitializer(
for { for {
_ <- loggerL.info("Initializing Systems") _ <- loggerL.info("Initializing Systems")
// playerMovementEventBus <- playerMovementEventBusTask // playerMovementEventBus <- playerMovementEventBusTask
_ <- Task(app.stateManager.attach(bulletAppState))
_ <- Task(stateManager.attach(bulletAppState))
_ <- Task( _ <- Task(
app.assetManager.registerLocator(
assetManager.registerLocator(
// "src/main/resources/assets/town.zip", // "src/main/resources/assets/town.zip",
(os.rel / "src" / "main" / "resources" / "assets" / "town.zip"),
(os.rel / "assets" / "town.zip"),
classOf[ZipLocator] classOf[ZipLocator]
) )
) )
_ <- app.enqueueL(() => DefaultGameLevel(app, bulletAppState))
// _ <- app.enqueueL(() => DefaultGameLevel(app, bulletAppState))
_ <- wireWith(createPlayerController _).startAndForget _ <- wireWith(createPlayerController _).startAndForget
_ <- wire[GameInputHandler.Props].begin _ <- wire[GameInputHandler.Props].begin
@ -71,8 +83,11 @@ class GameSystemsInitializer(
// ], // ],
// playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]] // playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]]
): IO[PlayerController.Error, Unit] = { ): IO[PlayerController.Error, Unit] = {
@annotation.unused
val playerPos = ImVector3f.ZERO val playerPos = ImVector3f.ZERO
@annotation.unused
val playerNode = None.taggedWith[Player] val playerNode = None.taggedWith[Player]
@annotation.unused
val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o" val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
wire[PlayerController.Props].create wire[PlayerController.Props].create
} }

4
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.Application
import com.jme3.app.SimpleApplication import com.jme3.app.SimpleApplication
import com.jme3.app.state.AppState import com.jme3.app.state.AppState
import com.jme3.scene.Node
import com.jme3.app.state.BaseAppState 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.EntityData
import com.simsilica.es.base.DefaultEntityData import com.simsilica.es.base.DefaultEntityData
import com.jme3.scene.Spatial
trait MyBaseState extends BaseAppState { trait MyBaseState extends BaseAppState {

12
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 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.InputManager
import com.jme3.input.KeyInput import com.jme3.input.KeyInput
import com.jme3.input.controls.KeyTrigger import com.jme3.input.controls.KeyTrigger
import com.jme3.math.Vector3f 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 com.jme3.scene.Geometry
import akka.actor.typed.scaladsl.TimerScheduler
import wow.doge.mygame.implicits._ import wow.doge.mygame.implicits._
import wow.doge.mygame.subsystems.movement.ImMovementActor import wow.doge.mygame.subsystems.movement.ImMovementActor

17
src/main/scala/wow/doge/mygame/game/appstates/ScriptingEngineState.scala

@ -1,17 +1,18 @@
package wow.doge.mygame.state package wow.doge.mygame.state
import ammonite.runtime.Storage.Folder
import ammonite.main.Defaults
import ammonite.Main
import javax.script.ScriptEngine 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.AbstractBehavior
import akka.actor.typed.scaladsl.ActorContext 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.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( class ScriptingEngineState(
sse: ScalaScriptingEngine, sse: ScalaScriptingEngine,

10
src/main/scala/wow/doge/mygame/game/appstates/TestAppState.scala

@ -1,13 +1,13 @@
package wow.doge.mygame.state 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.material.Material
import com.jme3.math.ColorRGBA import com.jme3.math.ColorRGBA
import com.jme3.asset.AssetManager
import com.jme3.math.Vector3f 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( class TestAppState(
// private var _entity: Option[EntityData] = Some(new DefaultEntityData()) // private var _entity: Option[EntityData] = Some(new DefaultEntityData())
) extends MyBaseState { ) extends MyBaseState {

2
src/main/scala/wow/doge/mygame/game/components/Position.scala

@ -1,6 +1,6 @@
package wow.doge.mygame.components package wow.doge.mygame.components
import com.simsilica.es.EntityComponent;
import com.simsilica.es.EntityComponent
import wow.doge.mygame.math.ImVector3f import wow.doge.mygame.math.ImVector3f
final case class Position(location: ImVector3f) extends EntityComponent final case class Position(location: ImVector3f) extends EntityComponent

31
src/main/scala/wow/doge/mygame/game/nodes/PlayerActorSupervisor.scala

@ -1,30 +1,29 @@
package wow.doge.mygame.game.nodes 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 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 akka.actor.typed.Behavior
import scala.concurrent.duration._
import akka.actor.typed.LogOptions import akka.actor.typed.LogOptions
import org.slf4j.event.Level
import com.typesafe.scalalogging.Logger
import akka.actor.typed.SupervisorStrategy 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 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.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 { object PlayerActorSupervisor {
sealed trait Command sealed trait Command
final case class Props( final case class Props(
app: GameApp,
enqueueR: Function1[() => Unit, Unit],
camNode: CameraNode, camNode: CameraNode,
playerMovementEventBus: ActorRef[ playerMovementEventBus: ActorRef[
EventBus.Command[PlayerMovementEvent] EventBus.Command[PlayerMovementEvent]
@ -47,7 +46,7 @@ object PlayerActorSupervisor {
Behaviors Behaviors
.supervise( .supervise(
ImMovementActor ImMovementActor
.Props(app, movable, playerMovementEventBus)
.Props(enqueueR, movable, playerMovementEventBus)
.create .create
) )
.onFailure[Exception](SupervisorStrategy.restart), .onFailure[Exception](SupervisorStrategy.restart),
@ -70,7 +69,7 @@ object PlayerActorSupervisor {
ctx.spawn( ctx.spawn(
Behaviors Behaviors
.supervise( .supervise(
PlayerCameraEventListener(camNode, app.enqueueR)
PlayerCameraEventListener(camNode, enqueueR)
) )
.onFailure[Exception](SupervisorStrategy.restart), .onFailure[Exception](SupervisorStrategy.restart),
"playerCameraHandler" "playerCameraHandler"

2
src/main/scala/wow/doge/mygame/game/nodes/PlayerCameraActor.scala

@ -1,7 +1,7 @@
package wow.doge.mygame.game.nodes package wow.doge.mygame.game.nodes
import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.scaladsl.Behaviors
object PlayerCameraActor { object PlayerCameraActor {
sealed trait Command sealed trait Command

60
src/main/scala/wow/doge/mygame/game/nodes/PlayerController.scala

@ -1,33 +1,34 @@
package wow.doge.mygame.game.nodes 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.CameraNode
import com.jme3.scene.Geometry 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.control.CameraControl.ControlDirection
import com.jme3.scene.shape.Box 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.game.GameApp
import wow.doge.mygame.implicits._ import wow.doge.mygame.implicits._
import wow.doge.mygame.math.ImVector3f 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.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.events.PlayerCameraEvent
import wow.doge.mygame.subsystems.movement.ImMovementActor
import wow.doge.mygame.utils.AkkaUtils import wow.doge.mygame.utils.AkkaUtils
// class PlayerNode(val name: String) extends Node(name) {} // class PlayerNode(val name: String) extends Node(name) {}
@ -39,7 +40,9 @@ object PlayerController {
case class GenericError(reason: String) extends Error case class GenericError(reason: String) extends Error
class Props( class Props(
app: GameApp,
enqueueR: Function1[() => Unit, Unit],
rootNode: Ref[Task, Node],
camera: Camera,
loggerL: Logger[Task], loggerL: Logger[Task],
assetManager: AssetManager, assetManager: AssetManager,
bulletAppState: BulletAppState, bulletAppState: BulletAppState,
@ -52,15 +55,15 @@ object PlayerController {
playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]], playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]],
_playerPhysicsControl: Option[BetterCharacterControl], _playerPhysicsControl: Option[BetterCharacterControl],
_playerNode: Option[Node with Player] = None, _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) { )(implicit timeout: Timeout, scheduler: Scheduler) {
import Defaults._ import Defaults._
import Methods._
val create: IO[Error, Unit] = val create: IO[Error, Unit] =
// IO.raiseError(GenericError("not implemented yet")) // IO.raiseError(GenericError("not implemented yet"))
(for { (for {
camNode <- IO( camNode <- IO(
_cameraNode.getOrElse(defaultCamerNode(app.camera, initialPlayerPos))
_cameraNode.getOrElse(defaultCamerNode(camera, initialPlayerPos))
) )
playerPhysicsControl <- IO( playerPhysicsControl <- IO(
_playerPhysicsControl _playerPhysicsControl
@ -82,7 +85,7 @@ object PlayerController {
spawnProtocol, spawnProtocol,
"playerActorSupervisor", "playerActorSupervisor",
new PlayerActorSupervisor.Props( new PlayerActorSupervisor.Props(
app,
enqueueR,
camNode, camNode,
playerMovementEventBus, playerMovementEventBus,
playerCameraEventBus playerCameraEventBus
@ -92,11 +95,10 @@ object PlayerController {
bulletAppState.physicsSpace += playerNode bulletAppState.physicsSpace += playerNode
bulletAppState.physicsSpace += playerPhysicsControl bulletAppState.physicsSpace += playerPhysicsControl
} }
_ <- IO(app.rootNode += playerNode)
_ <- rootNode.update(_ :+ playerNode)
} yield ()) } yield ())
.onErrorHandleWith(e => IO.raiseError(GenericError(e.getMessage()))) .onErrorHandleWith(e => IO.raiseError(GenericError(e.getMessage())))
.executeOn(app.scheduler)
.executeOn(appScheduler)
} }
def apply( def apply(
@ -175,7 +177,7 @@ object Defaults {
object Methods { object Methods {
def spawnMovementActor( def spawnMovementActor(
app: GameApp,
enqueueR: Function1[() => Unit, Unit],
spawnProtocol: ActorRef[SpawnProtocol.Command], spawnProtocol: ActorRef[SpawnProtocol.Command],
movable: BetterCharacterControl @@ Player, movable: BetterCharacterControl @@ Player,
playerMovementEventBus: ActorRef[ playerMovementEventBus: ActorRef[
@ -185,7 +187,7 @@ object Methods {
)(implicit timeout: Timeout, scheduler: Scheduler) = )(implicit timeout: Timeout, scheduler: Scheduler) =
spawnProtocol.askL[ActorRef[ImMovementActor.Command]]( spawnProtocol.askL[ActorRef[ImMovementActor.Command]](
SpawnProtocol.Spawn( SpawnProtocol.Spawn(
ImMovementActor.Props(app, movable, playerMovementEventBus).create,
ImMovementActor.Props(enqueueR, movable, playerMovementEventBus).create,
"imMovementActor", "imMovementActor",
Props.empty, Props.empty,
_ _

12
src/main/scala/wow/doge/mygame/game/nodes/PlayerEventListeners.scala

@ -1,18 +1,16 @@
package wow.doge.mygame.game.nodes package wow.doge.mygame.game.nodes
import akka.actor.typed.ActorRef import akka.actor.typed.ActorRef
import akka.actor.typed.LogOptions
import akka.actor.typed.scaladsl.Behaviors 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 org.slf4j.event.Level
import akka.actor.typed.LogOptions
import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent 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
import wow.doge.mygame.subsystems.events.PlayerCameraEvent.CameraMovedUp
import wow.doge.mygame.subsystems.events.PlayerCameraEvent.CameraMovedDown 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 { object PlayerMovementEventListener {
import PlayerMovementEvent._ import PlayerMovementEvent._

135
src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala

@ -1,23 +1,19 @@
package wow.doge.mygame.game.subsystems.input 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 akka.actor.typed.ActorRef
import wow.doge.mygame.events.EventBus
import com.jme3.input.InputManager
import com.jme3.input.KeyInput import com.jme3.input.KeyInput
import com.jme3.input.MouseInput
import com.jme3.input.controls.KeyTrigger import com.jme3.input.controls.KeyTrigger
import com.jme3.input.controls.MouseAxisTrigger
import monix.bio.UIO 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 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 import wow.doge.mygame.subsystems.events.PlayerCameraEvent
// class GameInputHandler(
// inputManager: InputManager
// // inputEventBus: InputEventBus
// ) {}
import wow.doge.mygame.utils.IOUtils._
object GameInputHandler { object GameInputHandler {
@ -30,6 +26,7 @@ object GameInputHandler {
) { ) {
def begin = def begin =
for { for {
_ <- UIO(setupMovementKeys(inputManager))
_ <- UIO(setupKeys(inputManager)) _ <- UIO(setupKeys(inputManager))
_ <- toIO( _ <- toIO(
generateMovementInputEvents( generateMovementInputEvents(
@ -49,40 +46,49 @@ object GameInputHandler {
playerCameraEventBus playerCameraEventBus
).completedL.startAndForget ).completedL.startAndForget
) )
_ <- toIO(
myTest(
inputManager
).completedL.startAndForget
)
} yield () } 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) = def setupKeys(inputManager: 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( .withMapping(
PlayerAnalogInput.TurnRight.entryName, PlayerAnalogInput.TurnRight.entryName,
new KeyTrigger(KeyInput.KEY_RIGHT), new KeyTrigger(KeyInput.KEY_RIGHT),
@ -145,33 +151,19 @@ object GameInputHandler {
name 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( def generateRotateEvents(
inputManager: InputManager, inputManager: InputManager,
playerMovementEventBus: ActorRef[ playerMovementEventBus: ActorRef[
@ -182,7 +174,7 @@ object GameInputHandler {
inputManager inputManager
.enumAnalogObservable(PlayerAnalogInput) .enumAnalogObservable(PlayerAnalogInput)
.sample(1.millis) .sample(1.millis)
.map(e => e)
// .map(e => e)
.doOnNext(analogEvent => .doOnNext(analogEvent =>
analogEvent.binding match { analogEvent.binding match {
case PlayerAnalogInput.TurnRight => 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])

3
src/main/scala/wow/doge/mygame/game/subsystems/input/InputEnums.scala

@ -1,6 +1,6 @@
package wow.doge.mygame.game.subsystems.input package wow.doge.mygame.game.subsystems.input
import enumeratum._
import enumeratum.EnumEntry._ import enumeratum.EnumEntry._
import enumeratum._
sealed trait PlayerMovementInput extends EnumEntry with UpperSnakecase sealed trait PlayerMovementInput extends EnumEntry with UpperSnakecase
object PlayerMovementInput extends Enum[PlayerMovementInput] { object PlayerMovementInput extends Enum[PlayerMovementInput] {
@ -9,6 +9,7 @@ object PlayerMovementInput extends Enum[PlayerMovementInput] {
case object WalkRight extends PlayerMovementInput case object WalkRight extends PlayerMovementInput
case object WalkLeft extends PlayerMovementInput case object WalkLeft extends PlayerMovementInput
case object WalkBackward extends PlayerMovementInput case object WalkBackward extends PlayerMovementInput
case object Jump extends PlayerMovementInput
} }
sealed trait PlayerAnalogInput extends EnumEntry with UpperSnakecase sealed trait PlayerAnalogInput extends EnumEntry with UpperSnakecase

57
src/main/scala/wow/doge/mygame/game/subsystems/level/DefaultGameLevel.scala

@ -1,36 +1,20 @@
package wow.doge.mygame.game.subsystems.level 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.control.RigidBodyControl
import com.jme3.bullet.util.CollisionShapeFactory 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.light.DirectionalLight
import com.jme3.math.ColorRGBA
import com.jme3.math.Vector3f import com.jme3.math.Vector3f
import com.jme3.light.AmbientLight
import com.jme3.renderer.ViewPort
import com.jme3.scene.Spatial
object DefaultGameLevel { 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( lazy val sceneShape = CollisionShapeFactory.createMeshShape(
sceneModel.toNode match { sceneModel.toNode match {
case util.Right(node) => node case util.Right(node) => node
@ -41,23 +25,26 @@ object DefaultGameLevel {
lazy val landscape: RigidBodyControl = lazy val landscape: RigidBodyControl =
new RigidBodyControl(sceneShape, 0) 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.setLocalScale(2f)
sceneModel.addControl(landscape) 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(); val al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(1.3f)); al.setColor(ColorRGBA.White.mult(1.3f));
app.rootNode.addLight(al);
// app.rootNode.addLight(al);
val dl = new DirectionalLight(); val dl = new DirectionalLight();
dl.setColor(ColorRGBA.White); dl.setColor(ColorRGBA.White);
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal()); 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
)
} }
} }

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

6
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.FastMath
import com.jme3.math.Quaternion import com.jme3.math.Quaternion
import com.jme3.math.Vector3f 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.jme3.scene.Spatial
import com.typesafe.scalalogging.LazyLogging 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] { trait CanMove[-A] {
// def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f // def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f

32
src/main/scala/wow/doge/mygame/game/subsystems/movement/MovementActor.scala

@ -1,19 +1,17 @@
package wow.doge.mygame.subsystems.movement 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.Behavior
import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.scaladsl.Behaviors 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.implicits._
import wow.doge.mygame.math.ImVector3f 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.state.CardinalDirection
import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent
import wow.doge.mygame.game.subsystems.movement.CanMove
import com.softwaremill.quicklens._
sealed trait RotateDir sealed trait RotateDir
object RotateDir { object RotateDir {
@ -36,7 +34,7 @@ object ImMovementActor {
final case object RotateLeft extends Movement final case object RotateLeft extends Movement
final case class Props[T: CanMove]( final case class Props[T: CanMove](
app: GameApp,
enqueueR: Function1[() => Unit, Unit],
movable: T, movable: T,
playerMovementEventBus: ActorRef[ playerMovementEventBus: ActorRef[
EventBus.Command[PlayerMovementEvent] EventBus.Command[PlayerMovementEvent]
@ -90,25 +88,25 @@ class ImMovementActor[T](
case m: Movement => case m: Movement =>
m match { m match {
case MovedLeft(pressed) => case MovedLeft(pressed) =>
props.app.enqueueR(() => stopIfNotPressed(pressed, props.movable))
props.enqueueR(() => stopIfNotPressed(pressed, props.movable))
receive(state = state.modify(_.cardinalDir.left).setTo(pressed)) receive(state = state.modify(_.cardinalDir.left).setTo(pressed))
case MovedUp(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)) receive(state = state.modify(_.cardinalDir.up).setTo(pressed))
case MovedRight(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)) receive(state = state.modify(_.cardinalDir.right).setTo(pressed))
case MovedDown(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)) receive(state = state.modify(_.cardinalDir.down).setTo(pressed))
case Jump => case Jump =>
props.app.enqueueR(() => cm.jump(props.movable))
props.enqueueR(() => cm.jump(props.movable))
Behaviors.same Behaviors.same
case RotateLeft => case RotateLeft =>
props.app.enqueueR(() => cm.rotate(props.movable, RotateDir.Left))
props.enqueueR(() => cm.rotate(props.movable, RotateDir.Left))
Behaviors.same Behaviors.same
case RotateRight => case RotateRight =>
props.app.enqueueR(() => cm.rotate(props.movable, RotateDir.Right))
props.enqueueR(() => cm.rotate(props.movable, RotateDir.Right))
Behaviors.same Behaviors.same
} }
@ -117,7 +115,7 @@ class ImMovementActor[T](
getDirection(state.cardinalDir, ctx.log.trace) getDirection(state.cardinalDir, ctx.log.trace)
if (walkDir != ImVector3f.ZERO) { if (walkDir != ImVector3f.ZERO) {
val tmp = walkDir * 25f * (1f / 144) val tmp = walkDir * 25f * (1f / 144)
props.app.enqueueR { () =>
props.enqueueR { () =>
cm.move(props.movable, tmp) cm.move(props.movable, tmp)
} }
} }

5
src/main/scala/wow/doge/mygame/implicits/EntityQuery.scala

@ -1,12 +1,13 @@
package wow.doge.mygame.implicits package wow.doge.mygame.implicits
import scala.reflect.ClassTag
import scala.util.Try
import com.simsilica.es.ComponentFilter import com.simsilica.es.ComponentFilter
import com.simsilica.es.EntityComponent import com.simsilica.es.EntityComponent
import com.simsilica.es.EntityData import com.simsilica.es.EntityData
import com.simsilica.es.EntitySet import com.simsilica.es.EntitySet
import com.simsilica.es.Filters import com.simsilica.es.Filters
import scala.reflect.ClassTag
import scala.util.Try
class EntityQuery(ed: EntityData) { class EntityQuery(ed: EntityData) {
private var cfilter: Option[ComponentFilter[_ <: EntityComponent]] = None private var cfilter: Option[ComponentFilter[_ <: EntityComponent]] = None

208
src/main/scala/wow/doge/mygame/implicits/package.scala

@ -1,52 +1,54 @@
package wow.doge.mygame package wow.doge.mygame
import com.jme3.app.SimpleApplication
import com.jme3.app.state.AppStateManager
import scala.jdk.CollectionConverters._
import scala.reflect.ClassTag 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.actor.typed.ActorRef
import akka.util.Timeout
import akka.actor.typed.Scheduler 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.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.InputListener
import com.jme3.input.controls.Trigger
import com.jme3.math.Vector3f import com.jme3.math.Vector3f
import wow.doge.mygame.math.ImVector3f
import com.jme3.scene.CameraNode
import com.jme3.scene.Geometry 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 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
import monix.execution.Ack.Continue
import monix.execution.Ack.Stop
import monix.execution.Cancelable import monix.execution.Cancelable
import monix.execution.cancelables.SingleAssignCancelable 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.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 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 ActionEvent(binding: Action, value: Boolean, tpf: Float)
case class EnumActionEvent[T <: EnumEntry]( 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 { extends AnyVal {
def state[S <: AppState]()(implicit c: ClassTag[S]): S = 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 { implicit class NodeExt[T <: Node](private val n: T) extends AnyVal {
/** /**
@ -139,6 +175,11 @@ package object implicits {
def observableChildren = def observableChildren =
Observable.fromIterable(n.getChildren().asScala) 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) def children = LazyList.from(n.getChildren().asScala)
/** /**
@ -147,12 +188,24 @@ package object implicits {
* @param lst * @param lst
*/ */
def withChildren(lst: Spatial*): Node = { def withChildren(lst: Spatial*): Node = {
for (c <- lst) n.withChild(c)
for (c <- lst) n.attachChild(c)
n n
} }
def +=(spatial: Spatial) = n.attachChild(spatial) 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) = def depthFirst(cb: Spatial => Unit) =
n.depthFirstTraversal(new SceneGraphVisitor() { n.depthFirstTraversal(new SceneGraphVisitor() {
override def visit(s: Spatial) = cb(s) override def visit(s: Spatial) = cb(s)
@ -333,6 +386,16 @@ package object implicits {
inputManager 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] = { def observableAction(mappingNames: String*): Observable[ActionEvent] = {
Observable.create(OverflowStrategy.DropOld(10)) { sub => 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] = { def analogObservable(mappingNames: String*): Observable[AnalogEvent] = {
Observable.create(OverflowStrategy.DropOld(50)) { sub => Observable.create(OverflowStrategy.DropOld(50)) { sub =>
@ -509,60 +566,60 @@ package object implicits {
//TODO Create a typeclass for this //TODO Create a typeclass for this
def +=(anyObject: Any) = space.add(anyObject) 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 { implicit class Vector3fExt(private val v: Vector3f) extends AnyVal {
//TODO add more operations //TODO add more operations
def +=(that: Vector3f) = v.addLocal(that) 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.addLocal(that.x, that.y, that.z)
def +=:(that: ImVector3f) = v += that def +=:(that: ImVector3f) = v += that
def *=(that: Vector3f) = v.multLocal(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: 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: Vector3f) = v.divideLocal(that)
def /=(that: ImVector3f) = v.divideLocal(that.mutable)
def /=:(that: ImVector3f) = v *= that
def unary_- = v.negateLocal() def unary_- = v.negateLocal()
def immutable = ImVector3f(v.x, v.y, v.z) def immutable = ImVector3f(v.x, v.y, v.z)
} }
implicit class ImVector3fExt(private val v: ImVector3f) extends AnyVal { 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 +(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 *(that: ImVector3f) = v.copy(v.x * that.x, v.y * that.y, v.z * that.z)
def *(f: Float): ImVector3f = def *(f: Float): ImVector3f =
v.copy(v.x * f, v.y * f, v.z * f) v.copy(v.x * f, v.y * f, v.z * f)
// v * ImVector3f(f, f, f) // v * ImVector3f(f, f, f)
def -(that: ImVector3f) = v.copy(v.x - that.x, v.y - that.y, v.z - that.z) 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 /(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_- = 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) 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

3
src/main/scala/wow/doge/mygame/subsystems/events/EventBus.scala

@ -1,9 +1,10 @@
package wow.doge.mygame.events package wow.doge.mygame.events
import scala.reflect.ClassTag
import akka.actor.typed.ActorRef import akka.actor.typed.ActorRef
import akka.actor.typed.Behavior import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.Behaviors
import scala.reflect.ClassTag
import akka.event.EventStream import akka.event.EventStream
/** /**

68
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.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.Props
import akka.actor.typed.SpawnProtocol
import akka.actor.typed.SupervisorStrategy
import akka.actor.typed.scaladsl.Behaviors
import akka.util.Timeout 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 com.typesafe.scalalogging.{Logger => SLLogger}
import monix.bio.Task
import org.slf4j.event.Level
import wow.doge.mygame.events.EventBus 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 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 = lazy val playerMovementEventBusTask =
createEventBus[PlayerMovementEvent]("movementEventBus") 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.askL(
SpawnProtocol.Spawn[EventBus.Command[T]]( SpawnProtocol.Spawn[EventBus.Command[T]](
Behaviors.logMessages( Behaviors.logMessages(
logOptions = LogOptions().withLogger(eventBusLogger.underlying),
logOptions = LogOptions()
.withLevel(logLevel)
.withLogger(eventBusLogger.underlying),
Behaviors Behaviors
.supervise(EventBus[T]()) .supervise(EventBus[T]())
.onFailure[Exception](SupervisorStrategy.restart) .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))
}

64
src/main/scala/wow/doge/mygame/subsystems/events/EventsModule2.scala

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

47
src/main/scala/wow/doge/mygame/subsystems/moddingsystem/ModdingSystem.scala

@ -1,5 +1,6 @@
package wow.doge.mygame.subsystems.moddingsystem package wow.doge.mygame.subsystems.moddingsystem
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.nio.file.NoSuchFileException
import scala.collection.View import scala.collection.View
import scala.collection.immutable.ArraySeq import scala.collection.immutable.ArraySeq
@ -11,7 +12,9 @@ import io.circe.generic.semiauto._
import io.circe.parser._ import io.circe.parser._
import monix.bio.IO import monix.bio.IO
import monix.bio.UIO 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 import io.circe.generic.JsonCodec
@JsonCodec @JsonCodec
@ -20,6 +23,9 @@ final case class Test1(hello1: String, hello2: String)
final case class Test2(hello1: String) final case class Test2(hello1: String)
final case class Plugin(name: String, priority: Int) final case class Plugin(name: String, priority: Int)
object Plugin { object Plugin {
// @annotation.nowarn(
// "msg=Block result was adapted via implicit conversion"
// )
implicit val pluginFormat: Decoder[Plugin] = deriveDecoder implicit val pluginFormat: Decoder[Plugin] = deriveDecoder
} }
@ -90,16 +96,29 @@ object ModdingSystem {
case (p, Right(value)) => Right(p -> value) 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 = // def test =
// for { // for {
// filePaths <- Task(findPluginFiles(os.pwd)) // filePaths <- Task(findPluginFiles(os.pwd))
@ -118,7 +137,16 @@ object ModdingSystem {
plugins <- IO.fromTryEither(readPluginsList(wd)) plugins <- IO.fromTryEither(readPluginsList(wd))
(readFailures, readSuccesses) <- UIO(findAndReadPluginFiles(wd, plugins)) (readFailures, readSuccesses) <- UIO(findAndReadPluginFiles(wd, plugins))
(parseFailures, parseSuccesses) <- UIO(parsePluginFiles(readSuccesses)) (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 { _ <- UIO {
println(s"Read Successes = ${readSuccesses.to(Seq)}") println(s"Read Successes = ${readSuccesses.to(Seq)}")
println(s"Read Failures = ${readFailures.to(Seq)}") println(s"Read Failures = ${readFailures.to(Seq)}")
@ -138,5 +166,4 @@ object ModdingSystem {
// def test3(wd: os.Path = os.pwd) = { // def test3(wd: os.Path = os.pwd) = {
// (readPluginsList(os.pwd).toValidatedNec) // (readPluginsList(os.pwd).toValidatedNec)
// } // }
;
} }

21
src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptActor.scala

@ -1,21 +1,22 @@
package wow.doge.mygame.state 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 akka.actor.typed.ActorRef
import ammonite.runtime.Storage.Folder
import ammonite.main.Defaults
import akka.actor.typed.Behavior import akka.actor.typed.Behavior
import akka.actor.typed.LogOptions
import akka.actor.typed.scaladsl.ActorContext 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 ammonite.util.Res.Success
import javax.script.ScriptEngine
import javax.script.ScriptEngineManager
import groovy.util.GroovyScriptEngine
import cats.implicits._ import cats.implicits._
import akka.actor.typed.LogOptions
import org.slf4j.event.Level
import com.typesafe.scalalogging.Logger
import com.softwaremill.tagging._ import com.softwaremill.tagging._
import com.typesafe.scalalogging.Logger
import groovy.util.GroovyScriptEngine
import org.slf4j.event.Level
object ScriptActor { object ScriptActor {
trait Kotlin trait Kotlin

19
src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptCachingActor.scala

@ -1,19 +1,20 @@
package wow.doge.mygame.scriptsystem 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.Behaviors
import akka.actor.typed.scaladsl.PoolRouter import akka.actor.typed.scaladsl.PoolRouter
import akka.actor.typed.scaladsl.Routers 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 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 com.typesafe.scalalogging.Logger
import org.slf4j.event.Level
import wow.doge.mygame.state.ScriptActor
object ScriptCachingActor { object ScriptCachingActor {

66
src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptSystemModule.scala

@ -1,23 +1,65 @@
package wow.doge.mygame.subsystems.scriptsystem 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.ActorRef
import akka.actor.typed.Scheduler
import akka.actor.typed.SpawnProtocol import akka.actor.typed.SpawnProtocol
import akka.util.Timeout 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( class ScriptSystemResource(
path: os.Path, path: os.Path,
spawnProtocol: ActorRef[SpawnProtocol.Command]
spawnProtocol: ActorRef[SpawnProtocol.Command],
mode: ScriptInitMode = ScriptInitMode.Lazy
)(implicit timeout: Timeout, scheduler: Scheduler) { )(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

6
src/main/scala/wow/doge/mygame/utils/AkkaUtils.scala

@ -1,11 +1,11 @@
package wow.doge.mygame.utils package wow.doge.mygame.utils
import akka.actor.typed.ActorRef
import akka.actor.typed.Behavior
import akka.actor.typed.Props import akka.actor.typed.Props
import akka.util.Timeout
import akka.actor.typed.Scheduler import akka.actor.typed.Scheduler
import akka.actor.typed.ActorRef
import akka.actor.typed.SpawnProtocol import akka.actor.typed.SpawnProtocol
import akka.actor.typed.Behavior
import akka.util.Timeout
import wow.doge.mygame.implicits._ import wow.doge.mygame.implicits._
object AkkaUtils { object AkkaUtils {

7
src/main/scala/wow/doge/mygame/utils/JFXConsoleStream.scala

@ -1,11 +1,12 @@
package wow.doge.mygame.utils package wow.doge.mygame.utils
import java.io.PrintStream
import java.io.OutputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import scalafx.scene.control.TextArea
import java.io.OutputStream
import java.io.PrintStream
import cats.effect.Resource import cats.effect.Resource
import monix.bio.Task import monix.bio.Task
import scalafx.scene.control.TextArea
trait JFXConsoleStreamable[T] { trait JFXConsoleStreamable[T] {
def println(inst: T, text: String): Unit def println(inst: T, text: String): Unit

Loading…
Cancel
Save