Browse Source

Commit 1

development
Rohan Sircar 3 years ago
parent
commit
3881aac350
  1. 0
      .attach_pid12833
  2. 0
      .attach_pid19972
  3. 7
      build.sbt
  4. 21
      src/main/scala/org/slf4j/impl/StaticLoggerBuilder.scala
  5. 30
      src/main/scala/wow/doge/mygame/Main.scala
  6. 167
      src/main/scala/wow/doge/mygame/MainApp.scala
  7. 11
      src/main/scala/wow/doge/mygame/MainModule.scala
  8. 61
      src/main/scala/wow/doge/mygame/game/GameApp.scala
  9. 5
      src/main/scala/wow/doge/mygame/game/GameAppActor.scala
  10. 58
      src/main/scala/wow/doge/mygame/game/GameModule.scala
  11. 30
      src/main/scala/wow/doge/mygame/game/SimpleAppExt.scala
  12. 14
      src/main/scala/wow/doge/mygame/game/TestActor.scala
  13. 10
      src/main/scala/wow/doge/mygame/game/appstates/PlayerMovementState.scala
  14. 30
      src/main/scala/wow/doge/mygame/game/entities/NpcActorSupervisor.scala
  15. 2
      src/main/scala/wow/doge/mygame/game/entities/player/PlayerActorSupervisor.scala
  16. 55
      src/main/scala/wow/doge/mygame/game/entities/player/PlayerController.scala
  17. 58
      src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala
  18. 6
      src/main/scala/wow/doge/mygame/game/subsystems/level/DefaultGameLevel.scala
  19. 30
      src/main/scala/wow/doge/mygame/game/subsystems/movement/CanMove2.scala
  20. 7
      src/main/scala/wow/doge/mygame/game/subsystems/movement/MovementActor.scala
  21. 32
      src/main/scala/wow/doge/mygame/implicits/JavaFXMonixObservables.scala
  22. 64
      src/main/scala/wow/doge/mygame/implicits/package.scala
  23. 118
      src/main/scala/wow/doge/mygame/launcher/Launcher.scala
  24. 14
      src/main/scala/wow/doge/mygame/subsystems/events/EventsModule.scala
  25. 6
      src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptActor.scala
  26. 12
      src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptCachingActor.scala
  27. 26
      src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptSystemModule.scala
  28. 4
      src/main/scala/wow/doge/mygame/utils/AkkaUtils.scala
  29. 4
      src/main/scala/wow/doge/mygame/utils/GenericConsoleStream.scala

0
.attach_pid12833

0
.attach_pid19972

7
build.sbt

@ -95,7 +95,8 @@ lazy val root = (project in file(".")).settings(
// "com.github.Oshan96" % "CustomStage" % "v1.3.1", // "com.github.Oshan96" % "CustomStage" % "v1.3.1",
"com.badlogicgames.gdx" % "gdx-ai" % "1.8.2", "com.badlogicgames.gdx" % "gdx-ai" % "1.8.2",
"org.recast4j" % "recast" % "1.2.5", "org.recast4j" % "recast" % "1.2.5",
"org.recast4j" % "detour" % "1.2.5"
"org.recast4j" % "detour" % "1.2.5",
"com.lihaoyi" %% "pprint" % "0.6.0"
), ),
// Determine OS version of JavaFX binaries // Determine OS version of JavaFX binaries
@ -155,10 +156,6 @@ lazy val root = (project in file(".")).settings(
// val oldStrategy = (assemblyMergeStrategy in assembly).value // val oldStrategy = (assemblyMergeStrategy in assembly).value
// oldStrategy(x) // oldStrategy(x)
} }
// scalaVersion := "2.13.2", // 2.11.12, or 2.13.3
// semanticdbEnabled := true, // enable SemanticDB
// semanticdbVersion := scalafixSemanticdb.revision // use Scalafix compatible version
// semanticdbVersion := "4.3.24",
) )
initialCommands in (console) := """ammonite.Main.main(Array.empty)""" initialCommands in (console) := """ammonite.Main.main(Array.empty)"""

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

@ -47,6 +47,10 @@ class StaticLoggerBinder extends OdinLoggerBinder[IO] {
.allocated .allocated
.unsafeRunSync() .unsafeRunSync()
val mainFileLogger2 = mainFileLogger.contramap(lm =>
lm.copy(message = lm.message.map(s => fansi.Str(s).plainText))
)
private lazy val (eventBusFileLogger, release3) = private lazy val (eventBusFileLogger, release3) =
fileLogger[IO]( fileLogger[IO](
"eventbus.log", "eventbus.log",
@ -72,15 +76,22 @@ class StaticLoggerBinder extends OdinLoggerBinder[IO] {
case s if s.startsWith("com.jayfella.jme.jfx.util.JfxPlatform") => case s if s.startsWith("com.jayfella.jme.jfx.util.JfxPlatform") =>
defaultConsoleLogger.withMinimalLevel(Level.Info) defaultConsoleLogger.withMinimalLevel(Level.Info)
// case s
// if s.startsWith(
// "wow.doge.mygame.subsystems.movement.PlayerMovementEventHandler"
// ) =>
case s
if s.startsWith(
"wow.doge.mygame.subsystems.movement.PlayerMovementEventHandler"
) =>
defaultConsoleLogger.withMinimalLevel(Level.Info)
case s
if s.startsWith(
"wow.doge.mygame.game.entities.NpcMovementActor"
) =>
defaultConsoleLogger.withMinimalLevel(Level.Trace) |+| mainFileLogger2
.withMinimalLevel(Level.Trace)
// defaultConsoleLogger.withMinimalLevel( Level.Trace) //selectively turn on trace logging for specific classes // defaultConsoleLogger.withMinimalLevel( Level.Trace) //selectively turn on trace logging for specific classes
case s if s.startsWith("wow.doge.mygame.subsystems.events.EventBus") => case s if s.startsWith("wow.doge.mygame.subsystems.events.EventBus") =>
defaultConsoleLogger.withMinimalLevel(Level.Debug) |+| eventBusFileLogger defaultConsoleLogger.withMinimalLevel(Level.Debug) |+| eventBusFileLogger
case s if s.startsWith("akka.actor") || s.startsWith("wow.doge.mygame") => case s if s.startsWith("akka.actor") || s.startsWith("wow.doge.mygame") =>
defaultConsoleLogger.withMinimalLevel(Level.Debug) |+| mainFileLogger
defaultConsoleLogger.withMinimalLevel(Level.Debug) |+| mainFileLogger2
case _ => //if wildcard case isn't provided, default logger is no-op case _ => //if wildcard case isn't provided, default logger is no-op
defaultConsoleLogger.withMinimalLevel(Level.Debug) defaultConsoleLogger.withMinimalLevel(Level.Debug)
} }

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

@ -5,16 +5,16 @@ import scala.concurrent.duration._
import _root_.monix.bio.BIOApp import _root_.monix.bio.BIOApp
import _root_.monix.bio.Task import _root_.monix.bio.Task
import _root_.monix.bio.UIO import _root_.monix.bio.UIO
import akka.actor.typed.ActorSystem
import akka.actor.typed.SpawnProtocol
import akka.util.Timeout import akka.util.Timeout
import cats.effect.ExitCode import cats.effect.ExitCode
import cats.effect.Resource import cats.effect.Resource
import cats.implicits._ import cats.implicits._
import com.softwaremill.macwire._
import io.odin._ import io.odin._
import io.odin.json.Formatter import io.odin.json.Formatter
import io.odin.syntax._ import io.odin.syntax._
import scalafx.scene.control.TextArea import scalafx.scene.control.TextArea
import wow.doge.mygame.game.GameAppResource
import wow.doge.mygame.utils.GenericConsoleStream import wow.doge.mygame.utils.GenericConsoleStream
object Main extends BIOApp with MainModule { object Main extends BIOApp with MainModule {
@ -34,25 +34,23 @@ object Main extends BIOApp with MainModule {
Formatter.json Formatter.json
).withAsync(timeWindow = 1.milliseconds, maxBufferSize = Some(2000)) ).withAsync(timeWindow = 1.milliseconds, maxBufferSize = Some(2000))
jmeScheduler <- jMESchedulerResource jmeScheduler <- jMESchedulerResource
actorSystem <- actorSystemResource(logger)
gameApp <- {
// new BulletAppState()
// bas.setThreadingType(Thr)
// gameAppResource(new StatsAppState())
wire[GameAppResource].get
}
implicit0(actorSystem: ActorSystem[SpawnProtocol.Command]) <-
actorSystemResource(logger)
// gameApp <- {
// // new BulletAppState()
// // bas.setThreadingType(Thr)
// // gameAppResource(new StatsAppState())
// wire[GameAppResource].get
// }
_ <- Resource.liftF( _ <- Resource.liftF(
new MainApp( new MainApp(
logger, logger,
gameApp,
actorSystem,
// gameApp,
// actorSystem,
jmeScheduler, jmeScheduler,
schedulers, schedulers,
consoleStream consoleStream
)(
timeout,
actorSystem.scheduler
).program
)(actorSystem, timeout, actorSystem.scheduler).program
) )
} yield () } yield ()
@ -63,7 +61,7 @@ object Main extends BIOApp with MainModule {
Console.withOut(consoleStream)( Console.withOut(consoleStream)(
appResource(consoleStream) appResource(consoleStream)
.use(_ => Task.unit >> Task(consoleStream.close())) .use(_ => Task.unit >> Task(consoleStream.close()))
.onErrorHandle(_.printStackTrace())
.onErrorHandleWith(ex => UIO(ex.printStackTrace()))
.as(ExitCode.Success) .as(ExitCode.Success)
) )
} }

