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.badlogicgames.gdx" % "gdx-ai" % "1.8.2",
"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
@ -155,10 +156,6 @@ lazy val root = (project in file(".")).settings(
// val oldStrategy = (assemblyMergeStrategy in assembly).value
// 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)"""

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

@ -47,6 +47,10 @@ class StaticLoggerBinder extends OdinLoggerBinder[IO] {
.allocated
.unsafeRunSync()
val mainFileLogger2 = mainFileLogger.contramap(lm =>
lm.copy(message = lm.message.map(s => fansi.Str(s).plainText))
)
private lazy val (eventBusFileLogger, release3) =
fileLogger[IO](
"eventbus.log",
@ -72,15 +76,22 @@ class StaticLoggerBinder extends OdinLoggerBinder[IO] {
case s if s.startsWith("com.jayfella.jme.jfx.util.JfxPlatform") =>
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
case s if s.startsWith("wow.doge.mygame.subsystems.events.EventBus") =>
defaultConsoleLogger.withMinimalLevel(Level.Debug) |+| eventBusFileLogger
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
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.Task
import _root_.monix.bio.UIO
import akka.actor.typed.ActorSystem
import akka.actor.typed.SpawnProtocol
import akka.util.Timeout
import cats.effect.ExitCode
import cats.effect.Resource
import cats.implicits._
import com.softwaremill.macwire._
import io.odin._
import io.odin.json.Formatter
import io.odin.syntax._
import scalafx.scene.control.TextArea
import wow.doge.mygame.game.GameAppResource
import wow.doge.mygame.utils.GenericConsoleStream
object Main extends BIOApp with MainModule {
@ -34,25 +34,23 @@ object Main extends BIOApp with MainModule {
Formatter.json
).withAsync(timeWindow = 1.milliseconds, maxBufferSize = Some(2000))
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(
new MainApp(
logger,
gameApp,
actorSystem,
// gameApp,
// actorSystem,
jmeScheduler,
schedulers,
consoleStream
)(
timeout,
actorSystem.scheduler
).program
)(actorSystem, timeout, actorSystem.scheduler).program
)
} yield ()
@ -63,7 +61,7 @@ object Main extends BIOApp with MainModule {
Console.withOut(consoleStream)(
appResource(consoleStream)
.use(_ => Task.unit >> Task(consoleStream.close()))
.onErrorHandle(_.printStackTrace())
.onErrorHandleWith(ex => UIO(ex.printStackTrace()))
.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.SpawnProtocol
import akka.util.Timeout
import cats.effect.Resource
import cats.effect.concurrent.Deferred
import com.jme3.app.state.AppStateManager
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.utils.AkkaUtils
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(
logger: Logger[Task],
gameApp: GameApp,
implicit val spawnProtocol: ActorSystem[SpawnProtocol.Command],
jmeThread: monix.execution.Scheduler,
schedulers: Schedulers,
consoleStream: GenericConsoleStream[TextArea]
)(implicit
spawnProtocol: ActorSystem[SpawnProtocol.Command],
@annotation.unused timeout: Timeout,
@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
/**
* 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]
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
*/
if (launchResult == LauncherResult.Exit)
if (launchResult === LauncherResult.Exit)
logger.info("Exiting")
/**
* User chose launch. Wait for game window to close
*/
else
gameInit.flatMap(_.join)
gameInit.use(_.join)
} yield ()
}
@ -146,7 +129,6 @@ class MainApp(
*/
class MainAppDelegate(
gameApp: GameApp,
implicit val spawnProtocol: ActorSystem[SpawnProtocol.Command],
loggerL: Logger[Task],
playerEventBus: GameEventBus[PlayerEvent],
tickEventBus: GameEventBus[TickEvent],
@ -159,10 +141,11 @@ class MainAppDelegate(
rootNode: Node @@ GameAppTags.RootNode,
bulletAppState: BulletAppState
)(implicit
spawnProtocol: ActorSystem[SpawnProtocol.Command],
@annotation.unused timeout: Timeout,
@annotation.unused scheduler: Scheduler
) {
lazy val physicsSpace = bulletAppState.physicsSpace
val physicsSpace = bulletAppState.physicsSpace
def init(
appScheduler: monix.execution.Scheduler
// consoleStream: GenericConsoleStream[TextArea]
@ -190,19 +173,21 @@ class MainAppDelegate(
// johnActor <- createTestNpc(appScheduler, "John").executeOn(appScheduler)
// _ <- 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 ()
def createPlayerController(
@ -210,14 +195,14 @@ class MainAppDelegate(
): IO[PlayerController.Error, Unit] = {
val playerPos = ImVector3f.ZERO
val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
lazy val playerPhysicsControl =
val playerPhysicsControl =
PlayerController.Defaults.defaultPlayerPhysicsControl
.taggedWith[PlayerControllerTags.PlayerTag]
// lazy val camNode =
// PlayerController.Defaults
// .defaultCamerNode(camera, playerPos)
// .taggedWith[PlayerControllerTags.PlayerCameraNode]
lazy val mbPlayerNode = PlayerController.Defaults
val mbPlayerNode = PlayerController.Defaults
.defaultPlayerNode(
assetManager,
modelPath,
@ -225,7 +210,7 @@ class MainAppDelegate(
// camNode
playerPhysicsControl
)
lazy val cameraPivotNode = new Node(EntityIds.CameraPivot.value)
val cameraPivotNode = new Node(EntityIds.CameraPivot.value)
.taggedWith[PlayerControllerTags.PlayerCameraPivotNode]
for {
@ -258,11 +243,11 @@ class MainAppDelegate(
) =
// : IO[PlayerController.Error, Unit] =
{
val initialPos = ImVector3f(100, 0, 0)
val initialPos = ImVector3f(50, 5, 0)
// 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(
// new NpcMovementActor2.Props(
// initialPos,
@ -271,13 +256,13 @@ class MainAppDelegate(
// ).behavior,
// s"${npcName}-npcMovementActor"
// )
lazy val mbNpcNode = PlayerController.Defaults.defaultNpcNode(
val mbNpcNode = PlayerController.Defaults.defaultNpcNode(
assetManager,
initialPos,
npcPhysicsControl,
npcName
)
val npcActorTask = AkkaUtils.spawnActorL2(
val npcActorTask = AkkaUtils.spawnActorL(
NpcActorSupervisor
.Props(
new NpcMovementActor.Props(
@ -302,7 +287,7 @@ class MainAppDelegate(
physicsSpace += 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(
logger: Logger[Task]
): 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 {
_ <- Task(sys.terminate())
_ <- Task.fromFuture(sys.whenTerminated)
_ <- Task.deferFuture(sys.whenTerminated)
_ <- logger.info("Actor System Terminated")
} yield ()
)

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

@ -1,11 +1,13 @@
package wow.doge.mygame.game
import cats.effect.Resource
import cats.effect.concurrent.Deferred
import com.jme3.app.state.AppStateManager
import com.jme3.asset.AssetManager
import com.jme3.input.InputManager
import com.jme3.scene.Node
import com.jme3.scene.Spatial
import com.jme3.system.AppSettings
import com.softwaremill.tagging._
import com.typesafe.scalalogging.{Logger => SLogger}
import io.odin.Logger
@ -15,7 +17,13 @@ import monix.catnap.ConcurrentChannel
import monix.catnap.ConsumerF
import monix.catnap.Semaphore
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.implicits._
import monix.execution.annotations.UnsafeBecauseImpure
import monix.reactive.Observable
sealed trait Error
case object FlyCamNotExists extends Error
@ -40,6 +48,8 @@ class GameApp(logger: Logger[Task], val app: SimpleAppExt) {
def camera = Task(app.getCamera())
def viewPort = Task(app.getViewPort())
def rootNode = Task(app.getRootNode().taggedWith[GameAppTags.RootNode])
def rootNode2 =
WrappedNode(app.getRootNode()).taggedWith[GameAppTags.RootNode]
// def rootNode2 = SynchedObject(app.getRootNode())
def addToRootNode = rootNode.flatMap(rn => Task(new AddToNode(rn)))
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

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 wow.doge.mygame.game.TickGenerator.Send
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.EventsModule.GameEventBus
import wow.doge.mygame.subsystems.events.TickEvent
@ -28,7 +29,7 @@ object GameAppActor {
) {
def behavior =
Behaviors.setup[Command] { ctx =>
ctx.log.info("Hello from GameAppActor")
ctx.log.infoP("Hello from GameAppActor")
val renderTickGenerator =
ctx.spawn(
Behaviors
@ -78,7 +79,7 @@ object TickGenerator {
object SubscribingActor {
def apply() =
Behaviors.receive[PhysicsTick.type] { (ctx, msg) =>
ctx.log.debug(s"received event $msg")
ctx.log.debugP(s"received event $msg")
Behaviors.same
}
}

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

@ -1,36 +1,30 @@
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 monix.bio.Task
import monix.execution.CancelableFuture
import monix.execution.CancelablePromise
import monix.execution.Scheduler
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.Schedulers
class SimpleAppExt(
schedulers: Schedulers,
startSignal: CancelablePromise[Unit],
appStates: AppState*
) extends SimpleApplication(appStates: _*) {
import SimpleAppExt._
@ -26,32 +24,26 @@ class SimpleAppExt(
*/
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 = {
tickSubject.onComplete()
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))
p.future
}
def enqueueL[T](cb: () => T): Task[T] =
Task.deferFuture(enqueueScala(cb))
Task.deferFuture(enqueueFuture(cb))
override protected def runQueuedTasks(): Unit = {
taskQueue2.transform { current =>
@ -73,7 +65,7 @@ class SimpleAppExt(
lazy val scheduler = Scheduler(JMEExecutorService)
}
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()

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

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

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

@ -193,23 +193,23 @@ class MovementActor(
// val walkDir = new Vector3f
val dir = state.cardinalDir
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 += camDir
}
if (dir.left) {
ctx.log.debug("left")
ctx.log.debugP("left")
// walkDir.addLocal(-1, 0, 0)
walkDir.addLocal(camLeft)
}
if (dir.right) {
ctx.log.debug("right")
ctx.log.debugP("right")
// walkDir.addLocal(1, 0, 0)
walkDir.addLocal(camLeft.negateLocal())
}
if (dir.down) {
ctx.log.debug("down")
ctx.log.debugP("down")
walkDir.addLocal(camDir.negateLocal())
// 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 object NoOp extends Command
private case class MovementFailed(err: Throwable) extends Command
final case class Props(
npcMovementActorBehavior: Behavior[NpcMovementActor.Command],
npcName: String,
@ -82,7 +84,7 @@ class NpcActorSupervisor(
def idle(state: State): Behavior[NpcActorSupervisor.Command] =
Behaviors.setup { _ =>
ctx.log.debug("Inside Idle State")
ctx.log.debugP("Inside Idle State")
Behaviors.receiveMessage[Command] {
case m @ Move(pos) =>
ctx.ask(
@ -97,7 +99,7 @@ class NpcActorSupervisor(
moving(state, move.pos, signal)
case LogError(err) =>
ctx.log.warn(err.getMessage())
ctx.log.warnP(err.getMessage())
Behaviors.same
case _ => Behaviors.unhandled
}
@ -117,12 +119,16 @@ class NpcActorSupervisor(
// )
ctx.pipeToSelf(signal) {
case Success(value) => DoneMoving
case Failure(exception) => LogError(exception)
case Failure(exception) => MovementFailed(exception)
}
Behaviors.receiveMessagePartial[Command] {
case LogError(err) =>
ctx.log.error(err.getMessage())
Behaviors.same
case MovementFailed(err) =>
ctx.self ! LogError(err)
movementTimer ! GenericTimerActor.Stop
idle(state)
case m @ Move(pos) =>
movementTimer ! GenericTimerActor.Stop
children.npcMovementActor ! NpcMovementActor.StopMoving
@ -132,7 +138,7 @@ class NpcActorSupervisor(
NpcMovementActor.MoveTo(pos, _)
) {
case Success(signal) => InternalMove(m, signal)
case Failure(exception) => LogError(exception)
case Failure(exception) => MovementFailed(exception)
}
Behaviors.same
case InternalMove(move, signal) =>
@ -190,12 +196,6 @@ class NpcMovementActor[T](
case AskPosition(replyTo) =>
replyTo ! location
Behaviors.same
case StopMoving =>
ctx.log.debug(
"Position at Stop = " + location.toString
)
props.enqueueR(() => cm.stop(props.movable))
receive(state)
case MoveTo(
target: ImVector3f,
replyTo: ActorRef[CancelableFuture[DoneMoving.type]]
@ -204,7 +204,6 @@ class NpcMovementActor[T](
val p = CancelablePromise[DoneMoving.type]()
replyTo ! p.future
ticking(p, target, state)
}
def ticking(
@ -214,7 +213,7 @@ class NpcMovementActor[T](
): Behavior[NpcMovementActor.Command] =
Behaviors.receiveMessagePartial {
case StopMoving =>
ctx.log.debug(
ctx.log.debugP(
"Position at Stop = " + location.toString
)
props.enqueueR(() => cm.stop(props.movable))
@ -225,12 +224,11 @@ class NpcMovementActor[T](
if (dst <= 10f) {
ctx.self ! StopMoving
reachDestination.success(DoneMoving)
receive(state)
} 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")
// spawn children actors
lazy val movementActor =
val movementActor =
ctx.spawn(
Behaviors
.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.movement.ImMovementActor
import wow.doge.mygame.utils.AkkaUtils
import com.softwaremill.macwire._
object PlayerControllerTags {
sealed trait PlayerTag
@ -47,7 +48,6 @@ object PlayerController {
loggerL: Logger[Task],
physicsSpace: PhysicsSpace,
initialPlayerPos: ImVector3f = ImVector3f.ZERO,
spawnProtocol: ActorRef[SpawnProtocol.Command],
playerEventBus: GameEventBus[PlayerEvent],
playerPhysicsControl: BetterCharacterControl,
appScheduler: monix.execution.Scheduler,
@ -56,29 +56,34 @@ object PlayerController {
cameraPivotNode: Node @@ PlayerControllerTags.PlayerCameraPivotNode,
tickEventBus: GameEventBus[TickEvent],
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] =
(for {
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)
_ <- IO {
@ -88,9 +93,7 @@ object PlayerController {
cameraPivotNode += cameraNode
// playerNode += cameraPivotNode
rootNode += cameraPivotNode
}
} yield ())
.onErrorHandleWith(e => IO.raiseError(GenericError(e.getMessage())))
.executeOn(appScheduler)
@ -101,10 +104,10 @@ object PlayerController {
modelPath: os.RelPath,
cam: Camera
)(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))
lazy val playerNode = new Node("PlayerNode")
val playerNode = new Node("PlayerNode")
.withChildren(
assetManager
.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.PlayerMovementEvent
import wow.doge.mygame.utils.IOUtils._
import monix.bio.Task
object GameInputHandler {
final class Props(
class Props(
inputManager: InputManager,
playerEventBus: GameEventBus[PlayerEvent]
// playerCameraEventBus: GameEventBus[PlayerCameraEvent]
@ -29,44 +30,44 @@ object GameInputHandler {
) {
def begin =
for {
_ <- UIO(setupMovementKeys(inputManager))
_ <- Task(setupMovementKeys(inputManager))
// _ <- UIO(setupAnalogMovementKeys)
_ <- UIO(setupCameraKeys())
_ <- Task(setupCameraKeys())
_ <- 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 ()
def setupMovementKeys(inputManager: InputManager) =
inputManager.withEnumMappings(PlayerMovementInput) {
case PlayerMovementInput.WalkRight =>
Seq(new KeyTrigger(KeyInput.KEY_D))
new KeyTrigger(KeyInput.KEY_D) :: Nil
case PlayerMovementInput.WalkLeft =>
Seq(new KeyTrigger(KeyInput.KEY_A))
new KeyTrigger(KeyInput.KEY_A) :: Nil
case PlayerMovementInput.WalkForward =>
Seq(new KeyTrigger(KeyInput.KEY_W))
new KeyTrigger(KeyInput.KEY_W) :: Nil
case PlayerMovementInput.WalkBackward =>
Seq(new KeyTrigger(KeyInput.KEY_S))
new KeyTrigger(KeyInput.KEY_S) :: Nil
case PlayerMovementInput.Jump =>
Seq(new KeyTrigger(KeyInput.KEY_SPACE))
new KeyTrigger(KeyInput.KEY_SPACE) :: Nil
}
def setupAnalogMovementKeys() =
@ -124,7 +125,6 @@ object GameInputHandler {
}
)
.completedL
.startAndForget
} yield ()
}

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

@ -14,15 +14,15 @@ object DefaultGameLevel {
assetManager: AssetManager,
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 {
case Right(node) => node
case Left(ex) =>
throw new NotImplementedError("No fallback sceneshape")
}
)
lazy val landscape: RigidBodyControl =
val landscape: RigidBodyControl =
new RigidBodyControl(sceneShape, 0)
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
import cats.Id
import com.jme3.bullet.control.BetterCharacterControl
import com.jme3.math.FastMath
import com.jme3.math.Quaternion
@ -8,7 +9,6 @@ import monix.eval.Coeval
import wow.doge.mygame.implicits._
import wow.doge.mygame.math.ImVector3f
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
trait CanMove2[-A, F[_]] {
// def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f
@ -19,7 +19,35 @@ trait CanMove2[-A, F[_]] {
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 {
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 =
new CanMove2[BetterCharacterControl, Coeval] {
override def move(

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

@ -84,7 +84,7 @@ class ImMovementActor[T](
case Tick =>
val walkDir =
getDirection2(state.cardinalDir, ctx.log.trace)
getDirection2(state.cardinalDir, ctx.log.traceP)
// if (walkDir != ImVector3f.ZERO) {
val tmp = walkDir * 25f * (1f / 144)
props.enqueueR { () =>
@ -94,7 +94,10 @@ class ImMovementActor[T](
Behaviors.same
}
def getDirection2(cardinalDir: CardinalDirection, debug: String => Unit) = {
def getDirection2(
cardinalDir: CardinalDirection,
debug: sourcecode.Text[String] => sourcecode.Text[String]
) = {
val camDir =
props.camera.getDirection().clone().normalizeLocal.multLocal(0.6f)
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
import javafx.beans.value.ObservableValue
import javafx.beans.{value => jfxbv}
import javafx.scene.{input => jfxsi}
import javafx.{event => jfxe}
import monix.execution.Ack
import monix.execution.Cancelable
import monix.reactive.Observable
import monix.reactive.OverflowStrategy
import scalafx.beans.property.Property
import scalafx.scene.Scene
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(
private val button: ButtonBase
) 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.OverflowStrategy
import monix.reactive.observers.Subscriber
import org.slf4j.Logger
import wow.doge.mygame.math.ImVector3f
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.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
import scala.concurrent.duration.FiniteDuration
import scala.concurrent.duration._
import cats.effect.concurrent.Deferred
import javafx.application.Platform
import javafx.beans.value.ObservableValue
import monix.bio.Task
import monix.catnap.CancelableF
import monix.eval.{Task => ETask}
import monix.execution.CancelablePromise
import monix.reactive.Observable
import monix.{eval => me}
import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.beans.property.StringProperty
import scalafx.scene.control.Button
import scalafx.stage.StageStyle
import wow.doge.mygame.executors.Schedulers
import wow.doge.mygame.implicits.JavaFXMonixObservables._
import wow.doge.mygame.utils.IOUtils._
import cats.effect.Resource
import cats.kernel.Eq
object Launcher {
sealed trait LauncherResult
object LauncherResult {
case object LaunchGame extends LauncherResult
case object Exit extends LauncherResult
implicit val eqForLR = Eq.fromUniversalEquals[LauncherResult]
}
class Props(
@ -44,10 +47,23 @@ class Launcher private (props: Launcher.Props) {
.observableAction()
.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 {
text = "Exit"
// text <-- testChangeObs
}
// exitButton.text.bind
StringProperty("") addListener ((_, _, _) => ())
private lazy val exitAction =
exitButton
.observableAction()
@ -60,22 +76,25 @@ class Launcher private (props: Launcher.Props) {
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 = {
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 =>
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(
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))
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
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")
// lazy val playerCameraEventBusTask =
// val playerCameraEventBusTask =
// createEventBus[PlayerCameraEvent]("playerCameraEventBus", Level.DEBUG)
lazy val tickEventBusTask =
val tickEventBusTask =
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) =
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]]]
) extends Command
lazy val defaultScalaRunner =
val defaultScalaRunner =
ammonite
.Main(
storageBackend = new Folder(
@ -51,13 +51,13 @@ object ScriptActor {
)
)
lazy val defaultKotlinRunner: KotlinScriptEngine = {
val defaultKotlinRunner: KotlinScriptEngine = {
val manager = new ScriptEngineManager()
val engine = manager.getEngineByExtension("main.kts")
engine.taggedWith[Kotlin]
}
lazy val defaultGroovyRunner: GroovyScriptEngine =
val defaultGroovyRunner: GroovyScriptEngine =
new GroovyScriptEngine(os.pwd.toString)
def apply(

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

@ -1,5 +1,6 @@
package wow.doge.mygame.scriptsystem
import scala.concurrent.duration._
import scala.util.Failure
import scala.util.Success
@ -14,8 +15,9 @@ import akka.actor.typed.scaladsl.Routers
import akka.util.Timeout
import com.typesafe.scalalogging.Logger
import org.slf4j.event.Level
import wow.doge.mygame.implicits._
import wow.doge.mygame.state.ScriptActor
import scala.concurrent.duration._
import ScriptActor.ScriptObject
object ScriptCachingActor {
@ -188,10 +190,10 @@ class ScriptCachingActor(
Behaviors.same
case Put(scriptPath, script) =>
ctx.log.debug(s"Putting $script at path $scriptPath")
ctx.log.debugP(s"Putting $script at path $scriptPath")
val newState =
state.modify(_.scriptsMap).using(_ + (scriptPath -> script))
ctx.log.trace(newState.toString())
ctx.log.traceP(newState.toString())
receiveMessage(state = newState)
case NoOp => Behaviors.same
@ -224,14 +226,14 @@ private[scriptsystem] object Methods {
scriptsMap
.get(scriptPath)
.fold {
ctx.log.debug("Delegating to child")
ctx.log.debugP("Delegating to child")
ctx.self ! DelegateToChild(
scriptActor,
scriptPath,
requester
)
} { s =>
ctx.log.debug("Getting script from cache")
ctx.log.debugP("Getting script from cache")
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.SpawnProtocol
import akka.util.Timeout
import cats.effect.Resource
import monix.bio.Task
import wow.doge.mygame.scriptsystem.ScriptCachingActor
import wow.doge.mygame.utils.AkkaUtils
@ -20,29 +19,18 @@ object ScriptInitMode {
}
class ScriptSystemResource(
path: os.Path,
spawnProtocol: ActorRef[SpawnProtocol.Command],
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 {
scriptFiles <- Task(findScriptFiles(os.pwd / "assets" / "scripts"))
scriptCacheActor <- AkkaUtils.spawnActorL(
spawnProtocol,
"scriptCachingActor",
ScriptCachingActor()
ScriptCachingActor(),
"scriptCachingActor"
)
} 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._
object AkkaUtils {
def spawnActorL[T](
def spawnActorOldL[T](
spawnProtocol: ActorRef[SpawnProtocol.Command],
actorName: String,
behavior: Behavior[T]
@ -22,7 +22,7 @@ object AkkaUtils {
_
)
)
def spawnActorL2[T](
def spawnActorL[T](
behavior: Behavior[T],
actorName: String
)(implicit

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

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

Loading…
Cancel
Save