167
src/main/scala/wow/doge/mygame/MainApp.scala

@ -4,6 +4,7 @@ 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.Resource
import cats.effect.concurrent.Deferred import cats.effect.concurrent.Deferred
import com.jme3.app.state.AppStateManager import com.jme3.app.state.AppStateManager
import com.jme3.asset.AssetManager import com.jme3.asset.AssetManager
@ -46,98 +47,80 @@ import wow.doge.mygame.subsystems.scriptsystem.ScriptInitMode
import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource
import wow.doge.mygame.utils.AkkaUtils import wow.doge.mygame.utils.AkkaUtils
import wow.doge.mygame.utils.GenericConsoleStream import wow.doge.mygame.utils.GenericConsoleStream
import wow.doge.mygame.utils.IOUtils
import cats.syntax.eq._
import EventsModule.GameEventBus
import wow.doge.mygame.subsystems.events.EventsModule.GameEventBus
class MainApp( class MainApp(
logger: Logger[Task], logger: Logger[Task],
gameApp: GameApp,
implicit val spawnProtocol: ActorSystem[SpawnProtocol.Command],
jmeThread: monix.execution.Scheduler, jmeThread: monix.execution.Scheduler,
schedulers: Schedulers, schedulers: Schedulers,
consoleStream: GenericConsoleStream[TextArea] consoleStream: GenericConsoleStream[TextArea]
)(implicit )(implicit
spawnProtocol: ActorSystem[SpawnProtocol.Command],
@annotation.unused timeout: Timeout, @annotation.unused timeout: Timeout,
@annotation.unused scheduler: Scheduler @annotation.unused scheduler: Scheduler
) { ) {
lazy val scriptSystemInit =
new ScriptSystemResource(os.pwd, spawnProtocol, ScriptInitMode.Eager).init
val scriptSystemInit =
new ScriptSystemResource(os.pwd, ScriptInitMode.Eager).init
def gameInit: Task[Fiber[Throwable, Unit]] =
for {
eventsModule <- Task(new EventsModule(spawnProtocol))
playerEventBus <- eventsModule.playerEventBusTask
mainEventBus <- eventsModule.mainEventBusTask
tickEventBus <- eventsModule.tickEventBusTask
gameAppActor <- AkkaUtils.spawnActorL2(
GameAppActor.Props(tickEventBus).behavior,
"gameAppActor"
)
_ <- gameAppActor !! GameAppActor.Start
gameAppFib <- gameApp.start.executeOn(jmeThread).start
/**
* schedule a task to run on the JME thread and wait for it's completion
* before proceeding forward, as a signal that the JME thread has been
* initialized, otherwise we'll get NPEs trying to access the fields
* of the game app
*/
res <- gameApp.enqueueL(() => "done")
_ <- logger.info(s"Result = $res")
/**
* JME Thread has been initialized at this point. We can now access the
* field of the game application
*/
inputManager <- gameApp.inputManager
assetManager <- gameApp.assetManager
stateManager <- gameApp.stateManager
camera <- gameApp.camera
rootNode <- gameApp.rootNode
enqueueR <- Task(gameApp.enqueue _)
viewPort <- gameApp.viewPort
_ <- logger.info("before")
// jfxUI <- gameApp.jfxUI
consoleTextArea <- Task(new TextArea {
text = "hello \n"
editable = false
wrapText = true
// maxHeight = 150
// maxWidth = 300
})
// _ <- Task(consoleStream := consoleTextArea)
// _ <- Task(jfxUI += consoleTextArea)
_ <- logger.info("after")
bulletAppState <- Task(new BulletAppState())
_ <- Task(stateManager.attach(bulletAppState))
_ <- logger.info("Initializing console stream")
_ <- wire[MainAppDelegate].init(gameApp.scheduler)
} yield (gameAppFib)
val eventsModule = new EventsModule(spawnProtocol)
lazy val program = for {
def gameInit: Resource[Task, Fiber[Throwable, Unit]] =
GameApp.resource(logger, jmeThread, schedulers).evalMap {
case gameApp -> gameAppFib =>
for {
playerEventBus <- eventsModule.playerEventBusTask
mainEventBus <- eventsModule.mainEventBusTask
tickEventBus <- eventsModule.tickEventBusTask
gameAppActor <- AkkaUtils.spawnActorL(
GameAppActor.Props(tickEventBus).behavior,
"gameAppActor"
)
_ <- gameAppActor !! GameAppActor.Start
inputManager <- gameApp.inputManager
assetManager <- gameApp.assetManager
stateManager <- gameApp.stateManager
camera <- gameApp.camera
rootNode <- gameApp.rootNode
enqueueR <- Task(gameApp.enqueue _)
viewPort <- gameApp.viewPort
_ <- logger.info("before")
// jfxUI <- gameApp.jfxUI
consoleTextArea <- Task(new TextArea {
text = "hello \n"
editable = false
wrapText = true
// maxHeight = 150
// maxWidth = 300
})
// _ <- Task(consoleStream := consoleTextArea)
// _ <- Task(jfxUI += consoleTextArea)
_ <- logger.info("after")
bulletAppState <- Task(new BulletAppState())
_ <- Task(stateManager.attach(bulletAppState))
_ <- logger.info("Initializing console stream")
_ <- wire[MainAppDelegate].init(gameApp.scheduler)
} yield gameAppFib
}
val program = for {
scriptSystem <- scriptSystemInit scriptSystem <- scriptSystemInit
/**
* Signal for synchronization between the JavaFX launcher and the in-game JavaFX GUI
* Without this, we get a "Toolkit already initialized" exception. The launch button
* in the launcher completes the signal. The game init process which listens for this
* signal can then continue
*/
launchSignal <- Deferred[Task, Launcher.LauncherResult] launchSignal <- Deferred[Task, Launcher.LauncherResult]
launcher <- new Launcher.Props(schedulers, launchSignal).create launcher <- new Launcher.Props(schedulers, launchSignal).create
cancelToken <- launcher.init()
launchResult <- launchSignal.get
_ <- cancelToken.cancel
launchResult <- launcher.init.use(_ => launchSignal.get)
_ <- _ <-
/** /**
* User chose to quit * User chose to quit
*/ */
if (launchResult == LauncherResult.Exit)
if (launchResult === LauncherResult.Exit)
logger.info("Exiting") logger.info("Exiting")
/** /**
* User chose launch. Wait for game window to close * User chose launch. Wait for game window to close
*/ */
else else
gameInit.flatMap(_.join)
gameInit.use(_.join)
} yield () } yield ()
} }
@ -146,7 +129,6 @@ class MainApp(
*/ */
class MainAppDelegate( class MainAppDelegate(
gameApp: GameApp, gameApp: GameApp,
implicit val spawnProtocol: ActorSystem[SpawnProtocol.Command],
loggerL: Logger[Task], loggerL: Logger[Task],
playerEventBus: GameEventBus[PlayerEvent], playerEventBus: GameEventBus[PlayerEvent],
tickEventBus: GameEventBus[TickEvent], tickEventBus: GameEventBus[TickEvent],
@ -159,10 +141,11 @@ class MainAppDelegate(
rootNode: Node @@ GameAppTags.RootNode, rootNode: Node @@ GameAppTags.RootNode,
bulletAppState: BulletAppState bulletAppState: BulletAppState
)(implicit )(implicit
spawnProtocol: ActorSystem[SpawnProtocol.Command],
@annotation.unused timeout: Timeout, @annotation.unused timeout: Timeout,
@annotation.unused scheduler: Scheduler @annotation.unused scheduler: Scheduler
) { ) {
lazy val physicsSpace = bulletAppState.physicsSpace
val physicsSpace = bulletAppState.physicsSpace
def init( def init(
appScheduler: monix.execution.Scheduler appScheduler: monix.execution.Scheduler
// consoleStream: GenericConsoleStream[TextArea] // consoleStream: GenericConsoleStream[TextArea]
@ -190,19 +173,21 @@ class MainAppDelegate(
// johnActor <- createTestNpc(appScheduler, "John").executeOn(appScheduler) // johnActor <- createTestNpc(appScheduler, "John").executeOn(appScheduler)
// _ <- johnActor !! NpcActorSupervisor.Move(ImVector3f(0, 0, 20)) // _ <- johnActor !! NpcActorSupervisor.Move(ImVector3f(0, 0, 20))
// _ <- (johnActor !! NpcActorSupervisor.Move(
// ImVector3f(-80, 0, 100)
// )).executeAsync.delayExecution(2.seconds)
_ <-
IOUtils
.toIO(
rootNode
.observableBreadthFirst()
.doOnNext(spat => IOUtils.toTask(loggerL.debug(spat.getName())))
.completedL
)
.executeOn(appScheduler)
.startAndForget
// _ <-
// (johnActor !! NpcActorSupervisor.Move(
// ImVector3f(-30, 0, 10)
// )).executeAsync
// .delayExecution(2.seconds)
// _ <-
// IOUtils
// .toIO(
// rootNode
// .observableBreadthFirst()
// .doOnNext(spat => IOUtils.toTask(loggerL.debug(spat.getName())))
// .completedL
// )
// .executeOn(appScheduler)
// .startAndForget
} yield () } yield ()
def createPlayerController( def createPlayerController(
@ -210,14 +195,14 @@ class MainAppDelegate(
): IO[PlayerController.Error, Unit] = { ): IO[PlayerController.Error, Unit] = {
val playerPos = ImVector3f.ZERO val playerPos = ImVector3f.ZERO
val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o" val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
lazy val playerPhysicsControl =
val playerPhysicsControl =
PlayerController.Defaults.defaultPlayerPhysicsControl PlayerController.Defaults.defaultPlayerPhysicsControl
.taggedWith[PlayerControllerTags.PlayerTag] .taggedWith[PlayerControllerTags.PlayerTag]
// lazy val camNode = // lazy val camNode =
// PlayerController.Defaults // PlayerController.Defaults
// .defaultCamerNode(camera, playerPos) // .defaultCamerNode(camera, playerPos)
// .taggedWith[PlayerControllerTags.PlayerCameraNode] // .taggedWith[PlayerControllerTags.PlayerCameraNode]
lazy val mbPlayerNode = PlayerController.Defaults
val mbPlayerNode = PlayerController.Defaults
.defaultPlayerNode( .defaultPlayerNode(
assetManager, assetManager,
modelPath, modelPath,
@ -225,7 +210,7 @@ class MainAppDelegate(
// camNode // camNode
playerPhysicsControl playerPhysicsControl
) )
lazy val cameraPivotNode = new Node(EntityIds.CameraPivot.value)
val cameraPivotNode = new Node(EntityIds.CameraPivot.value)
.taggedWith[PlayerControllerTags.PlayerCameraPivotNode] .taggedWith[PlayerControllerTags.PlayerCameraPivotNode]
for { for {
@ -258,11 +243,11 @@ class MainAppDelegate(
) = ) =
// : IO[PlayerController.Error, Unit] = // : IO[PlayerController.Error, Unit] =
{ {
val initialPos = ImVector3f(100, 0, 0)
val initialPos = ImVector3f(50, 5, 0)
// val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o" // val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
lazy val npcPhysicsControl =
new BetterCharacterControl(1f, 2.1f, 10f)
// .withJumpForce(ImVector3f(0, 5f, 0))
val npcPhysicsControl = new BetterCharacterControl(1.5f, 6f, 1f)
// (1f, 2.1f, 10f)
.withJumpForce(ImVector3f(0, 5f, 0))
// val npcMovementActor = AkkaUtils.spawnActorL2( // val npcMovementActor = AkkaUtils.spawnActorL2(
// new NpcMovementActor2.Props( // new NpcMovementActor2.Props(
// initialPos, // initialPos,
@ -271,13 +256,13 @@ class MainAppDelegate(
// ).behavior, // ).behavior,
// s"${npcName}-npcMovementActor" // s"${npcName}-npcMovementActor"
// ) // )
lazy val mbNpcNode = PlayerController.Defaults.defaultNpcNode(
val mbNpcNode = PlayerController.Defaults.defaultNpcNode(
assetManager, assetManager,
initialPos, initialPos,
npcPhysicsControl, npcPhysicsControl,
npcName npcName
) )
val npcActorTask = AkkaUtils.spawnActorL2(
val npcActorTask = AkkaUtils.spawnActorL(
NpcActorSupervisor NpcActorSupervisor
.Props( .Props(
new NpcMovementActor.Props( new NpcMovementActor.Props(
@ -302,7 +287,7 @@ class MainAppDelegate(
physicsSpace += npcNode physicsSpace += npcNode
rootNode += npcNode rootNode += npcNode
} }
} yield (npcActor)
} yield npcActor
} }
} }

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

@ -11,15 +11,14 @@ trait MainModule extends ExecutorsModule {
def actorSystemResource( def actorSystemResource(
logger: Logger[Task] logger: Logger[Task]
): Resource[Task, ActorSystem[SpawnProtocol.Command]] = ): Resource[Task, ActorSystem[SpawnProtocol.Command]] =
Resource.make(logger.info("Creating Actor System") >> Task {
ActorSystem(
SpawnProtocol(),
name = "GameActorSystem"
Resource.make(
logger.info("Creating Actor System") >> Task(
ActorSystem(SpawnProtocol(), name = "GameActorSystem")
) )
})(sys =>
)(sys =>
for { for {
_ <- Task(sys.terminate()) _ <- Task(sys.terminate())
_ <- Task.fromFuture(sys.whenTerminated)
_ <- Task.deferFuture(sys.whenTerminated)
_ <- logger.info("Actor System Terminated") _ <- logger.info("Actor System Terminated")
} yield () } yield ()
) )

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

@ -1,11 +1,13 @@
package wow.doge.mygame.game package wow.doge.mygame.game
import cats.effect.Resource
import cats.effect.concurrent.Deferred import cats.effect.concurrent.Deferred
import com.jme3.app.state.AppStateManager import com.jme3.app.state.AppStateManager
import com.jme3.asset.AssetManager import com.jme3.asset.AssetManager
import com.jme3.input.InputManager import com.jme3.input.InputManager
import com.jme3.scene.Node import com.jme3.scene.Node
import com.jme3.scene.Spatial import com.jme3.scene.Spatial
import com.jme3.system.AppSettings
import com.softwaremill.tagging._ import com.softwaremill.tagging._
import com.typesafe.scalalogging.{Logger => SLogger} import com.typesafe.scalalogging.{Logger => SLogger}
import io.odin.Logger import io.odin.Logger
@ -15,7 +17,13 @@ import monix.catnap.ConcurrentChannel
import monix.catnap.ConsumerF import monix.catnap.ConsumerF
import monix.catnap.Semaphore import monix.catnap.Semaphore
import monix.eval.Coeval import monix.eval.Coeval
import monix.execution.CancelablePromise
import monix.execution.Scheduler
import wow.doge.mygame.executors.Schedulers
import wow.doge.mygame.game.subsystems.ui.JFxUI import wow.doge.mygame.game.subsystems.ui.JFxUI
import wow.doge.mygame.implicits._
import monix.execution.annotations.UnsafeBecauseImpure
import monix.reactive.Observable
sealed trait Error sealed trait Error
case object FlyCamNotExists extends Error case object FlyCamNotExists extends Error
@ -40,6 +48,8 @@ class GameApp(logger: Logger[Task], val app: SimpleAppExt) {
def camera = Task(app.getCamera()) def camera = Task(app.getCamera())
def viewPort = Task(app.getViewPort()) def viewPort = Task(app.getViewPort())
def rootNode = Task(app.getRootNode().taggedWith[GameAppTags.RootNode]) def rootNode = Task(app.getRootNode().taggedWith[GameAppTags.RootNode])
def rootNode2 =
WrappedNode(app.getRootNode()).taggedWith[GameAppTags.RootNode]
// def rootNode2 = SynchedObject(app.getRootNode()) // def rootNode2 = SynchedObject(app.getRootNode())
def addToRootNode = rootNode.flatMap(rn => Task(new AddToNode(rn))) def addToRootNode = rootNode.flatMap(rn => Task(new AddToNode(rn)))
def enqueue(cb: () => Unit) = def enqueue(cb: () => Unit) =
@ -55,12 +65,57 @@ class GameApp(logger: Logger[Task], val app: SimpleAppExt) {
} }
object GameApp {
class WrappedNode private (node: Node) {
// def +=(spat: Spatial) = lock.withPermit(Task(node.attachChild(spat)))
def children: Observable[Spatial] = node.observableChildren
def attachChild(n: Node): Task[Unit] = Task(node.attachChild(node))
def add(wn: WrappedNode): Task[Unit] =
Task(node.attachChild(wn.unsafeDelegate))
class WrappedNode(node: Node, lock: Semaphore[Task]) {
/**
* Get the underlying wrapped value
*/
@UnsafeBecauseImpure
def unsafeDelegate = node
}
object WrappedNode {
def +=(spat: Spatial) = lock.withPermit(Task(node.attachChild(spat)))
def apply(name: String) = new WrappedNode(new Node(name))
def apply(n: Node) = new WrappedNode(n)
implicit class WrappedNodeOps(private val wn: WrappedNode) extends AnyVal {
def +=(n: Node) = wn.attachChild(n)
def +=(wn: WrappedNode) = wn.add(wn)
} }
}
object GameApp {
def resource(
logger: Logger[Task],
jmeScheduler: Scheduler,
schedulers: Schedulers
) =
Resource.make(
for {
startSignal <- Task(CancelablePromise[Unit]())
app <- Task(new SimpleAppExt(schedulers, startSignal))
_ <- Task {
val settings = new AppSettings(true)
settings.setVSync(true)
/**
* disables the launcher
* We'll be making our own launcher anyway
*/
app.setShowSettings(false)
app.setSettings(settings)
}
gameApp <- Task(new GameApp(logger, app))
fib <- gameApp.start.executeOn(jmeScheduler).start
_ <- Task.fromCancelablePromise(startSignal)
} yield gameApp -> fib
)(_._2.cancel)
/** /**
* Synchronization wrapper for a mutable object * Synchronization wrapper for a mutable object

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

@ -6,6 +6,7 @@ import akka.actor.typed.SupervisorStrategy
import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.Behaviors
import wow.doge.mygame.game.TickGenerator.Send import wow.doge.mygame.game.TickGenerator.Send
import wow.doge.mygame.game.entities.GenericTimerActor import wow.doge.mygame.game.entities.GenericTimerActor
import wow.doge.mygame.implicits._
import wow.doge.mygame.subsystems.events.EventBus import wow.doge.mygame.subsystems.events.EventBus
import wow.doge.mygame.subsystems.events.EventsModule.GameEventBus import wow.doge.mygame.subsystems.events.EventsModule.GameEventBus
import wow.doge.mygame.subsystems.events.TickEvent import wow.doge.mygame.subsystems.events.TickEvent
@ -28,7 +29,7 @@ object GameAppActor {
) { ) {
def behavior = def behavior =
Behaviors.setup[Command] { ctx => Behaviors.setup[Command] { ctx =>
ctx.log.info("Hello from GameAppActor")
ctx.log.infoP("Hello from GameAppActor")
val renderTickGenerator = val renderTickGenerator =
ctx.spawn( ctx.spawn(
Behaviors Behaviors
@ -78,7 +79,7 @@ object TickGenerator {
object SubscribingActor { object SubscribingActor {
def apply() = def apply() =
Behaviors.receive[PhysicsTick.type] { (ctx, msg) => Behaviors.receive[PhysicsTick.type] { (ctx, msg) =>
ctx.log.debug(s"received event $msg")
ctx.log.debugP(s"received event $msg")
Behaviors.same Behaviors.same
} }
} }

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

@ -1,36 +1,30 @@
package wow.doge.mygame.game package wow.doge.mygame.game
import cats.effect.Resource
import com.jme3.app.StatsAppState
import com.jme3.system.AppSettings
import io.odin.Logger
import monix.bio.Task
import monix.execution.Scheduler
import wow.doge.mygame.executors.Schedulers
class GameAppResource(
logger: Logger[Task],
jmeScheduler: Scheduler,
schedulers: Schedulers
) {
def get: Resource[Task, GameApp] =
Resource.make(
for {
_ <- logger.info("Creating game app")
appExt <- Task(new SimpleAppExt(schedulers, new StatsAppState()))
app <- Task {
val settings = new AppSettings(true)
settings.setVSync(true)
// class GameAppResource(
// logger: Logger[Task],
// jmeScheduler: Scheduler,
// schedulers: Schedulers
// ) {
/**
* disables the launcher
* We'll be making our own launcher anyway
*/
appExt.setShowSettings(false)
appExt.setSettings(settings)
// JMERunner.runner = app
new GameApp(logger, appExt)
}
} yield (app)
)(_ => logger.info("Closing game app"))
}
// def get: Resource[Task, GameApp] =
// Resource.make(
// for {
// _ <- logger.info("Creating game app")
// appExt <- Task(new SimpleAppExt(schedulers, new StatsAppState()))
// app <- Task {
// val settings = new AppSettings(true)
// settings.setVSync(true)
// /**
// * disables the launcher
// * We'll be making our own launcher anyway
// */
// appExt.setShowSettings(false)
// appExt.setSettings(settings)
// // JMERunner.runner = app
// new GameApp(logger, appExt)
// }
// } yield (app)
// )(_ => logger.info("Closing game app"))
// }

30
src/main/scala/wow/doge/mygame/game/SimpleAppExt.scala

@ -6,17 +6,15 @@ import com.jme3.app.SimpleApplication
import com.jme3.app.state.AppState import com.jme3.app.state.AppState
import monix.bio.Task import monix.bio.Task
import monix.execution.CancelableFuture import monix.execution.CancelableFuture
import monix.execution.CancelablePromise
import monix.execution.Scheduler import monix.execution.Scheduler
import monix.execution.atomic.Atomic import monix.execution.atomic.Atomic
import monix.execution.{CancelablePromise => Promise}
import monix.reactive.MulticastStrategy
import monix.reactive.Observable
import monix.reactive.subjects.ConcurrentSubject
import wow.doge.mygame.executors.GUIExecutorService import wow.doge.mygame.executors.GUIExecutorService
import wow.doge.mygame.executors.Schedulers import wow.doge.mygame.executors.Schedulers
class SimpleAppExt( class SimpleAppExt(
schedulers: Schedulers, schedulers: Schedulers,
startSignal: CancelablePromise[Unit],
appStates: AppState* appStates: AppState*
) extends SimpleApplication(appStates: _*) { ) extends SimpleApplication(appStates: _*) {
import SimpleAppExt._ import SimpleAppExt._
@ -26,32 +24,26 @@ class SimpleAppExt(
*/ */
private lazy val taskQueue2 = Atomic(Queue.empty[MyTask[_]]) private lazy val taskQueue2 = Atomic(Queue.empty[MyTask[_]])
private val tickSubject =
ConcurrentSubject[Float](multicast = MulticastStrategy.publish)(
schedulers.async
)
// def tickObservable: Observable[Float] = tickSubject
def tickObservable: Observable[Float] = tickSubject
override def simpleInitApp(): Unit = {}
override def simpleUpdate(tpf: Float): Unit = {
tickSubject.onNext(tpf)
override def simpleInitApp(): Unit = {
startSignal.success(())
} }
override def simpleUpdate(tpf: Float): Unit = {}
override def stop(): Unit = { override def stop(): Unit = {
tickSubject.onComplete()
super.stop() super.stop()
} }
def enqueueScala[T](cb: () => T): CancelableFuture[T] = {
val p = Promise[T]()
def enqueueFuture[T](cb: () => T): CancelableFuture[T] = {
val p = CancelablePromise[T]()
taskQueue2.transform(_ :+ MyTask(p, cb)) taskQueue2.transform(_ :+ MyTask(p, cb))
p.future p.future
} }
def enqueueL[T](cb: () => T): Task[T] = def enqueueL[T](cb: () => T): Task[T] =
Task.deferFuture(enqueueScala(cb))
Task.deferFuture(enqueueFuture(cb))
override protected def runQueuedTasks(): Unit = { override protected def runQueuedTasks(): Unit = {
taskQueue2.transform { current => taskQueue2.transform { current =>
@ -73,7 +65,7 @@ class SimpleAppExt(
lazy val scheduler = Scheduler(JMEExecutorService) lazy val scheduler = Scheduler(JMEExecutorService)
} }
object SimpleAppExt { object SimpleAppExt {
private[game] case class MyTask[T](p: Promise[T], cb: () => T)
private[game] case class MyTask[T](p: CancelablePromise[T], cb: () => T)
} }
// val ship = ed.createEntity() // val ship = ed.createEntity()

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

@ -36,11 +36,11 @@ object TestActor {
// ) // )
// ) { // ) {
// case Success(value) => // case Success(value) =>
// ctx.log.debug("Received Value")
// ctx.log.debug(value.toString())
// ctx.log.debugP("Received Value")
// ctx.log.debugP(value.toString())
// Done // Done
// case Failure(exception) => // case Failure(exception) =>
// ctx.log.debug(s"Received Error ${exception.getMessage()}")
// ctx.log.debugP(s"Received Error ${exception.getMessage()}")
// Done // Done
// } // }
} }
@ -60,24 +60,24 @@ object TestActor {
// .Get(os.pwd / "src" / "main" / "resources" / "hello2.sc", _) // .Get(os.pwd / "src" / "main" / "resources" / "hello2.sc", _)
// ) { // ) {
// case Success(value) => { // case Success(value) => {
// ctx.log.debug(value.toString())
// ctx.log.debugP(value.toString())
// ctx.ask( // ctx.ask(
// scriptStorer, // scriptStorer,
// ScriptStoringActor // ScriptStoringActor
// .Get(os.pwd / "src" / "main" / "resources" / "hello2.sc", _) // .Get(os.pwd / "src" / "main" / "resources" / "hello2.sc", _)
// ) { // ) {
// case Success(value) => { // case Success(value) => {
// ctx.log.debug(value.toString())
// ctx.log.debugP(value.toString())
// Done // Done
// } // }
// case Failure(exception) => // case Failure(exception) =>
// ctx.log.debug(exception.getMessage())
// ctx.log.debugP(exception.getMessage())
// Done // Done
// } // }
// Done // Done
// } // }
// case Failure(exception) => // case Failure(exception) =>
// ctx.log.debug(exception.getMessage())
// ctx.log.debugP(exception.getMessage())
// Done // Done
// } // }
} }

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

@ -193,23 +193,23 @@ class MovementActor(
// val walkDir = new Vector3f // val walkDir = new Vector3f
val dir = state.cardinalDir val dir = state.cardinalDir
if (dir.up) { if (dir.up) {
ctx.log.debug("up")
// ctx.log.debug(Thread.currentThread().getName())
ctx.log.debugP("up")
// ctx.log.debugP(Thread.currentThread().getName())
// walkDir.addLocal(0, 0, -1) // walkDir.addLocal(0, 0, -1)
walkDir += camDir walkDir += camDir
} }
if (dir.left) { if (dir.left) {
ctx.log.debug("left")
ctx.log.debugP("left")
// walkDir.addLocal(-1, 0, 0) // walkDir.addLocal(-1, 0, 0)
walkDir.addLocal(camLeft) walkDir.addLocal(camLeft)
} }
if (dir.right) { if (dir.right) {
ctx.log.debug("right")
ctx.log.debugP("right")
// walkDir.addLocal(1, 0, 0) // walkDir.addLocal(1, 0, 0)
walkDir.addLocal(camLeft.negateLocal()) walkDir.addLocal(camLeft.negateLocal())
} }
if (dir.down) { if (dir.down) {
ctx.log.debug("down")
ctx.log.debugP("down")
walkDir.addLocal(camDir.negateLocal()) walkDir.addLocal(camDir.negateLocal())
// walkDir.addLocal(0, 0, 1) // walkDir.addLocal(0, 0, 1)
} }

30
src/main/scala/wow/doge/mygame/game/entities/NpcActorSupervisor.scala

@ -39,6 +39,8 @@ object NpcActorSupervisor {
private case class LogError(err: Throwable) extends Command private case class LogError(err: Throwable) extends Command
private case object NoOp extends Command private case object NoOp extends Command
private case class MovementFailed(err: Throwable) extends Command
final case class Props( final case class Props(
npcMovementActorBehavior: Behavior[NpcMovementActor.Command], npcMovementActorBehavior: Behavior[NpcMovementActor.Command],
npcName: String, npcName: String,
@ -82,7 +84,7 @@ class NpcActorSupervisor(
def idle(state: State): Behavior[NpcActorSupervisor.Command] = def idle(state: State): Behavior[NpcActorSupervisor.Command] =
Behaviors.setup { _ => Behaviors.setup { _ =>
ctx.log.debug("Inside Idle State")
ctx.log.debugP("Inside Idle State")
Behaviors.receiveMessage[Command] { Behaviors.receiveMessage[Command] {
case m @ Move(pos) => case m @ Move(pos) =>
ctx.ask( ctx.ask(
@ -97,7 +99,7 @@ class NpcActorSupervisor(
moving(state, move.pos, signal) moving(state, move.pos, signal)
case LogError(err) => case LogError(err) =>
ctx.log.warn(err.getMessage())
ctx.log.warnP(err.getMessage())
Behaviors.same Behaviors.same
case _ => Behaviors.unhandled case _ => Behaviors.unhandled
} }
@ -117,12 +119,16 @@ class NpcActorSupervisor(
// ) // )
ctx.pipeToSelf(signal) { ctx.pipeToSelf(signal) {
case Success(value) => DoneMoving case Success(value) => DoneMoving
case Failure(exception) => LogError(exception)
case Failure(exception) => MovementFailed(exception)
} }
Behaviors.receiveMessagePartial[Command] { Behaviors.receiveMessagePartial[Command] {
case LogError(err) => case LogError(err) =>
ctx.log.error(err.getMessage()) ctx.log.error(err.getMessage())
Behaviors.same Behaviors.same
case MovementFailed(err) =>
ctx.self ! LogError(err)
movementTimer ! GenericTimerActor.Stop
idle(state)
case m @ Move(pos) => case m @ Move(pos) =>
movementTimer ! GenericTimerActor.Stop movementTimer ! GenericTimerActor.Stop
children.npcMovementActor ! NpcMovementActor.StopMoving children.npcMovementActor ! NpcMovementActor.StopMoving
@ -132,7 +138,7 @@ class NpcActorSupervisor(
NpcMovementActor.MoveTo(pos, _) NpcMovementActor.MoveTo(pos, _)
) { ) {
case Success(signal) => InternalMove(m, signal) case Success(signal) => InternalMove(m, signal)
case Failure(exception) => LogError(exception)
case Failure(exception) => MovementFailed(exception)
} }
Behaviors.same Behaviors.same
case InternalMove(move, signal) => case InternalMove(move, signal) =>
@ -190,12 +196,6 @@ class NpcMovementActor[T](
case AskPosition(replyTo) => case AskPosition(replyTo) =>
replyTo ! location replyTo ! location
Behaviors.same Behaviors.same
case StopMoving =>
ctx.log.debug(
"Position at Stop = " + location.toString
)
props.enqueueR(() => cm.stop(props.movable))
receive(state)
case MoveTo( case MoveTo(
target: ImVector3f, target: ImVector3f,
replyTo: ActorRef[CancelableFuture[DoneMoving.type]] replyTo: ActorRef[CancelableFuture[DoneMoving.type]]
@ -204,7 +204,6 @@ class NpcMovementActor[T](
val p = CancelablePromise[DoneMoving.type]() val p = CancelablePromise[DoneMoving.type]()
replyTo ! p.future replyTo ! p.future
ticking(p, target, state) ticking(p, target, state)
} }
def ticking( def ticking(
@ -214,7 +213,7 @@ class NpcMovementActor[T](
): Behavior[NpcMovementActor.Command] = ): Behavior[NpcMovementActor.Command] =
Behaviors.receiveMessagePartial { Behaviors.receiveMessagePartial {
case StopMoving => case StopMoving =>
ctx.log.debug(
ctx.log.debugP(
"Position at Stop = " + location.toString "Position at Stop = " + location.toString
) )
props.enqueueR(() => cm.stop(props.movable)) props.enqueueR(() => cm.stop(props.movable))
@ -225,12 +224,11 @@ class NpcMovementActor[T](
if (dst <= 10f) { if (dst <= 10f) {
ctx.self ! StopMoving ctx.self ! StopMoving
reachDestination.success(DoneMoving) reachDestination.success(DoneMoving)
receive(state)
} else { } else {
ctx.log.trace("Difference = " + dst.toString())
ctx.log.trace("Current pos = " + location.toString())
Behaviors.same
ctx.log.traceP("Difference = " + dst.toString())
ctx.log.traceP("Current pos = " + location.toString())
} }
Behaviors.same
} }
} }

2
src/main/scala/wow/doge/mygame/game/entities/player/PlayerActorSupervisor.scala

@ -39,7 +39,7 @@ object PlayerActorSupervisor {
ctx.log.info("Hello from PlayerActor") ctx.log.info("Hello from PlayerActor")
// spawn children actors // spawn children actors
lazy val movementActor =
val movementActor =
ctx.spawn( ctx.spawn(
Behaviors Behaviors
.supervise(imMovementActorBehavior) .supervise(imMovementActorBehavior)

55
src/main/scala/wow/doge/mygame/game/entities/player/PlayerController.scala

@ -29,6 +29,7 @@ import wow.doge.mygame.subsystems.events.PlayerEvent
import wow.doge.mygame.subsystems.events.TickEvent import wow.doge.mygame.subsystems.events.TickEvent
import wow.doge.mygame.subsystems.movement.ImMovementActor import wow.doge.mygame.subsystems.movement.ImMovementActor
import wow.doge.mygame.utils.AkkaUtils import wow.doge.mygame.utils.AkkaUtils
import com.softwaremill.macwire._
object PlayerControllerTags { object PlayerControllerTags {
sealed trait PlayerTag sealed trait PlayerTag
@ -47,7 +48,6 @@ object PlayerController {
loggerL: Logger[Task], loggerL: Logger[Task],
physicsSpace: PhysicsSpace, physicsSpace: PhysicsSpace,
initialPlayerPos: ImVector3f = ImVector3f.ZERO, initialPlayerPos: ImVector3f = ImVector3f.ZERO,
spawnProtocol: ActorRef[SpawnProtocol.Command],
playerEventBus: GameEventBus[PlayerEvent], playerEventBus: GameEventBus[PlayerEvent],
playerPhysicsControl: BetterCharacterControl, playerPhysicsControl: BetterCharacterControl,
appScheduler: monix.execution.Scheduler, appScheduler: monix.execution.Scheduler,
@ -56,29 +56,34 @@ object PlayerController {
cameraPivotNode: Node @@ PlayerControllerTags.PlayerCameraPivotNode, cameraPivotNode: Node @@ PlayerControllerTags.PlayerCameraPivotNode,
tickEventBus: GameEventBus[TickEvent], tickEventBus: GameEventBus[TickEvent],
camera: Camera camera: Camera
)(implicit timeout: Timeout, scheduler: Scheduler) {
)(implicit
spawnProtocol: ActorRef[SpawnProtocol.Command],
timeout: Timeout,
scheduler: Scheduler
) {
val playerActorBehavior = {
val movementActorBeh = new ImMovementActor.Props(
enqueueR,
playerPhysicsControl,
camera
).behavior
val cameraActorBeh = new PlayerCameraActor.Props(
cameraPivotNode,
enqueueR,
playerNode.getWorldTranslation _
).behavior
new PlayerActorSupervisor.Props(
playerEventBus,
tickEventBus,
movementActorBeh,
cameraActorBeh
).behavior(playerPhysicsControl)
}
val create: IO[Error, Unit] = val create: IO[Error, Unit] =
(for { (for {
playerActor <- AkkaUtils.spawnActorL( playerActor <- AkkaUtils.spawnActorL(
spawnProtocol,
"playerActorSupervisor",
new PlayerActorSupervisor.Props(
playerEventBus,
// playerCameraEventBus,
tickEventBus,
new ImMovementActor.Props(
enqueueR,
playerPhysicsControl,
camera
).behavior,
// wireWith(PlayerCameraEventListener.apply _)
// PlayerCameraEventListener()
new PlayerCameraActor.Props(
cameraPivotNode,
enqueueR,
playerNode.getWorldTranslation _
).behavior
).behavior(playerPhysicsControl)
playerActorBehavior,
"playerActorSupervisor"
) )
_ <- Task(rootNode += playerNode) _ <- Task(rootNode += playerNode)
_ <- IO { _ <- IO {
@ -88,9 +93,7 @@ object PlayerController {
cameraPivotNode += cameraNode cameraPivotNode += cameraNode
// playerNode += cameraPivotNode // playerNode += cameraPivotNode
rootNode += cameraPivotNode rootNode += cameraPivotNode
} }
} yield ()) } yield ())
.onErrorHandleWith(e => IO.raiseError(GenericError(e.getMessage()))) .onErrorHandleWith(e => IO.raiseError(GenericError(e.getMessage())))
.executeOn(appScheduler) .executeOn(appScheduler)
@ -101,10 +104,10 @@ object PlayerController {
modelPath: os.RelPath, modelPath: os.RelPath,
cam: Camera cam: Camera
)(assetManager: AssetManager, bulletAppState: BulletAppState) = { )(assetManager: AssetManager, bulletAppState: BulletAppState) = {
lazy val playerPos = ImVector3f.ZERO
lazy val playerPhysicsControl = new BetterCharacterControl(1.5f, 6f, 1f)
val playerPos = ImVector3f.ZERO
val playerPhysicsControl = new BetterCharacterControl(1.5f, 6f, 1f)
.withJumpForce(ImVector3f(0, 5f, 0)) .withJumpForce(ImVector3f(0, 5f, 0))
lazy val playerNode = new Node("PlayerNode")
val playerNode = new Node("PlayerNode")
.withChildren( .withChildren(
assetManager assetManager
.loadModel(modelPath) .loadModel(modelPath)

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

@ -18,10 +18,11 @@ import wow.doge.mygame.subsystems.events.PlayerCameraEvent
import wow.doge.mygame.subsystems.events.PlayerEvent import wow.doge.mygame.subsystems.events.PlayerEvent
import wow.doge.mygame.subsystems.events.PlayerMovementEvent import wow.doge.mygame.subsystems.events.PlayerMovementEvent
import wow.doge.mygame.utils.IOUtils._ import wow.doge.mygame.utils.IOUtils._
import monix.bio.Task
object GameInputHandler { object GameInputHandler {
final class Props(
class Props(
inputManager: InputManager, inputManager: InputManager,
playerEventBus: GameEventBus[PlayerEvent] playerEventBus: GameEventBus[PlayerEvent]
// playerCameraEventBus: GameEventBus[PlayerCameraEvent] // playerCameraEventBus: GameEventBus[PlayerCameraEvent]
@ -29,44 +30,44 @@ object GameInputHandler {
) { ) {
def begin = def begin =
for { for {
_ <- UIO(setupMovementKeys(inputManager))
_ <- Task(setupMovementKeys(inputManager))
// _ <- UIO(setupAnalogMovementKeys) // _ <- UIO(setupAnalogMovementKeys)
_ <- UIO(setupCameraKeys())
_ <- Task(setupCameraKeys())
_ <- toIO( _ <- toIO(
generateMovementInputEvents(
inputManager,
playerEventBus
).completedL.startAndForget
)
_ <- toIO(
generateAnalogMovementEvents(
inputManager,
playerEventBus
).completedL.startAndForget
)
_ <- toIO(
generateCameraEvents(
inputManager,
playerEventBus
).completedL.startAndForget
)
_ <- toIO(
Ref.of[me.Task, Boolean](false).flatMap(value => cursorToggle(value))
)
me.Task.parSequence(
Seq(
generateMovementInputEvents(
inputManager,
playerEventBus
).completedL,
// generateAnalogMovementEvents(
// inputManager,
// playerEventBus
// ).completedL,
generateCameraEvents(
inputManager,
playerEventBus
).completedL,
Ref
.of[me.Task, Boolean](false)
.flatMap(value => cursorToggle(value))
)
)
).startAndForget
} yield () } yield ()
def setupMovementKeys(inputManager: InputManager) = def setupMovementKeys(inputManager: InputManager) =
inputManager.withEnumMappings(PlayerMovementInput) { inputManager.withEnumMappings(PlayerMovementInput) {
case PlayerMovementInput.WalkRight => case PlayerMovementInput.WalkRight =>
Seq(new KeyTrigger(KeyInput.KEY_D))
new KeyTrigger(KeyInput.KEY_D) :: Nil
case PlayerMovementInput.WalkLeft => case PlayerMovementInput.WalkLeft =>
Seq(new KeyTrigger(KeyInput.KEY_A))
new KeyTrigger(KeyInput.KEY_A) :: Nil
case PlayerMovementInput.WalkForward => case PlayerMovementInput.WalkForward =>
Seq(new KeyTrigger(KeyInput.KEY_W))
new KeyTrigger(KeyInput.KEY_W) :: Nil
case PlayerMovementInput.WalkBackward => case PlayerMovementInput.WalkBackward =>
Seq(new KeyTrigger(KeyInput.KEY_S))
new KeyTrigger(KeyInput.KEY_S) :: Nil
case PlayerMovementInput.Jump => case PlayerMovementInput.Jump =>
Seq(new KeyTrigger(KeyInput.KEY_SPACE))
new KeyTrigger(KeyInput.KEY_SPACE) :: Nil
} }
def setupAnalogMovementKeys() = def setupAnalogMovementKeys() =
@ -124,7 +125,6 @@ object GameInputHandler {
} }
) )
.completedL .completedL
.startAndForget
} yield () } yield ()
} }

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

@ -14,15 +14,15 @@ object DefaultGameLevel {
assetManager: AssetManager, assetManager: AssetManager,
viewPort: ViewPort viewPort: ViewPort
) = { ) = {
lazy val sceneModel: Spatial = assetManager.loadModel("main.scene")
lazy val sceneShape = CollisionShapeFactory.createMeshShape(
val sceneModel: Spatial = assetManager.loadModel("main.scene")
val sceneShape = CollisionShapeFactory.createMeshShape(
sceneModel.toNode match { sceneModel.toNode match {
case Right(node) => node case Right(node) => node
case Left(ex) => case Left(ex) =>
throw new NotImplementedError("No fallback sceneshape") throw new NotImplementedError("No fallback sceneshape")
} }
) )
lazy val landscape: RigidBodyControl =
val landscape: RigidBodyControl =
new RigidBodyControl(sceneShape, 0) new RigidBodyControl(sceneShape, 0)
viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f)) viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f))

30
src/main/scala/wow/doge/mygame/game/subsystems/movement/CanMove2.scala

@ -1,5 +1,6 @@
package wow.doge.mygame.game.subsystems.movement package wow.doge.mygame.game.subsystems.movement
import cats.Id
import com.jme3.bullet.control.BetterCharacterControl 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
@ -8,7 +9,6 @@ import monix.eval.Coeval
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.subsystems.movement.RotateDir import wow.doge.mygame.subsystems.movement.RotateDir
// experiment to see if it would be useful to use an effect wrapper for a typeclass like this // experiment to see if it would be useful to use an effect wrapper for a typeclass like this
trait CanMove2[-A, F[_]] { trait CanMove2[-A, F[_]] {
// def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f // def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f
@ -19,7 +19,35 @@ trait CanMove2[-A, F[_]] {
def rotate(inst: A, rotateDir: RotateDir): F[Unit] def rotate(inst: A, rotateDir: RotateDir): F[Unit]
} }
object Test {
val x = new BetterCharacterControl(4, 10, 5)
def test[T](x: T)(implicit cm: CanMove2[T, Id]) = {
cm.move(x, ImVector3f.ZERO)
}
}
object CanMove2 { object CanMove2 {
implicit val testImpl = new CanMove2[BetterCharacterControl, Id] {
override def move(
inst: BetterCharacterControl,
direction: ImVector3f,
speedFactor: Float
): Id[Unit] = {}
override def location(inst: BetterCharacterControl): Id[ImVector3f] =
ImVector3f.ZERO
override def jump(inst: BetterCharacterControl): Id[Unit] = ???
override def stop(inst: BetterCharacterControl): Id[Unit] = ???
override def rotate(
inst: BetterCharacterControl,
rotateDir: RotateDir
): Id[Unit] = ???
}
implicit val implCanMoveForBetterCharacterControl = implicit val implCanMoveForBetterCharacterControl =
new CanMove2[BetterCharacterControl, Coeval] { new CanMove2[BetterCharacterControl, Coeval] {
override def move( override def move(

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

@ -84,7 +84,7 @@ class ImMovementActor[T](
case Tick => case Tick =>
val walkDir = val walkDir =
getDirection2(state.cardinalDir, ctx.log.trace)
getDirection2(state.cardinalDir, ctx.log.traceP)
// if (walkDir != ImVector3f.ZERO) { // if (walkDir != ImVector3f.ZERO) {
val tmp = walkDir * 25f * (1f / 144) val tmp = walkDir * 25f * (1f / 144)
props.enqueueR { () => props.enqueueR { () =>
@ -94,7 +94,10 @@ class ImMovementActor[T](
Behaviors.same Behaviors.same
} }
def getDirection2(cardinalDir: CardinalDirection, debug: String => Unit) = {
def getDirection2(
cardinalDir: CardinalDirection,
debug: sourcecode.Text[String] => sourcecode.Text[String]
) = {
val camDir = val camDir =
props.camera.getDirection().clone().normalizeLocal.multLocal(0.6f) props.camera.getDirection().clone().normalizeLocal.multLocal(0.6f)
val camLeft = props.camera.getLeft().clone().normalizeLocal.multLocal(0.4f) val camLeft = props.camera.getLeft().clone().normalizeLocal.multLocal(0.4f)

32
src/main/scala/wow/doge/mygame/implicits/JavaFXMonixObservables.scala

@ -1,11 +1,14 @@
package wow.doge.mygame.implicits package wow.doge.mygame.implicits
import javafx.beans.value.ObservableValue
import javafx.beans.{value => jfxbv}
import javafx.scene.{input => jfxsi} import javafx.scene.{input => jfxsi}
import javafx.{event => jfxe} import javafx.{event => jfxe}
import monix.execution.Ack import monix.execution.Ack
import monix.execution.Cancelable import monix.execution.Cancelable
import monix.reactive.Observable import monix.reactive.Observable
import monix.reactive.OverflowStrategy import monix.reactive.OverflowStrategy
import scalafx.beans.property.Property
import scalafx.scene.Scene import scalafx.scene.Scene
import scalafx.scene.control.ButtonBase import scalafx.scene.control.ButtonBase
@ -55,6 +58,35 @@ object JavaFXMonixObservables {
} }
} }
implicit final class BindObs[A, B](private val prop: Property[A, B])
extends AnyVal {
def <--[T](op: Observable[(ObservableValue[_ <: B], B, B)] => T) = {
op(prop.observableChange())
}
def observableChange(): Observable[(ObservableValue[_ <: B], B, B)] = {
import monix.execution.cancelables.SingleAssignCancelable
Observable.create(OverflowStrategy.Unbounded) { sub =>
val c = SingleAssignCancelable()
val listener = new jfxbv.ChangeListener[B] {
override def changed(
observable: ObservableValue[_ <: B],
oldValue: B,
newValue: B
): Unit = {
sub.onNext((observable, oldValue, newValue))
}
}
prop.addListener(listener)
c := Cancelable(() => prop.removeListener(listener))
c
}
}
}
implicit final class OnActionObservable( implicit final class OnActionObservable(
private val button: ButtonBase private val button: ButtonBase
) extends AnyVal { ) extends AnyVal {

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

@ -49,6 +49,7 @@ import monix.execution.cancelables.SingleAssignCancelable
import monix.reactive.Observable import monix.reactive.Observable
import monix.reactive.OverflowStrategy import monix.reactive.OverflowStrategy
import monix.reactive.observers.Subscriber import monix.reactive.observers.Subscriber
import org.slf4j.Logger
import wow.doge.mygame.math.ImVector3f import wow.doge.mygame.math.ImVector3f
import wow.doge.mygame.state.MyBaseState import wow.doge.mygame.state.MyBaseState
@ -794,4 +795,67 @@ package object implicits {
def +=(node: scalafx.scene.Node) = jfxui.attachChild(node) def +=(node: scalafx.scene.Node) = jfxui.attachChild(node)
def -=(node: scalafx.scene.Node) = jfxui.detachChild(node) def -=(node: scalafx.scene.Node) = jfxui.detachChild(node)
} }
implicit class AkkaLoggerExt(private val logger: Logger) extends AnyVal {
def logP[T](
x: sourcecode.Text[T],
tag: String = "",
width: Int = 100,
height: Int = 500,
indent: Int = 2,
initialOffset: Int = 0
)(implicit line: sourcecode.Line, fileName: sourcecode.FileName) = {
// def joinSeq[T](seq: Seq[T], sep: T): Seq[T] = {
// seq.flatMap(x => Seq(x, sep)).dropRight(1)
// }
val tagStrs =
if (tag.isEmpty) Seq.empty
else Seq(fansi.Color.Cyan(tag), fansi.Str(" "))
val prefix = Seq(
fansi.Color.Magenta(fileName.value),
fansi.Str(":"),
fansi.Color.Green(line.value.toString),
fansi.Str(" "),
fansi.Color.Cyan(x.source),
fansi.Str(": ")
) ++ tagStrs
fansi.Str.join(
prefix ++ pprint.tokenize(x.value, width, height, indent).toSeq: _*
)
// x.value
}
def warnP[T](
s: sourcecode.Text[T]
)(implicit line: sourcecode.Line, fileName: sourcecode.FileName) = {
logger.warn(logP(s).render)
s
}
def errorP[T](
s: sourcecode.Text[T]
)(implicit line: sourcecode.Line, fileName: sourcecode.FileName) = {
logger.error(logP(s).render)
s
}
def infoP[T](
s: sourcecode.Text[T]
)(implicit line: sourcecode.Line, fileName: sourcecode.FileName) = {
logger.info(logP(s).render)
s
}
def debugP[T](
s: sourcecode.Text[T]
)(implicit line: sourcecode.Line, fileName: sourcecode.FileName) = {
logger.debug(logP(s).render)
s
}
def traceP[T](
s: sourcecode.Text[T]
)(implicit line: sourcecode.Line, fileName: sourcecode.FileName) = {
logger.trace(logP(s).render)
s
}
}
} }

118
src/main/scala/wow/doge/mygame/launcher/Launcher.scala

@ -1,28 +1,31 @@
package wow.doge.mygame.launcher package wow.doge.mygame.launcher
import scala.concurrent.duration.FiniteDuration
import scala.concurrent.duration._
import cats.effect.concurrent.Deferred import cats.effect.concurrent.Deferred
import javafx.application.Platform import javafx.application.Platform
import javafx.beans.value.ObservableValue
import monix.bio.Task import monix.bio.Task
import monix.catnap.CancelableF import monix.catnap.CancelableF
import monix.eval.{Task => ETask}
import monix.execution.CancelablePromise
import monix.reactive.Observable import monix.reactive.Observable
import monix.{eval => me}
import scalafx.Includes._ import scalafx.Includes._
import scalafx.application.JFXApp import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage import scalafx.application.JFXApp.PrimaryStage
import scalafx.beans.property.StringProperty
import scalafx.scene.control.Button import scalafx.scene.control.Button
import scalafx.stage.StageStyle import scalafx.stage.StageStyle
import wow.doge.mygame.executors.Schedulers import wow.doge.mygame.executors.Schedulers
import wow.doge.mygame.implicits.JavaFXMonixObservables._ import wow.doge.mygame.implicits.JavaFXMonixObservables._
import wow.doge.mygame.utils.IOUtils._ import wow.doge.mygame.utils.IOUtils._
import cats.effect.Resource
import cats.kernel.Eq
object Launcher { object Launcher {
sealed trait LauncherResult sealed trait LauncherResult
object LauncherResult { object LauncherResult {
case object LaunchGame extends LauncherResult case object LaunchGame extends LauncherResult
case object Exit extends LauncherResult case object Exit extends LauncherResult
implicit val eqForLR = Eq.fromUniversalEquals[LauncherResult]
} }
class Props( class Props(
@ -44,10 +47,23 @@ class Launcher private (props: Launcher.Props) {
.observableAction() .observableAction()
.doOnNext(_ => toTask(props.signal.complete(LauncherResult.LaunchGame))) .doOnNext(_ => toTask(props.signal.complete(LauncherResult.LaunchGame)))
def testChangeObs(
obs: Observable[(ObservableValue[_ <: String], String, String)]
) =
obs
.doOnNext {
case (x, y, z) => monix.eval.Task.unit
}
// .subscribe()
private lazy val exitButton = new Button { private lazy val exitButton = new Button {
text = "Exit" text = "Exit"
// text <-- testChangeObs
} }
// exitButton.text.bind
StringProperty("") addListener ((_, _, _) => ())
private lazy val exitAction = private lazy val exitAction =
exitButton exitButton
.observableAction() .observableAction()
@ -60,22 +76,25 @@ class Launcher private (props: Launcher.Props) {
scene = _scene scene = _scene
} }
private lazy val internal = new JFXApp {
stage = _stage
stage.initStyle(StageStyle.Undecorated)
// ResizeHelper.addResizeListener(stage)
}
private def internal(startSignal: CancelablePromise[Unit]) =
new JFXApp {
stage = _stage
stage.initStyle(StageStyle.Undecorated)
// ResizeHelper.addResizeListener(stage)
startSignal.success(())
}
private lazy val sceneDragObservable = { private lazy val sceneDragObservable = {
lazy val mpo = _scene.observableMousePressed()
lazy val mdo = _scene.observableMouseDragged()
val mpo = _scene.observableMousePressed()
val mdo = _scene.observableMouseDragged()
mpo.mergeMap(pressEvent =>
mpo.concatMap(pressEvent =>
mdo.doOnNext(dragEvent => mdo.doOnNext(dragEvent =>
ETask(
_stage.setX(dragEvent.screenX - pressEvent.sceneX)
) >>
ETask(
me.Task(pprint.log("emitted")) >>
me.Task(
_stage.setX(dragEvent.screenX - pressEvent.sceneX)
) >>
me.Task(
_stage.setY( _stage.setY(
dragEvent.screenY - pressEvent.sceneY dragEvent.screenY - pressEvent.sceneY
) )
@ -84,21 +103,58 @@ class Launcher private (props: Launcher.Props) {
) )
} }
def init(delay: FiniteDuration = 2000.millis) =
for {
// import cats.syntax.all._
// def init(delay: FiniteDuration = 2000.millis) =
// for {
// _ <- Task(Platform.setImplicitExit(false))
// x <- (Task.unit.start, Task.unit.start).parTupled
// fxAppStartFib <- Task(internal.main(Array.empty)).start
// _ <- Task.sleep(500.millis)
// sceneDragFib <- toIO(sceneDragObservable.completedL).start
// buttonActionsComposedFib <- toIO(
// Observable(launchAction, exitAction).merge
// .doOnNext(_ =>
// me.Task(internal.stage.close()).executeOn(props.schedulers.fx)
// )
// .completedL
// ).start
// c <- CancelableF[Task](
// fxAppStartFib.cancel >> buttonActionsComposedFib.cancel >> sceneDragFib.cancel
// )
// } yield (c)
def init =
Resource.make(for {
_ <- Task(Platform.setImplicitExit(false)) _ <- Task(Platform.setImplicitExit(false))
fib <- Task(internal.main(Array.empty)).start
_ <- Task.sleep(500.millis)
sceneDragFib <- toIO(sceneDragObservable.completedL).start
fib2 <- toIO(
Observable(launchAction, exitAction).merge
.doOnNext(_ =>
ETask(internal.stage.close()).executeOn(props.schedulers.fx)
startSignal <- Task(CancelablePromise[Unit]())
delegate <- Task(internal(startSignal))
combinedFib <-
Task
.parZip2(
Task(delegate.main(Array.empty)),
Task.fromCancelablePromise(startSignal) >> toIO(
me.Task.parSequence(
List(
sceneDragObservable.completedL,
Observable(launchAction, exitAction).merge
.doOnNext(_ =>
me.Task(delegate.stage.close())
.executeOn(props.schedulers.fx)
)
.completedL
)
)
)
) )
.completedL
).start
c <- CancelableF[Task](fib.cancel >> fib2.cancel >> sceneDragFib.cancel)
} yield (c)
.start
c <- CancelableF[Task](
// Task(println("Cancelling")) >>
// combinedFib.cancel >>
// fxAppStartFib.cancel
// Task.unit
combinedFib.cancel
)
} yield c)(_.cancel)
} }

14
src/main/scala/wow/doge/mygame/subsystems/events/EventsModule.scala

@ -18,22 +18,22 @@ import wow.doge.mygame.subsystems.events.EventBus
import wow.doge.mygame.subsystems.events.TickEvent import wow.doge.mygame.subsystems.events.TickEvent
class EventsModule(spawnProtocol: ActorSystem[SpawnProtocol.Command]) { class EventsModule(spawnProtocol: ActorSystem[SpawnProtocol.Command]) {
implicit lazy val s = spawnProtocol.scheduler
implicit val s = spawnProtocol.scheduler
implicit lazy val timeout = Timeout(1.second)
implicit val timeout = Timeout(1.second)
lazy val eventBusLogger = SLogger[EventBus[_]]
val eventBusLogger = SLogger[EventBus[_]]
lazy val playerEventBusTask =
val playerEventBusTask =
createEventBus[PlayerEvent]("playerEventBus") createEventBus[PlayerEvent]("playerEventBus")
// lazy val playerCameraEventBusTask =
// val playerCameraEventBusTask =
// createEventBus[PlayerCameraEvent]("playerCameraEventBus", Level.DEBUG) // createEventBus[PlayerCameraEvent]("playerCameraEventBus", Level.DEBUG)
lazy val tickEventBusTask =
val tickEventBusTask =
createEventBus[TickEvent]("tickEventBus", Level.TRACE) createEventBus[TickEvent]("tickEventBus", Level.TRACE)
lazy val mainEventBusTask = createEventBus[Event]("mainEventBus")
val mainEventBusTask = createEventBus[Event]("mainEventBus")
def createEventBus[T](busName: String, logLevel: Level = Level.DEBUG) = def createEventBus[T](busName: String, logLevel: Level = Level.DEBUG) =
spawnProtocol.askL( spawnProtocol.askL(

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

@ -41,7 +41,7 @@ object ScriptActor {
result: ActorRef[Map[os.Path, Either[Error, Any]]] result: ActorRef[Map[os.Path, Either[Error, Any]]]
) extends Command ) extends Command
lazy val defaultScalaRunner =
val defaultScalaRunner =
ammonite ammonite
.Main( .Main(
storageBackend = new Folder( storageBackend = new Folder(
@ -51,13 +51,13 @@ object ScriptActor {
) )
) )
lazy val defaultKotlinRunner: KotlinScriptEngine = {
val defaultKotlinRunner: KotlinScriptEngine = {
val manager = new ScriptEngineManager() val manager = new ScriptEngineManager()
val engine = manager.getEngineByExtension("main.kts") val engine = manager.getEngineByExtension("main.kts")
engine.taggedWith[Kotlin] engine.taggedWith[Kotlin]
} }
lazy val defaultGroovyRunner: GroovyScriptEngine =
val defaultGroovyRunner: GroovyScriptEngine =
new GroovyScriptEngine(os.pwd.toString) new GroovyScriptEngine(os.pwd.toString)
def apply( def apply(

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

@ -1,5 +1,6 @@
package wow.doge.mygame.scriptsystem package wow.doge.mygame.scriptsystem
import scala.concurrent.duration._
import scala.util.Failure import scala.util.Failure
import scala.util.Success import scala.util.Success
@ -14,8 +15,9 @@ import akka.actor.typed.scaladsl.Routers
import akka.util.Timeout import akka.util.Timeout
import com.typesafe.scalalogging.Logger import com.typesafe.scalalogging.Logger
import org.slf4j.event.Level import org.slf4j.event.Level
import wow.doge.mygame.implicits._
import wow.doge.mygame.state.ScriptActor import wow.doge.mygame.state.ScriptActor
import scala.concurrent.duration._
import ScriptActor.ScriptObject import ScriptActor.ScriptObject
object ScriptCachingActor { object ScriptCachingActor {
@ -188,10 +190,10 @@ class ScriptCachingActor(
Behaviors.same Behaviors.same
case Put(scriptPath, script) => case Put(scriptPath, script) =>
ctx.log.debug(s"Putting $script at path $scriptPath")
ctx.log.debugP(s"Putting $script at path $scriptPath")
val newState = val newState =
state.modify(_.scriptsMap).using(_ + (scriptPath -> script)) state.modify(_.scriptsMap).using(_ + (scriptPath -> script))
ctx.log.trace(newState.toString())
ctx.log.traceP(newState.toString())
receiveMessage(state = newState) receiveMessage(state = newState)
case NoOp => Behaviors.same case NoOp => Behaviors.same
@ -224,14 +226,14 @@ private[scriptsystem] object Methods {
scriptsMap scriptsMap
.get(scriptPath) .get(scriptPath)
.fold { .fold {
ctx.log.debug("Delegating to child")
ctx.log.debugP("Delegating to child")
ctx.self ! DelegateToChild( ctx.self ! DelegateToChild(
scriptActor, scriptActor,
scriptPath, scriptPath,
requester requester
) )
} { s => } { s =>
ctx.log.debug("Getting script from cache")
ctx.log.debugP("Getting script from cache")
requester ! Right(s) requester ! Right(s)
} }
} }

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

@ -4,7 +4,6 @@ import akka.actor.typed.ActorRef
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.Resource
import monix.bio.Task import monix.bio.Task
import wow.doge.mygame.scriptsystem.ScriptCachingActor import wow.doge.mygame.scriptsystem.ScriptCachingActor
import wow.doge.mygame.utils.AkkaUtils import wow.doge.mygame.utils.AkkaUtils
@ -20,29 +19,18 @@ object ScriptInitMode {
} }
class ScriptSystemResource( class ScriptSystemResource(
path: os.Path, path: os.Path,
spawnProtocol: ActorRef[SpawnProtocol.Command],
mode: ScriptInitMode = ScriptInitMode.Lazy mode: ScriptInitMode = ScriptInitMode.Lazy
)(implicit timeout: Timeout, scheduler: Scheduler) {
val make = {
// throw new Exception("boom")
findScriptFiles(os.pwd / "assets" / "scripts")
lazy val scriptCacheActor = AkkaUtils.spawnActorL(
spawnProtocol,
"scriptCachingActor",
ScriptCachingActor()
)
Resource.liftF(scriptCacheActor)
}
// sys.ask(ref => ScriptCachingActor.GetAll(os.pwd/'assets/'scripts/'scala/"hello2.sc",ref, false))
)(implicit
spawnProtocol: ActorRef[SpawnProtocol.Command],
timeout: Timeout,
scheduler: Scheduler
) {
val init = for { val init = for {
scriptFiles <- Task(findScriptFiles(os.pwd / "assets" / "scripts")) scriptFiles <- Task(findScriptFiles(os.pwd / "assets" / "scripts"))
scriptCacheActor <- AkkaUtils.spawnActorL( scriptCacheActor <- AkkaUtils.spawnActorL(
spawnProtocol,
"scriptCachingActor",
ScriptCachingActor()
ScriptCachingActor(),
"scriptCachingActor"
) )
} yield (scriptCacheActor) } yield (scriptCacheActor)

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

@ -9,7 +9,7 @@ import akka.util.Timeout
import wow.doge.mygame.implicits._ import wow.doge.mygame.implicits._
object AkkaUtils { object AkkaUtils {
def spawnActorL[T](
def spawnActorOldL[T](
spawnProtocol: ActorRef[SpawnProtocol.Command], spawnProtocol: ActorRef[SpawnProtocol.Command],
actorName: String, actorName: String,
behavior: Behavior[T] behavior: Behavior[T]
@ -22,7 +22,7 @@ object AkkaUtils {
_ _
) )
) )
def spawnActorL2[T](
def spawnActorL[T](
behavior: Behavior[T], behavior: Behavior[T],
actorName: String actorName: String
)(implicit )(implicit

4
src/main/scala/wow/doge/mygame/utils/GenericConsoleStream.scala

@ -21,7 +21,7 @@ class GenericConsoleStream[T](
)(implicit )(implicit
cs: ConsoleStreamable[T] cs: ConsoleStreamable[T]
) extends PrintStream(outputStream, true) { ) extends PrintStream(outputStream, true) {
private lazy val defaultOut = System.out
private val defaultOut = System.out
def printToStreamable(stble: Option[T], text: String) = def printToStreamable(stble: Option[T], text: String) =
stble.foreach(s => cs.println(s, text)) stble.foreach(s => cs.println(s, text))
@ -57,7 +57,7 @@ object GenericConsoleStream {
*/ */
case class Config(exclusive: Boolean = false) case class Config(exclusive: Boolean = false)
object Config { object Config {
lazy val default = Config()
val default = Config()
} }
implicit val implJFXConsoleStreamForTextArea = implicit val implJFXConsoleStreamForTextArea =

Loading…
Cancel
Save