many changes

This commit is contained in:
Rohan Sircar 2021-02-27 11:36:32 +05:30
parent fd8b3819ff
commit 12b232fb3c
77 changed files with 1434 additions and 828 deletions

1
.gitignore vendored
View File

@ -15,6 +15,7 @@ metals.sbt
.metals .metals
.bloop .bloop
.ammonite .ammonite
.bsp
# Scala-IDE specific # Scala-IDE specific
.scala_dependencies .scala_dependencies

8
.scalafix.conf Normal file
View File

@ -0,0 +1,8 @@
rules = [
# ScalalintClasses,
# ScalalintImports,
# ScalalintPackages,
# ScalalintInference,
OrganizeImports
]
# ScalalintClasses.removeEmptyConstructor = false

View File

@ -7,7 +7,7 @@ resolvers += "Jitpack" at "https://jitpack.io"
resolvers += Resolver.mavenLocal resolvers += Resolver.mavenLocal
resolvers += Resolver.sonatypeRepo("snapshots") resolvers += Resolver.sonatypeRepo("snapshots")
lazy val jmeVersion = "3.3.2-stable" val jmeVersion = "3.3.2-stable"
lazy val osName = System.getProperty("os.name") match { lazy val osName = System.getProperty("os.name") match {
case n if n.startsWith("Linux") => "linux" case n if n.startsWith("Linux") => "linux"
@ -67,13 +67,20 @@ lazy val root = (project in file(".")).settings(
"org.scalatest" %% "scalatest" % "3.2.2" % "test", "org.scalatest" %% "scalatest" % "3.2.2" % "test",
"org.typelevel" %% "cats-mtl" % "1.1.1", "org.typelevel" %% "cats-mtl" % "1.1.1",
"io.estatico" %% "newtype" % "0.4.4", "io.estatico" %% "newtype" % "0.4.4",
"io.methvin" %% "directory-watcher-better-files" % "0.14.0" "io.methvin" %% "directory-watcher-better-files" % "0.14.0",
"com.github.rohan-sircar" % "scalafx-utils" % "0.15.0-SNAPSHOT",
"com.jfoenix" % "jfoenix" % "9.0.10",
"org.kordamp.ikonli" % "ikonli-core" % "12.0.0",
"org.kordamp.ikonli" % "ikonli-javafx" % "12.0.0",
"org.kordamp.ikonli" % "ikonli-fontawesome5-pack" % "12.0.0",
"org.kordamp.ikonli" % "ikonli-material-pack" % "12.0.0",
"org.kordamp.bootstrapfx" % "bootstrapfx-core" % "0.4.0"
), ),
// Determine OS version of JavaFX binaries // Determine OS version of JavaFX binaries
// Add JavaFX dependencies // Add JavaFX dependencies
libraryDependencies ++= javaFXModules.map(m => libraryDependencies ++= javaFXModules.map(m =>
"org.openjfx" % s"javafx-$m" % "14.0.1" classifier osName "org.openjfx" % s"javafx-$m" % "11.0.1" classifier osName
), ),
scalacOptions ++= Seq( scalacOptions ++= Seq(
"-encoding", "-encoding",
@ -126,7 +133,8 @@ lazy val root = (project in file(".")).settings(
// oldStrategy(x) // oldStrategy(x)
} }
) )
initialCommands in (console) := """ammonite.Main.main(Array.empty)""" // initialCommands in (console) := """ammonite.Main.main(Array.empty)"""
ammoniteVersion := "2.2.0"
addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1") addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1")
addCompilerPlugin( addCompilerPlugin(
"org.typelevel" %% "kind-projector" % "0.11.1" cross CrossVersion.full "org.typelevel" %% "kind-projector" % "0.11.1" cross CrossVersion.full
@ -139,3 +147,33 @@ inThisBuild(
) )
) )
ThisBuild / scalafixDependencies += "com.github.liancheng" %% "organize-imports" % "0.4.3" ThisBuild / scalafixDependencies += "com.github.liancheng" %% "organize-imports" % "0.4.3"
scalafixDependencies in ThisBuild += "org.scalalint" %% "rules" % "0.1.4"
// wartremoverErrors in (Compile, compile) ++= Warts.allBut(
// Wart.Any,
// Wart.Nothing,
// Wart.Serializable
// )
// wartremoverWarnings in (Compile, compile) ++= Seq(Wart.Any, Wart.Serializable)
wartremoverErrors in (Compile, compile) ++=
Warts.allBut(
Wart.Any,
Wart.NonUnitStatements,
// Wart.StringPlusAny,
Wart.Overloading,
Wart.PublicInference,
Wart.Nothing,
Wart.Var,
Wart.DefaultArguments,
// Wart.MutableDataStructures,
Wart.ImplicitConversion,
Wart.ImplicitParameter,
Wart.ToString,
Wart.Recursion,
Wart.While,
Wart.ExplicitImplicitTypes,
Wart.ListUnapply
)
// Seq(Wart.FinalCaseClass)

View File

@ -1 +1 @@
sbt.version=1.3.13 sbt.version=1.4.7

View File

@ -1,2 +1,7 @@
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.15.0") addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.15.0")
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.23") addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.23")
addSbtPlugin("io.spray" % "sbt-revolver" % "0.9.1")
addSbtPlugin(
"com.thoughtworks.deeplearning" % "sbt-ammonite-classpath" % "2.0.0"
)
addSbtPlugin("org.wartremover" % "sbt-wartremover" % "2.4.13")

View File

@ -60,11 +60,9 @@ class StaticLoggerBinder extends OdinLoggerBinder[IO] {
.allocated .allocated
.unsafeRunSync() .unsafeRunSync()
{
ArraySeq(release1, release2, release3).foreach(r => ArraySeq(release1, release2, release3).foreach(r =>
sys.addShutdownHook(r.unsafeRunSync()) sys.addShutdownHook(r.unsafeRunSync())
) )
}
val loggers: PartialFunction[String, Logger[IO]] = { val loggers: PartialFunction[String, Logger[IO]] = {
case "some.external.package.SpecificClass" => case "some.external.package.SpecificClass" =>

View File

@ -9,7 +9,7 @@ import wow.doge.mygame.utils.wrappers.jme.AssetManager
import wow.doge.mygame.utils.wrappers.jme.CollisionShapeFactory import wow.doge.mygame.utils.wrappers.jme.CollisionShapeFactory
import wow.doge.mygame.utils.wrappers.jme.NodeWrapper2 import wow.doge.mygame.utils.wrappers.jme.NodeWrapper2
sealed trait AppError sealed trait AppError extends Product with Serializable
object AppError { object AppError {
final case class TimeoutError(reason: String) extends AppError final case class TimeoutError(reason: String) extends AppError
object TimeoutError { object TimeoutError {

View File

@ -2,17 +2,18 @@ package wow.doge.mygame
import scala.concurrent.duration._ import scala.concurrent.duration._
import _root_.monix.bio.BIOApp
import _root_.monix.bio.Task
import _root_.monix.bio.UIO
import _root_.monix.execution.Scheduler
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 io.odin._ import io.odin.consoleLogger
import io.odin.fileLogger
import io.odin.json.Formatter import io.odin.json.Formatter
import io.odin.syntax._ import io.odin.syntax._
import monix.bio.BIOApp
import monix.bio.Task
import monix.bio.UIO
import monix.execution.Scheduler
import scalafx.scene.control.TextArea import scalafx.scene.control.TextArea
import wow.doge.mygame.ActorSystemResource import wow.doge.mygame.ActorSystemResource
import wow.doge.mygame.executors.ExecutorsModule import wow.doge.mygame.executors.ExecutorsModule

View File

@ -1,5 +1,7 @@
package wow.doge.mygame package wow.doge.mygame
import java.util.concurrent.TimeoutException
import scala.concurrent.duration._ import scala.concurrent.duration._
import akka.actor.typed.ActorRef import akka.actor.typed.ActorRef
@ -8,6 +10,8 @@ import akka.util.Timeout
import cats.effect.Resource import cats.effect.Resource
import cats.effect.concurrent.Deferred import cats.effect.concurrent.Deferred
import cats.syntax.eq._ import cats.syntax.eq._
import cats.syntax.show._
import com.jayfella.jme.jfx.JavaFxUI
import com.jme3.asset.plugins.ZipLocator import com.jme3.asset.plugins.ZipLocator
import com.jme3.bullet.control.BetterCharacterControl import com.jme3.bullet.control.BetterCharacterControl
import com.jme3.input.InputManager import com.jme3.input.InputManager
@ -28,9 +32,14 @@ import monix.bio.IO
import monix.bio.Task import monix.bio.Task
import monix.bio.UIO import monix.bio.UIO
import monix.eval.Coeval import monix.eval.Coeval
import monix.execution.cancelables.CompositeCancelable
import monix.execution.exceptions.DummyException import monix.execution.exceptions.DummyException
import monix.reactive.Observable import monix.reactive.Observable
import scalafx.scene.control.Label
import scalafx.scene.control.TextArea import scalafx.scene.control.TextArea
import scalafx.scene.layout.HBox
import scalafx.scene.layout.VBox
import scalafx.scene.paint.Color
import wow.doge.mygame.AppError.TimeoutError import wow.doge.mygame.AppError.TimeoutError
import wow.doge.mygame.executors.Schedulers import wow.doge.mygame.executors.Schedulers
import wow.doge.mygame.game.GameApp import wow.doge.mygame.game.GameApp
@ -59,12 +68,16 @@ 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.subsystems.events.StatsEvent.DamageEvent import wow.doge.mygame.subsystems.events.StatsEvent.DamageEvent
import wow.doge.mygame.subsystems.events.TickEvent import wow.doge.mygame.subsystems.events.TickEvent
import wow.doge.mygame.subsystems.scriptsystem.ScriptCompiler
import wow.doge.mygame.subsystems.scriptsystem.ScriptInitMode 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.types._ import wow.doge.mygame.types._
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 wow.doge.mygame.utils.IOUtils
import wow.doge.mygame.utils.MonixDirectoryWatcher
import wow.doge.mygame.utils.MonixDirectoryWatcher.ModifyEvent
import wow.doge.mygame.utils.controls.JFXProgressBar
import wow.doge.mygame.utils.wrappers.jme.AssetManager import wow.doge.mygame.utils.wrappers.jme.AssetManager
import wow.doge.mygame.utils.wrappers.jme.PhysicsSpace import wow.doge.mygame.utils.wrappers.jme.PhysicsSpace
class MainApp( class MainApp(
@ -79,8 +92,8 @@ class MainApp(
) { ) {
implicit val as = scheduler.value implicit val as = scheduler.value
val scriptSystemInit = val scriptSystemResource: Resource[UIO, ScriptCompiler] =
new ScriptSystemResource(os.pwd, ScriptInitMode.Eager).init new ScriptSystemResource(os.pwd, logger, ScriptInitMode.Eager).init2
val eventsModule = new EventsModule(scheduler, spawnProtocol) val eventsModule = new EventsModule(scheduler, spawnProtocol)
@ -101,7 +114,9 @@ class MainApp(
IOUtils IOUtils
.toIO( .toIO(
obs obs
.doOnNextF(pme => Coeval(pprint.log(s"Received event $pme")).void) .doOnNextF(pme =>
Coeval(pprint.log(show"Received event $pme")).void
)
.completedL .completedL
.startAndForget .startAndForget
) )
@ -114,7 +129,7 @@ class MainApp(
viewPort <- gameApp.viewPort viewPort <- gameApp.viewPort
physicsSpace <- UIO.pure(gameApp.physicsSpace) physicsSpace <- UIO.pure(gameApp.physicsSpace)
_ <- logger.infoU("before") _ <- logger.infoU("before")
// jfxUI <- gameApp.jfxUI jfxUI <- gameApp.jfxUI.hideErrors
consoleTextArea <- UIO(new TextArea { consoleTextArea <- UIO(new TextArea {
text = "hello \n" text = "hello \n"
editable = false editable = false
@ -122,6 +137,7 @@ class MainApp(
// maxHeight = 150 // maxHeight = 150
// maxWidth = 300 // maxWidth = 300
}) })
// _ <- Task(consoleStream := consoleTextArea) // _ <- Task(consoleStream := consoleTextArea)
// _ <- Task(jfxUI += consoleTextArea) // _ <- Task(jfxUI += consoleTextArea)
_ <- logger.infoU("after") _ <- logger.infoU("after")
@ -132,14 +148,48 @@ class MainApp(
.executeOn(gameApp.scheduler.value) .executeOn(gameApp.scheduler.value)
} yield fib } yield fib
// val k = new FunctionK[Task, UIO] {
// override def apply[A](fa: monix.bio.Task[A]): monix.bio.UIO[A] =
// fa.hideErrors
// }
def gameInit( def gameInit(
tickEventBus: GameEventBus[TickEvent] tickEventBus: GameEventBus[TickEvent]
): Resource[UIO, Either[AppError, Fiber[Nothing, Unit]]] = ): Resource[UIO, Either[AppError, Fiber[Nothing, Unit]]] =
wire[GameAppResource].resource.evalMap { for {
r1 <- wire[GameAppResource].resource.evalMap {
case Right(gameApp -> gameAppFib) => case Right(gameApp -> gameAppFib) =>
eval(tickEventBus, gameApp, gameAppFib).attempt eval(tickEventBus, gameApp, gameAppFib).attempt
case Left(error) => IO.terminate(new Exception(error.toString)) case Left(error) => IO.terminate(new Exception(error.toString))
} }
dirWatcher <- Resource.liftF(
MonixDirectoryWatcher(
os.pwd / "assets" / "scripts"
).hideErrors
)
sc <- scriptSystemResource
obs = dirWatcher.doOnNext {
case ModifyEvent(file, count) =>
sc.request(ScriptCompiler.GetScript(os.Path(file.path), _, true))(
15.seconds
).toTask
.void
case _ => monix.eval.Task.unit
}
_ <- Resource.make(obs.completedL.toIO.hideErrors.start)(_.cancel)
// _ <-
// dirWatcher
// .doOnNextF(event =>
// Coeval(pprint.log(show"Received file event $event")).void
// )
// .completedL
// .executeOn(schedulers.io.value)
// .startAndForget
// .toIO
// .hideErrors
} yield r1
val program = for { val program = for {
// scriptSystem <- scriptSystemInit // scriptSystem <- scriptSystemInit
@ -185,7 +235,8 @@ class MainAppDelegate(
viewPort: ViewPort, viewPort: ViewPort,
enqueueR: Function1[() => Unit, Unit], enqueueR: Function1[() => Unit, Unit],
rootNode: RootNode, rootNode: RootNode,
schedulers: Schedulers schedulers: Schedulers,
jfxUI: JavaFxUI
)(implicit )(implicit
spawnProtocol: ActorRef[SpawnProtocol.Command], spawnProtocol: ActorRef[SpawnProtocol.Command],
timeout: Timeout, timeout: Timeout,
@ -203,7 +254,7 @@ class MainAppDelegate(
os.rel / "assets" / "town.zip", os.rel / "assets" / "town.zip",
classOf[ZipLocator] classOf[ZipLocator]
) )
_ <- loggerL.infoU("test")
// _ <- Task(consoleStream.println("text")) // _ <- Task(consoleStream.println("text"))
level <- DefaultGameLevel(assetManager, viewPort) level <- DefaultGameLevel(assetManager, viewPort)
_ <- level.addToGame(rootNode, physicsSpace) _ <- level.addToGame(rootNode, physicsSpace)
@ -231,45 +282,44 @@ class MainAppDelegate(
_ <- _ <-
damageObs damageObs
.doOnNextF(event => .doOnNextF(event =>
(loggerL.debug(s"Received Damage Event $event") >> (loggerL.debug(show"Received Damage Event $event") >>
(if (event.victimName === "PlayerNode") (if (event.victimName === "PlayerNode")
// playerActor !! PlayerActorSupervisor.TakeDamage(event.amount) playerActor
playerActor.askL( .askL(PlayerActorSupervisor.TakeDamage(event.amount, _))
PlayerActorSupervisor.TakeDamage2(event.amount, _) .onErrorHandle { case ex: TimeoutException => () }
)
else IO.unit)).toTask else IO.unit)).toTask
) )
.completedL .completedL
.toIO .toIO
.hideErrors .hideErrors
.startAndForget .startAndForget
_ <- // _ <-
Observable // Observable
.interval(1.second) // .interval(1.second)
.doOnNextF(_ =>
playerActor
.askL(PlayerActorSupervisor.GetStatus)
.flatMap(s => loggerL.debug(s"Player actor status: $s"))
// .flatMap(s =>
// if (s == Status.Alive)
// playerActor
// .askL(PlayerActorSupervisor.CurrentStats )
// .flatMap(s => loggerL.debug(s"Got state $s"))
// else IO.unit
// )
.toTask
)
// .doOnNextF(_ => // .doOnNextF(_ =>
// playerActor // playerActor
// .askL(PlayerActorSupervisor.GetStatus ) // .askL(PlayerActorSupervisor.GetStatus)
// .flatMap(s => loggerL.debug(s"Player actor status: $s")) // .flatMap(s => loggerL.debug(show"Player actor status: $s"))
// // .flatMap(s =>
// // if (s == Status.Alive)
// // playerActor
// // .askL(PlayerActorSupervisor.CurrentStats )
// // .flatMap(s => loggerL.debug(show"Got state $s"))
// // else IO.unit
// // )
// .toTask // .toTask
// ) // )
.completedL // // .doOnNextF(_ =>
.toIO // // playerActor
.hideErrors // // .askL(PlayerActorSupervisor.GetStatus )
.startAndForget // // .flatMap(s => loggerL.debug(show"Player actor status: $s"))
// // .toTask
// // )
// .completedL
// .toIO
// .hideErrors
// .startAndForget
_ <- _ <-
physicsSpace.collisionObservable physicsSpace.collisionObservable
// .filter(event => // .filter(event =>
@ -282,7 +332,7 @@ class MainAppDelegate(
// ) // )
// .doOnNextF(event => // .doOnNextF(event =>
// loggerL // loggerL
// .debug(s"$event ${event.appliedImpulse()}") // .debug(show"$event ${event.appliedImpulse()}")
// .toTask // .toTask
// ) // )
.filter(_.nodeA.map(_.getName =!= "main-scene_node").getOrElse(false)) .filter(_.nodeA.map(_.getName =!= "main-scene_node").getOrElse(false))
@ -295,7 +345,7 @@ class MainAppDelegate(
} yield if (nodeB.getName === "John") nodeA else nodeB) } yield if (nodeB.getName === "John") nodeA else nodeB)
_ <- Coeval( _ <- Coeval(
victim.foreach { v => victim.foreach { v =>
pprint.log(s"emitted event ${v.getName}") pprint.log(show"emitted event ${v.getName}")
mainEventBus ! EventBus.Publish( mainEventBus ! EventBus.Publish(
DamageEvent( DamageEvent(
"John", "John",
@ -322,6 +372,63 @@ class MainAppDelegate(
// ) // )
// .executeOn(appScheduler) // .executeOn(appScheduler)
// .startAndForget // .startAndForget
statsObs <-
playerActor
.askL(PlayerActorSupervisor.GetStatsObservable(_))
.onErrorHandleWith(TimeoutError.from)
playerHud <-
UIO
.deferAction(implicit s =>
UIO(new VBox {
implicit val c = CompositeCancelable()
spacing = 10
style = """-fx-background-color: rgba(0,0,0,0.7);"""
children = List(
new HBox {
spacing = 5
children = List(
new Label("Health") { textFill = Color.White },
new Label("100") {
text == "hello"
text <-- statsObs
.doOnNextF(i => loggerL.debug(show"Received stats: $i"))
.map(_.hp.toInt.toString)
textFill = Color.White
},
new JFXProgressBar {
progress = 100
minHeight = 10
progress <-- statsObs
.map(_.hp.toInt.toDouble / 100)
}
)
},
new HBox {
spacing = 5
children = List(
new Label("Stamina") {
textFill = Color.White
},
new Label("100") {
textFill = Color.White
text <-- statsObs
.doOnNextF(i => loggerL.debug(show"Received stats: $i"))
.map(_.stamina.toInt.toString)
},
new JFXProgressBar {
progress = 100
minHeight = 10
progress <-- statsObs
.map(_.stamina.toInt.toDouble / 100)
}
)
}
)
})
)
.executeOn(schedulers.fx.value)
_ <- UIO(jfxUI += playerHud)
} yield () } yield ()
def createPlayerController( def createPlayerController(
@ -369,70 +476,34 @@ class MainAppDelegate(
.scan(new Quaternion) { .scan(new Quaternion) {
case (rotationBuf, action) => case (rotationBuf, action) =>
action.binding match { action.binding match {
// case PlayerCameraEvent.CameraLeft =>
case PlayerCameraInput.CameraRotateLeft => case PlayerCameraInput.CameraRotateLeft =>
// me.Task {
val rot = rotationBuf val rot = rotationBuf
.fromAngleAxis(1 * FastMath.DEG_TO_RAD, Vector3f.UNIT_Y) .fromAngleAxis(1 * FastMath.DEG_TO_RAD, Vector3f.UNIT_Y)
cameraPivotNode.rotate(rot) cameraPivotNode.rotate(rot)
rotationBuf rotationBuf
// }
// case PlayerCameraEvent.CameraRight =>
case PlayerCameraInput.CameraRotateRight => case PlayerCameraInput.CameraRotateRight =>
// me.Task {
val rot = rotationBuf val rot = rotationBuf
.fromAngleAxis(-1 * FastMath.DEG_TO_RAD, Vector3f.UNIT_Y) .fromAngleAxis(-1 * FastMath.DEG_TO_RAD, Vector3f.UNIT_Y)
cameraPivotNode.rotate(rot) cameraPivotNode.rotate(rot)
rotationBuf rotationBuf
// }
// case PlayerCameraEvent.CameraMovedUp =>
case PlayerCameraInput.CameraRotateUp => case PlayerCameraInput.CameraRotateUp =>
// me.Task {
val rot = rotationBuf val rot = rotationBuf
.fromAngleAxis(-1 * FastMath.DEG_TO_RAD, Vector3f.UNIT_X) .fromAngleAxis(-1 * FastMath.DEG_TO_RAD, Vector3f.UNIT_X)
cameraPivotNode.rotate(rot) cameraPivotNode.rotate(rot)
rotationBuf rotationBuf
// }
// case PlayerCameraEvent.CameraMovedDown =>
case PlayerCameraInput.CameraRotateDown => case PlayerCameraInput.CameraRotateDown =>
// me.Task {
val rot = rotationBuf val rot = rotationBuf
.fromAngleAxis(1 * FastMath.DEG_TO_RAD, Vector3f.UNIT_X) .fromAngleAxis(1 * FastMath.DEG_TO_RAD, Vector3f.UNIT_X)
cameraPivotNode.rotate(rot) cameraPivotNode.rotate(rot)
rotationBuf rotationBuf
// }
} }
} }
.completedL .completedL
.toIO .toIO
.hideErrors .hideErrors
.startAndForget .startAndForget
// _ <-
// Observable
// .interval(10.millis)
// .doOnNextF(_ =>
// Coeval {
// val location = playerNode.getWorldTranslation()
// cameraPivotNode.setLocalTranslation(location)
// }
// )
// .completedL
// .toIO
// .hideErrors
// .startAndForget
sched <- UIO.pure(schedulers.async) sched <- UIO.pure(schedulers.async)
playerActor <- wire[PlayerController.Props].create playerActor <- wire[PlayerController.Props].create
obs <-
playerActor
.askL(PlayerActorSupervisor.GetStatsObservable2)
.onErrorHandleWith(TimeoutError.from)
_ <-
obs
.doOnNext(s => loggerL.debug(s"Got state $s").toTask)
.completedL
.toIO
.hideErrors
.startAndForget
} yield playerActor } yield playerActor
} }
@ -456,7 +527,7 @@ class MainAppDelegate(
npcName, npcName,
initialPos initialPos
).behavior, ).behavior,
actorName = Some(s"${npcName}-npcActorSupervisor") actorName = Some(show"${npcName}-npcActorSupervisor")
) )
(for { (for {

View File

@ -16,11 +16,11 @@ import wow.doge.mygame.implicits._
object GameActorSystem { object GameActorSystem {
sealed trait Command sealed trait Command
case class GetSpawnProtocol( final case class GetSpawnProtocol(
replyTo: ActorRef[ActorRef[SpawnProtocol.Command]] replyTo: ActorRef[ActorRef[SpawnProtocol.Command]]
) extends Command ) extends Command
class Props() { class Props {
def create = def create =
Behaviors.setup[Command] { ctx => Behaviors.setup[Command] { ctx =>
val systemSpawnProtocol = ctx.spawnN(SpawnProtocol()) val systemSpawnProtocol = ctx.spawnN(SpawnProtocol())
@ -44,9 +44,9 @@ class GameActorSystem(
// object EventBusSupervisor { // object EventBusSupervisor {
// sealed trait Command // sealed trait Command
// case class GetMainEventBus(replyTo: ActorRef[GameEventBus[Event]]) // final case class GetMainEventBus(replyTo: ActorRef[GameEventBus[Event]])
// extends Command // extends Command
// case class GetEventBus[T](replyTo: ActorRef[GameEventBus[T]])(implicit // final case class GetEventBus[T](replyTo: ActorRef[GameEventBus[T]])(implicit
// classTag: ClassTag[T] // classTag: ClassTag[T]
// ) extends Command { // ) extends Command {
// def ct = classTag // def ct = classTag

View File

@ -47,6 +47,7 @@ object JMEExecutorService extends GUIExecutorService {
} }
object JMERunner { object JMERunner {
@SuppressWarnings(Array("org.wartremover.warts.Null"))
var runner: Application = null var runner: Application = null
} }

View File

@ -5,7 +5,7 @@ import monix.execution.Scheduler
import monix.execution.UncaughtExceptionReporter import monix.execution.UncaughtExceptionReporter
final case class Schedulers( final case class Schedulers(
blockingIO: Schedulers.IoScheduler, io: Schedulers.IoScheduler,
async: Schedulers.AsyncScheduler, async: Schedulers.AsyncScheduler,
fx: Schedulers.FxScheduler fx: Schedulers.FxScheduler
) )
@ -32,8 +32,8 @@ object Schedulers {
) )
) )
case class AsyncScheduler(value: Scheduler) final case class AsyncScheduler(value: Scheduler)
case class IoScheduler(value: Scheduler) final case class IoScheduler(value: Scheduler)
case class FxScheduler(value: Scheduler) final case class FxScheduler(value: Scheduler)
} }

View File

@ -8,8 +8,10 @@ import akka.actor.typed.Props
import akka.actor.typed.SpawnProtocol import akka.actor.typed.SpawnProtocol
import akka.actor.typed.scaladsl.AskPattern._ import akka.actor.typed.scaladsl.AskPattern._
import akka.util.Timeout import akka.util.Timeout
import cats.Show
import cats.effect.Resource import cats.effect.Resource
import cats.effect.concurrent.Deferred import cats.effect.concurrent.Deferred
import cats.syntax.show._
import com.jme3.bullet.BulletAppState import com.jme3.bullet.BulletAppState
import com.jme3.input.InputManager import com.jme3.input.InputManager
import com.jme3.scene.Node import com.jme3.scene.Node
@ -177,6 +179,10 @@ object SpawnSystem {
result: Deferred[Task, Result] result: Deferred[Task, Result]
) )
object SpawnRequestWrapper {
implicit val show = Show.fromToString[SpawnRequestWrapper]
}
def apply(logger: Logger[Task]) = def apply(logger: Logger[Task]) =
for { for {
spawnChannel <- ConcurrentChannel[Task].of[Complete, SpawnRequestWrapper] spawnChannel <- ConcurrentChannel[Task].of[Complete, SpawnRequestWrapper]
@ -213,7 +219,7 @@ class SpawnSystem(
for { for {
_ <- _ <-
logger logger
.debug(s"Received spawn request $message") .debug(show"Received spawn request $message")
_ <- handleSpawn(message) _ <- handleSpawn(message)
} yield receive(consumer) } yield receive(consumer)
case Left(r) => case Left(r) =>

View File

@ -22,12 +22,13 @@ object GameAppActor {
case object Start extends Command case object Start extends Command
case object Pause extends Command case object Pause extends Command
case object Ping extends Command case object Ping extends Command
case class Stop(stopSignal: ActorRef[CancelableFuture[Unit]]) extends Command final case class Stop(stopSignal: ActorRef[CancelableFuture[Unit]])
case class GetSpawnProtocol( extends Command
final case class GetSpawnProtocol(
replyTo: ActorRef[ActorRef[SpawnProtocol.Command]] replyTo: ActorRef[ActorRef[SpawnProtocol.Command]]
) extends Command ) extends Command
case class Props(tickEventBus: GameEventBus[TickEvent]) { final case class Props(tickEventBus: GameEventBus[TickEvent]) {
def behavior = def behavior =
Behaviors.setup[Command] { ctx => Behaviors.setup[Command] { ctx =>
ctx.log.infoP("Hello from GameAppActor") ctx.log.infoP("Hello from GameAppActor")

View File

@ -1,30 +0,0 @@
package wow.doge.mygame.game
// 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)
// /**
// * 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"))
// }

View File

@ -1,7 +1,6 @@
package wow.doge.mygame.game package wow.doge.mygame.game
import scala.collection.immutable.Queue import scala.collection.immutable.Queue
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future import scala.concurrent.Future
import com.jme3.app.SimpleApplication import com.jme3.app.SimpleApplication
@ -28,6 +27,7 @@ class SimpleAppExt(
private val startSignal: CancelablePromise[Unit] = CancelablePromise() private val startSignal: CancelablePromise[Unit] = CancelablePromise()
private val terminationSignal: CancelablePromise[Unit] = CancelablePromise() private val terminationSignal: CancelablePromise[Unit] = CancelablePromise()
private implicit val ec = schedulers.async.value
var cancelToken: Option[() => Future[Unit]] = None var cancelToken: Option[() => Future[Unit]] = None
@ -87,7 +87,7 @@ class SimpleAppExt(
val scheduler = Scheduler(JMEExecutorService) val scheduler = Scheduler(JMEExecutorService)
} }
object SimpleAppExt { object SimpleAppExt {
private[game] case class MyTask[T](p: CancelablePromise[T], cb: () => T) private[game] final case class MyTask[T](p: CancelablePromise[T], cb: () => T)
} }
// val ship = ed.createEntity() // val ship = ed.createEntity()

View File

@ -40,7 +40,7 @@ object TestActor {
// ctx.log.debugP(value.toString()) // ctx.log.debugP(value.toString())
// Done // Done
// case Failure(exception) => // case Failure(exception) =>
// ctx.log.debugP(s"Received Error ${exception.getMessage()}") // ctx.log.debugP(show"Received Error ${exception.getMessage()}")
// Done // Done
// } // }
} }

View File

@ -1,69 +0,0 @@
package wow.doge.mygame.state
import com.jme3.app.Application
import com.jme3.app.SimpleApplication
import com.jme3.app.state.AppState
import com.jme3.app.state.BaseAppState
import com.jme3.scene.Node
import com.jme3.scene.Spatial
import com.simsilica.es.EntityData
import com.simsilica.es.base.DefaultEntityData
trait MyBaseState extends BaseAppState {
var simpleApp: SimpleApplication = null
implicit val entityData: EntityData = new DefaultEntityData()
def stateManager = simpleApp.getStateManager
def guiNode = simpleApp.getGuiNode
def rootNode = simpleApp.getRootNode
def assetManager = simpleApp.getAssetManager
def inputManager = simpleApp.getInputManager
def cam = simpleApp.getCamera
override protected final def initialize(app: Application): Unit = {
simpleApp = app.asInstanceOf[SimpleApplication]
init()
// stateManager.getState(classOf[FlyCamAppState]).getCamera().setMoveSpeed(100)
}
protected def init(): Unit
protected def stop(): Unit
override protected def cleanup(app: Application): Unit = {
entityData.close()
// stop()
}
protected def getChildOption(parent: Node, id: String) =
Option(parent.getChild(id))
protected def getOrCreateSpatial(parent: Node, id: String): Spatial =
Option(parent.getChild(id)).getOrElse {
val node: Spatial = new Node(id)
parent.attachChild(node)
node
}
protected def enableStates(classes: Class[_ <: AppState]*) =
setEnabledToStates(true, classes: _*)
protected def disableStates(classes: Class[_ <: AppState]*) =
setEnabledToStates(false, classes: _*)
protected def setEnabledToStates(
enabled: Boolean,
classes: Class[_ <: AppState]*
) = {
for (clazz <- classes) {
val st = stateManager.getState(clazz)
if (st != null) st.setEnabled(enabled)
}
}
protected def removeStates(classes: Class[_ <: AppState]*) = {
for (clazz <- classes) {
val st = stateManager.getState(clazz)
if (st != null) stateManager.detach(st)
}
}
}

View File

@ -1,207 +0,0 @@
package wow.doge.mygame.state
import javax.script.ScriptEngine
import akka.actor.typed.ActorRef
import akka.actor.typed.Behavior
import akka.actor.typed.SpawnProtocol
import akka.actor.typed.scaladsl.AbstractBehavior
import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.scaladsl.Behaviors
import ammonite.Main
import ammonite.main.Defaults
import ammonite.runtime.Storage.Folder
import ammonite.util.Res.Success
import com.jme3.app.state.AppState
class ScriptingEngineState(
sse: ScalaScriptingEngine,
kse: KotlinScriptingEngine
) extends MyBaseState {
// implicit val actorSystem =
// ActorSystem.create(MyActorSystem(), "rootActor")
// implicit val timeout: Timeout = Timeout(3.seconds)
// val scalaScriptActor: Future[ActorRef[ScalaScriptBehavior.Command]] =
// actorSystem.ask(
// SpawnProtocol.Spawn(
// ScalaScriptBehavior(sse.runner),
// name = "ScalaScriptCompilerActor",
// Props.empty,
// _
// )
// )
override def stop(): Unit = {}
// override protected def cleanup(app: Application): Unit = {
// // actorSystem.terminate()
// }
// override protected def initialize(app: Application): Unit = {
// super.initialize(app)
// }
override def init() = {
// Future {
// while (true) {
// // super.update(tpf)
// val (res, k) = sse.runner.runScript(
// // os.Path(getClass().getResource("/hello.sc").getPath),
// os.pwd / "src" / "main" / "resources" / "hello.sc",
// Seq.empty
// // Seq(("start", None))
// // Scripts.groupArgs(List(""))
// )
// val ms = res.map(_.asInstanceOf[GameScript])
// ms.map(_.start())
// val res2 = kse.engine.eval(
// os.read(os.pwd / "src" / "main" / "resources" / "hello.main.kts")
// )
// // val res2 = engine.eval(getClass().getResource("/hello.main.kts").getPath)
// // val invoker = engine.asInstanceOf[Invocable]
// // val scr = invoker.getInterface(res2, classOf[GameScript])
// val scr = res2.asInstanceOf[GameScript]
// scr.start()
// Thread.sleep(2000)
// }
// }
// Future {
// sse.runner
// .runScript(
// os.pwd / "src" / "main" / "resources" / "hello2.sc",
// Seq.empty
// )
// ._1
// .map(_.asInstanceOf[MyBaseState])
// .map(s => stateManager.attach(s))
// ()
// }
// val res = scalaScriptActor
// .map(
// _.ask(ref =>
// ScalaScriptBehavior.Compile(
// ref,
// os.pwd / "src" / "main" / "resources" / "hello2.sc"
// // os.Path(getClass().getResource("/hello2.sc").getPath)
// )
// )(Timeout(10.seconds), actorSystem.scheduler)
// )
// .flatten
// res.foreach(_ match {
// case AppStateResult(state) => {
// stateManager.attach(state)
// }
// case wow.doge.mygame.state.ScalaScriptBehavior.Error(reason) =>
// println("error")
// })
}
override def update(tpf: Float): Unit = {}
override protected def onEnable(): Unit = {}
override protected def onDisable(): Unit = {}
}
object MyActorSystem {
def apply(): Behavior[SpawnProtocol.Command] =
Behaviors.setup { context =>
// Start initial tasks
// context.spawn(...)
SpawnProtocol()
}
}
class ScalaScriptingEngine(
val runner: Main = ammonite
.Main(
// predefCode = """
// import coursierapi.MavenRepository
// interp.repositories.update(
// interp.repositories() ::: List(
// MavenRepository.of("file://home/rohan/.m2/repository")
// )
// )
// @
// """,
defaultPredef = false,
storageBackend = new Folder(Defaults.ammoniteHome, isRepl = false)
)
) {}
class KotlinScriptingEngine(val engine: ScriptEngine) {
// val manager = new ScriptEngineManager()
// val engine = manager.getEngineByExtension("main.kts")
}
object ScalaScriptBehavior {
sealed trait Result
final case class AppStateResult(state: AppState) extends Result
final case class Error(reason: String) extends Result
sealed trait Command
final case class Compile(sender: ActorRef[Result], path: os.Path)
extends Command
// final case class CompileScripts(sender: ActorRef[Result], paths: os.Path*)
// extends Command
def apply(
runner: Main = ammonite
.Main(
storageBackend = new Folder(
// os.pwd / "target"
Defaults.ammoniteHome,
isRepl = false
)
)
) =
Behaviors.setup(ctx => new ScalaScriptActor(runner, ctx))
private class ScalaScriptActor(
val runner: Main,
context: ActorContext[Command]
) extends AbstractBehavior[Command](context) {
override def onMessage(msg: Command): Behavior[Command] = {
msg match {
case Compile(sender, path) =>
context.log.debug(s"Received $path")
val res = getScript(path)
println(res)
sender ! res
Behaviors.same
// case CompileScripts(sender, paths) =>
}
}
def getScript(path: os.Path): Result = {
runner
.runScript(
path,
Seq.empty
)
._1 match {
case ammonite.util.Res.Exception(t, msg) => Error(msg)
case Success(obj) =>
obj match {
case s: MyBaseState => AppStateResult(s)
case _ => Error("Unknown script type")
// AppStateResult(s.asInstanceOf[AppState])
}
case _ => Error("Failed to run script")
}
}
}
}

View File

@ -1,71 +0,0 @@
package wow.doge.mygame.state
import com.jme3.asset.AssetManager
import com.jme3.material.Material
import com.jme3.math.ColorRGBA
import com.jme3.math.Vector3f
import com.jme3.scene.Geometry
import com.jme3.scene.shape.Box
import wow.doge.mygame.components.TestComponent
import wow.doge.mygame.implicits._
class TestAppState(
// private var _entity: Option[EntityData] = Some(new DefaultEntityData())
) extends MyBaseState {
var geom: Option[Geometry] = None
// def entity = _entity
// override def initialize(app: Application): Unit = {
// super.initialize(app)
// }
override def init() = {
entityData
.createEntity()
.withComponents(TestComponent())
// entityData.setComponents(x, TestComponent())
val es = entityData.getEntities(classOf[TestComponent])
println(es)
val b = new Box(1, 1, 1)
geom = Some(new Geometry("Box", b))
val mat = MyMaterial(
assetManager = assetManager,
path = os.rel / "Common" / "MatDefs" / "Misc" / "Unshaded.j3md"
)
geom.foreach(e => {
e.setMaterial(mat)
rootNode.attachChild(e)
})
}
override def update(tpf: Float) = {
geom.foreach(_.rotate(0, 0.5f * tpf, 0))
geom.foreach(_.move(new Vector3f(0, 1 * tpf, 0)))
}
// override def cleanup(app: Application): Unit = {
// // _entity.map(_.close())
// // _entity = None
// }
override def onEnable(): Unit = {}
override def onDisable(): Unit = {}
override def stop(): Unit = {}
}
object MyMaterial {
def apply(
color: String = "Color",
colorType: com.jme3.math.ColorRGBA = ColorRGBA.Blue,
assetManager: AssetManager,
path: os.RelPath
): Material = {
val mat =
new Material(assetManager, path.toString())
mat.setColor(color, colorType)
mat
}
}

View File

@ -2,6 +2,7 @@ package wow.doge.mygame.game.controls
import scala.concurrent.Future import scala.concurrent.Future
import cats.syntax.eq._
import com.jme3.math.FastMath import com.jme3.math.FastMath
import com.jme3.math.Quaternion import com.jme3.math.Quaternion
import com.jme3.math.Vector3f import com.jme3.math.Vector3f
@ -26,6 +27,7 @@ import wow.doge.mygame.game.subsystems.input.PlayerCameraInput
* @param rotateFn * @param rotateFn
* @param s * @param s
*/ */
@SuppressWarnings(Array("org.wartremover.warts.Null"))
class CameraMovementControl( class CameraMovementControl(
rotationBuf: Quaternion, rotationBuf: Quaternion,
obs: Observable[PlayerCameraInput], obs: Observable[PlayerCameraInput],
@ -49,7 +51,7 @@ class CameraMovementControl(
} }
override def controlUpdate(tpf: Float): Unit = override def controlUpdate(tpf: Float): Unit =
if (_event != null) { if (_event =!= null) {
_event match { _event match {
case PlayerCameraInput.CameraRotateLeft => case PlayerCameraInput.CameraRotateLeft =>
val rot = rotationBuf val rot = rotationBuf
@ -75,6 +77,8 @@ class CameraMovementControl(
x$1: RenderManager, x$1: RenderManager,
x$2: ViewPort x$2: ViewPort
): Unit = {} ): Unit = {}
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
override def setSpatial(spatial: Spatial): Unit = { override def setSpatial(spatial: Spatial): Unit = {
super.setSpatial(spatial) super.setSpatial(spatial)
if (this.spatial != null) if (this.spatial != null)

View File

@ -4,14 +4,18 @@ import akka.actor.typed.ActorRef
import akka.actor.typed.Behavior import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.Behaviors
import cats.Show
import io.estatico.newtype.macros.newtype import io.estatico.newtype.macros.newtype
import wow.doge.mygame.game.entities.CharacterStats.HealHealth import wow.doge.mygame.game.entities.CharacterStats.HealHealth
case class CharacterStats(hp: CharacterStats.Health, stamina: Int) final case class CharacterStats(
hp: CharacterStats.Health,
stamina: CharacterStats.Stamina
)
object CharacterStats { object CharacterStats {
@newtype case class HealHealth(toInt: Int) @newtype final case class HealHealth(toInt: Int)
@newtype case class DamageHealth(toInt: Int) @newtype final case class DamageHealth(toInt: Int)
@newtype case class Health(toInt: Int) @newtype final case class Health(toInt: Int)
object Health { object Health {
implicit class HealthOps(private val h: Health) extends AnyVal { implicit class HealthOps(private val h: Health) extends AnyVal {
// def +(v: Int): Health = Health(h.toInt + v) // def +(v: Int): Health = Health(h.toInt + v)
@ -22,9 +26,9 @@ object CharacterStats {
def -(v: DamageHealth): Health = Health(h.toInt - v.toInt) def -(v: DamageHealth): Health = Health(h.toInt - v.toInt)
} }
} }
@newtype case class HealStamina(toInt: Int) @newtype final case class HealStamina(toInt: Int)
@newtype case class DamageStamina(toInt: Int) @newtype final case class DamageStamina(toInt: Int)
@newtype case class Stamina(toInt: Int) @newtype final case class Stamina(toInt: Int)
object Stamina { object Stamina {
implicit class StaminaOps(private val h: Stamina) extends AnyVal { implicit class StaminaOps(private val h: Stamina) extends AnyVal {
// def +(v: Int): Stamina = Stamina(h.toInt + v) // def +(v: Int): Stamina = Stamina(h.toInt + v)
@ -53,18 +57,25 @@ object CharacterStats {
// } // }
// } // }
implicit val show = Show.fromToString[CharacterStats]
} }
object StatsActor { object StatsActor {
sealed trait Command sealed trait Command
// case class TakeDamage(value: Int) extends Command // final case class TakeDamage(value: Int) extends Command
case class TakeDamageResult( final case class TakeDamageResult(
value: CharacterStats.DamageHealth, value: CharacterStats.DamageHealth,
replyTo: ActorRef[(Boolean, CharacterStats)] replyTo: ActorRef[(Boolean, CharacterStats)]
) extends Command ) extends Command
case class HealResult(value: HealHealth) extends Command final case class ConsumeStaminaResult(
case class CurrentStats(replyTo: ActorRef[CharacterStats]) extends Command value: CharacterStats.DamageStamina,
replyTo: ActorRef[(Boolean, CharacterStats)]
) extends Command
final case class HealResult(value: HealHealth) extends Command
final case class CurrentStats(replyTo: ActorRef[CharacterStats])
extends Command
class Props( class Props(
startingHealth: CharacterStats.Health, startingHealth: CharacterStats.Health,
@ -74,12 +85,12 @@ object StatsActor {
Behaviors.setup[Command] { ctx => Behaviors.setup[Command] { ctx =>
new StatsActor(ctx, this) new StatsActor(ctx, this)
.receive( .receive(
State(CharacterStats(startingHealth, startingStamina.toInt)) State(CharacterStats(startingHealth, startingStamina))
) )
} }
} }
case class State(stats: CharacterStats) final case class State(stats: CharacterStats)
} }
class StatsActor( class StatsActor(
ctx: ActorContext[StatsActor.Command], ctx: ActorContext[StatsActor.Command],
@ -100,11 +111,24 @@ class StatsActor(
// receive(nextState) // receive(nextState)
case TakeDamageResult(value, replyTo) => case TakeDamageResult(value, replyTo) =>
val nextState = if ((state.stats.hp - value).toInt <= 0) { val nextState = if ((state.stats.hp - value).toInt <= 0) {
replyTo ! true -> state.stats val s = state.modify(_.stats.hp).setTo(Health(0))
state.modify(_.stats.hp).setTo(Health(0)) replyTo ! true -> s.stats
s
} else { } else {
replyTo ! false -> state.stats val s = state.modify(_.stats.hp).using(_ - value)
state.modify(_.stats.hp).using(_ - value) replyTo ! false -> s.stats
s
}
receive(nextState)
case ConsumeStaminaResult(value, replyTo) =>
val nextState = if ((state.stats.stamina - value).toInt <= 0) {
val s = state.modify(_.stats.stamina).setTo(Stamina(0))
replyTo ! false -> s.stats
s
} else {
val s = state.modify(_.stats.stamina).using(_ - value)
replyTo ! false -> s.stats
s
} }
receive(nextState) receive(nextState)
case HealResult(value) => case HealResult(value) =>

View File

@ -10,6 +10,7 @@ import akka.actor.typed.SupervisorStrategy
import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.Behaviors
import akka.util.Timeout import akka.util.Timeout
import cats.syntax.eq._
import cats.syntax.show._ import cats.syntax.show._
import monix.execution.CancelableFuture import monix.execution.CancelableFuture
import monix.execution.CancelablePromise import monix.execution.CancelablePromise
@ -39,8 +40,8 @@ object NpcActorSupervisor {
signal: CancelableFuture[NpcMovementActor.DoneMoving.type] signal: CancelableFuture[NpcMovementActor.DoneMoving.type]
) extends Command ) extends Command
private case object DoneMoving extends Command private case object DoneMoving extends Command
private case class LogError(err: Throwable) extends Command private final case class LogError(err: Throwable) extends Command
private case class MovementFailed(err: Throwable) extends Command private final case class MovementFailed(err: Throwable) extends Command
class Props( class Props(
val npcMovementActorBehavior: Behavior[NpcMovementActor.Command], val npcMovementActorBehavior: Behavior[NpcMovementActor.Command],
@ -86,7 +87,7 @@ class NpcActorSupervisor(
def idle(state: State): Behavior[NpcActorSupervisor.Command] = def idle(state: State): Behavior[NpcActorSupervisor.Command] =
Behaviors.setup { _ => Behaviors.setup { _ =>
ctx.log.debugP(s"npcActor-${props.npcName}: Entered Idle State") ctx.log.debugP(show"npcActor-${props.npcName}: Entered Idle State")
Behaviors.receiveMessage[Command] { Behaviors.receiveMessage[Command] {
case m @ Move(pos) => case m @ Move(pos) =>
ctx.ask( ctx.ask(
@ -113,7 +114,7 @@ class NpcActorSupervisor(
signal: CancelableFuture[NpcMovementActor.DoneMoving.type] signal: CancelableFuture[NpcMovementActor.DoneMoving.type]
): Behavior[NpcActorSupervisor.Command] = ): Behavior[NpcActorSupervisor.Command] =
Behaviors.setup { _ => Behaviors.setup { _ =>
ctx.log.debugP(s"npcActor-${props.npcName}: Entered Moving State") ctx.log.debugP(show"npcActor-${props.npcName}: Entered Moving State")
movementTimer ! GenericTimerActor.Start movementTimer ! GenericTimerActor.Start
ctx.pipeToSelf(signal) { ctx.pipeToSelf(signal) {
case Success(value) => DoneMoving case Success(value) => DoneMoving
@ -150,7 +151,7 @@ class NpcActorSupervisor(
} }
def logError(err: Throwable) = def logError(err: Throwable) =
ctx.log.errorP(s"npcActor-${props.npcName}: " + err.getMessage) ctx.log.errorP(show"npcActor-${props.npcName}: " + err.getMessage)
} }
object NpcMovementActor { object NpcMovementActor {
@ -158,10 +159,10 @@ object NpcMovementActor {
case object DoneMoving case object DoneMoving
sealed trait Command sealed trait Command
case class AskPosition(replyTo: ActorRef[ImVector3f]) extends Command final case class AskPosition(replyTo: ActorRef[ImVector3f]) extends Command
case object MovementTick extends Command case object MovementTick extends Command
case object StopMoving extends Command case object StopMoving extends Command
case class MoveTo( final case class MoveTo(
target: ImVector3f, target: ImVector3f,
doneSignal: ActorRef[CancelableFuture[DoneMoving.type]] doneSignal: ActorRef[CancelableFuture[DoneMoving.type]]
) extends Command ) extends Command
@ -212,7 +213,7 @@ class NpcMovementActor[T](
Behaviors.receiveMessagePartial { Behaviors.receiveMessagePartial {
case StopMoving => case StopMoving =>
ctx.log.debugP( ctx.log.debugP(
show"npcActor-${props.npcName}: Position at Stop = " + location show"npcActor-${props.npcName}: Position at Stop = $location"
) )
props.enqueueR(() => cm.stop(props.movable)) props.enqueueR(() => cm.stop(props.movable))
receive(state) receive(state)
@ -262,19 +263,19 @@ object NpcMovementActorNotUsed {
case event: EntityMovementEvent => case event: EntityMovementEvent =>
event match { event match {
case MovedLeft(name, pressed) => case MovedLeft(name, pressed) =>
if (name == npcName) if (name === npcName)
movementActor ! ImMovementActor.MoveLeft(pressed) movementActor ! ImMovementActor.MoveLeft(pressed)
Behaviors.same Behaviors.same
case MovedUp(name, pressed) => case MovedUp(name, pressed) =>
if (name == npcName) if (name === npcName)
movementActor ! ImMovementActor.MoveUp(pressed) movementActor ! ImMovementActor.MoveUp(pressed)
Behaviors.same Behaviors.same
case MovedRight(name, pressed) => case MovedRight(name, pressed) =>
if (name == npcName) if (name === npcName)
movementActor ! ImMovementActor.MoveRight(pressed) movementActor ! ImMovementActor.MoveRight(pressed)
Behaviors.same Behaviors.same
case MovedDown(name, pressed) => case MovedDown(name, pressed) =>
if (name == npcName) if (name === npcName)
movementActor ! ImMovementActor.MoveDown(pressed) movementActor ! ImMovementActor.MoveDown(pressed)
Behaviors.same Behaviors.same
} }

View File

@ -12,7 +12,10 @@ import akka.actor.typed.SupervisorStrategy
import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.Behaviors
import akka.util.Timeout import akka.util.Timeout
import cats.syntax.show._
import com.typesafe.scalalogging.Logger import com.typesafe.scalalogging.Logger
import monix.eval.Coeval
import monix.execution.AsyncQueue
import monix.reactive.Observable import monix.reactive.Observable
import monix.reactive.OverflowStrategy import monix.reactive.OverflowStrategy
import monix.reactive.subjects.ConcurrentSubject import monix.reactive.subjects.ConcurrentSubject
@ -27,8 +30,6 @@ 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.events.TickEvent.RenderTick import wow.doge.mygame.subsystems.events.TickEvent.RenderTick
import wow.doge.mygame.subsystems.movement.ImMovementActor import wow.doge.mygame.subsystems.movement.ImMovementActor
import monix.eval.Coeval
import monix.execution.AsyncQueue
object PlayerActorSupervisor { object PlayerActorSupervisor {
type Ref = ActorRef[PlayerActorSupervisor.Command] type Ref = ActorRef[PlayerActorSupervisor.Command]
@ -40,28 +41,29 @@ object PlayerActorSupervisor {
} }
sealed trait Command sealed trait Command
case class TakeDamage(value: CharacterStats.DamageHealth) extends Command final case class TakeDamage(
case class TakeDamage2(
value: CharacterStats.DamageHealth, value: CharacterStats.DamageHealth,
replyTo: ActorRef[Unit] replyTo: ActorRef[Unit]
) extends Command ) extends Command
case class Heal(value: CharacterStats.HealHealth) extends Command final case class ConsumeStamina(
case class CurrentStats(replyTo: ActorRef[CharacterStats]) extends Command value: CharacterStats.DamageStamina,
case class GetStatus(replyTo: ActorRef[Status]) extends Command replyTo: ActorRef[Unit]
case class GetStatsObservable(replyTo: ActorRef[Observable[CharacterStats]]) ) extends Command
extends Command final case class Heal(value: CharacterStats.HealHealth) extends Command
case class GetStatsObservable2(replyTo: ActorRef[Observable[CharacterStats]]) final case class CurrentStats(replyTo: ActorRef[CharacterStats])
extends Command extends Command
final case class GetStatus(replyTo: ActorRef[Status]) extends Command
final case class GetStatsObservable(
replyTo: ActorRef[Observable[CharacterStats]]
) extends Command
private case object Die extends Command private case object Die extends Command
private case class DamageResponse(response: (Boolean, CharacterStats)) private final case class DamageResponse(
extends Command
private case class DamageResponse2(
response: (Boolean, CharacterStats), response: (Boolean, CharacterStats),
replyTo: ActorRef[Unit] replyTo: ActorRef[Unit]
) extends Command ) extends Command
// private case class InternalTakeDamage(old: Int, value: Int) extends Command // private final case class InternalTakeDamage(old: Int, value: Int) extends Command
private case class LogError(ex: Throwable) extends Command private final case class LogError(ex: Throwable) extends Command
class Props( class Props(
val playerEventBus: GameEventBus[PlayerEvent], val playerEventBus: GameEventBus[PlayerEvent],
val tickEventBus: GameEventBus[TickEvent], val tickEventBus: GameEventBus[TickEvent],
@ -80,6 +82,15 @@ object PlayerActorSupervisor {
ctx.log.infoP("Starting PlayerActor") ctx.log.infoP("Starting PlayerActor")
// spawn children actors // spawn children actors
val playerStatsActor =
ctx.spawnN(
new StatsActor.Props(
CharacterStats.Health(100),
CharacterStats.Stamina(100)
).behavior
)
val playerMovementActor = val playerMovementActor =
ctx.spawnN( ctx.spawnN(
Behaviors Behaviors
@ -90,14 +101,6 @@ object PlayerActorSupervisor {
Dispatchers.jmeDispatcher Dispatchers.jmeDispatcher
) )
val playerStatsActor =
ctx.spawnN(
new StatsActor.Props(
CharacterStats.Health(100),
CharacterStats.Stamina(100)
).behavior
)
val playerMovementEl = ctx.spawnN( val playerMovementEl = ctx.spawnN(
Behaviors Behaviors
.supervise(PlayerMovementEventListener(playerMovementActor)) .supervise(PlayerMovementEventListener(playerMovementActor))
@ -146,7 +149,7 @@ object PlayerActorSupervisor {
} }
case class Children( final case class Children(
movementActor: ActorRef[ImMovementActor.Command], movementActor: ActorRef[ImMovementActor.Command],
statsActor: ActorRef[StatsActor.Command] statsActor: ActorRef[StatsActor.Command]
) )
@ -163,28 +166,27 @@ class PlayerActorSupervisor(
val aliveState = val aliveState =
Behaviors Behaviors
.receiveMessage[Command] { .receiveMessage[Command] {
case TakeDamage(value) => case TakeDamage(value, replyTo) =>
// children.movementActor ! ImMovementActor.MovedDown(true) // children.movementActor ! ImMovementActor.MovedDown(true)
// ctx.ask(children.statsActor, StatsActor.CurrentStats(_)) { // ctx.ask(children.statsActor, StatsActor.CurrentStats(_)) {
// case Success(status) => InternalTakeDamage(status.hp, value) // case Success(status) => InternalTakeDamage(status.hp, value)
// case Failure(ex) => LogError(ex) // case Failure(ex) => LogError(ex)
// } // }
ctx.ask(children.statsActor, StatsActor.TakeDamageResult(value, _)) { ctx.ask(children.statsActor, StatsActor.TakeDamageResult(value, _)) {
case Success(response) => DamageResponse(response) case Success(response) => DamageResponse(response, replyTo)
case Failure(ex) => LogError(ex) case Failure(ex) => LogError(ex)
} }
Behaviors.same Behaviors.same
case TakeDamage2(value, replyTo) => case ConsumeStamina(value, replyTo) =>
// children.movementActor ! ImMovementActor.MovedDown(true) ctx.ask(
// ctx.ask(children.statsActor, StatsActor.CurrentStats(_)) { children.statsActor,
// case Success(status) => InternalTakeDamage(status.hp, value) StatsActor.ConsumeStaminaResult(value, _)
// case Failure(ex) => LogError(ex) ) {
// } case Success(response) => DamageResponse(response, replyTo)
ctx.ask(children.statsActor, StatsActor.TakeDamageResult(value, _)) {
case Success(response) => DamageResponse2(response, replyTo)
case Failure(ex) => LogError(ex) case Failure(ex) => LogError(ex)
} }
Behaviors.same Behaviors.same
Behaviors.same
case CurrentStats(replyTo) => case CurrentStats(replyTo) =>
// ctx.ask(children.statsActor, StatsActor.CurrentStats()) // ctx.ask(children.statsActor, StatsActor.CurrentStats())
children.statsActor ! StatsActor.CurrentStats(replyTo) children.statsActor ! StatsActor.CurrentStats(replyTo)
@ -203,28 +205,21 @@ class PlayerActorSupervisor(
// Behaviors.same // Behaviors.same
// } // }
case GetStatsObservable(replyTo) => case GetStatsObservable(replyTo) =>
replyTo ! statsSubject
Behaviors.same
case GetStatsObservable2(replyTo) =>
import monix.{eval => me} import monix.{eval => me}
replyTo ! Observable.repeatEvalF( replyTo ! Observable.repeatEvalF(
me.Task.deferFuture(statsQueue.poll()) me.Task.deferFuture(statsQueue.poll())
) )
Behaviors.same Behaviors.same
case DamageResponse(response) => case DamageResponse(response, replyTo) =>
response match {
case (dead, state) =>
if (dead) ctx.self ! Die
statsSubject.onNext(state)
}
Behaviors.same
case DamageResponse2(response, replyTo) =>
response match { response match {
case (dead, stats) => case (dead, stats) =>
if (dead) ctx.self ! Die if (dead) ctx.self ! Die
statsQueue statsQueue
.offer(stats) .offer(stats)
.foreach(_ => replyTo ! ())(props.scheduler.value) .foreach { _ =>
pprint.log(show"Published stats $stats")
replyTo ! ()
}(props.scheduler.value)
} }
Behaviors.same Behaviors.same
case Die => deadState case Die => deadState

View File

@ -121,7 +121,7 @@ object PlayerActorSupervisor2 {
} }
case class Children( final case class Children(
movementActor: ActorRef[ImMovementActor.Command] movementActor: ActorRef[ImMovementActor.Command]
) )
} }

View File

@ -37,7 +37,7 @@ object PlayerCameraActor {
) )
} }
case class State() final case class State()
object State { object State {
val empty = State() val empty = State()
} }

View File

@ -27,7 +27,8 @@ import wow.doge.mygame.utils.wrappers.jme._
object PlayerController { object PlayerController {
sealed trait Error sealed trait Error
case class CouldNotCreatePlayerModel(reason: AssetManager.Error) extends Error final case class CouldNotCreatePlayerModel(reason: AssetManager.Error)
extends Error
object Tags { object Tags {
sealed trait PlayerNode sealed trait PlayerNode

View File

@ -11,8 +11,8 @@ import wow.doge.mygame.game.subsystems.ai.gdx.MyIndexedGraph
// import com.badlogic.gdx.ai.pfa.indexed.IndexedGraph // import com.badlogic.gdx.ai.pfa.indexed.IndexedGraph
// import scala.jdk.javaapi.CollectionConverters._ // import scala.jdk.javaapi.CollectionConverters._
case class City(x: Float, y: Float, name: String, index: Int) final case class City(x: Float, y: Float, name: String, index: Int)
case class Street(fromNode: City, toNode: City, cost: Float) final case class Street(fromNode: City, toNode: City, cost: Float)
extends Connection[City] { extends Connection[City] {
override def getCost(): Float = cost override def getCost(): Float = cost

View File

@ -1,6 +1,9 @@
package wow.doge.mygame.game.subsystems.input package wow.doge.mygame.game.subsystems.input
import cats.Show
import cats.kernel.Eq
import enumeratum.EnumEntry._ import enumeratum.EnumEntry._
import enumeratum._ import enumeratum._
import io.circe.generic.semiauto._
sealed trait PlayerMovementInput extends EnumEntry with UpperSnakecase sealed trait PlayerMovementInput extends EnumEntry with UpperSnakecase
object PlayerMovementInput extends Enum[PlayerMovementInput] { object PlayerMovementInput extends Enum[PlayerMovementInput] {
@ -10,6 +13,9 @@ object PlayerMovementInput extends Enum[PlayerMovementInput] {
case object WalkLeft extends PlayerMovementInput case object WalkLeft extends PlayerMovementInput
case object WalkBackward extends PlayerMovementInput case object WalkBackward extends PlayerMovementInput
case object Jump extends PlayerMovementInput case object Jump extends PlayerMovementInput
implicit val eq = Eq.fromUniversalEquals[PlayerMovementInput]
implicit val show = Show.fromToString[PlayerMovementInput]
} }
sealed trait PlayerAnalogMovementInput extends EnumEntry with UpperSnakecase sealed trait PlayerAnalogMovementInput extends EnumEntry with UpperSnakecase
@ -17,6 +23,9 @@ object PlayerAnalogMovementInput extends Enum[PlayerAnalogMovementInput] {
val values = findValues val values = findValues
case object TurnRight extends PlayerAnalogMovementInput case object TurnRight extends PlayerAnalogMovementInput
case object TurnLeft extends PlayerAnalogMovementInput case object TurnLeft extends PlayerAnalogMovementInput
implicit val eq = Eq.fromUniversalEquals[PlayerAnalogMovementInput]
implicit val show = Show.fromToString[PlayerAnalogMovementInput]
} }
sealed trait PlayerCameraInput extends EnumEntry with UpperSnakecase sealed trait PlayerCameraInput extends EnumEntry with UpperSnakecase
@ -26,6 +35,10 @@ object PlayerCameraInput extends Enum[PlayerCameraInput] {
case object CameraRotateRight extends PlayerCameraInput case object CameraRotateRight extends PlayerCameraInput
case object CameraRotateUp extends PlayerCameraInput case object CameraRotateUp extends PlayerCameraInput
case object CameraRotateDown extends PlayerCameraInput case object CameraRotateDown extends PlayerCameraInput
implicit val eq = Eq.fromUniversalEquals[PlayerCameraInput]
implicit val show = Show.fromToString[PlayerCameraInput]
implicit val codec = deriveCodec[PlayerCameraInput]
} }
sealed trait MiscInput extends EnumEntry with UpperSnakecase sealed trait MiscInput extends EnumEntry with UpperSnakecase

View File

@ -1,55 +1,14 @@
package wow.doge.mygame.game.subsystems.level package wow.doge.mygame.game.subsystems.level
import com.jme3.asset.AssetManager
import com.jme3.bullet.control.RigidBodyControl
import com.jme3.bullet.util.CollisionShapeFactory
import com.jme3.light.AmbientLight import com.jme3.light.AmbientLight
import com.jme3.light.DirectionalLight import com.jme3.light.DirectionalLight
import com.jme3.math.ColorRGBA import com.jme3.math.ColorRGBA
import com.jme3.math.Vector3f import com.jme3.math.Vector3f
import com.jme3.renderer.ViewPort import com.jme3.renderer.ViewPort
import com.jme3.scene.Spatial
import monix.bio.IO import monix.bio.IO
import monix.bio.UIO import monix.bio.UIO
import wow.doge.mygame.AppError import wow.doge.mygame.AppError
object DefaultGameLevel { object DefaultGameLevel {
def apply(
assetManager: AssetManager,
viewPort: ViewPort
) = {
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")
}
)
val landscape: RigidBodyControl = new RigidBodyControl(sceneShape, 0)
viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f))
sceneModel.setLocalScale(2f)
sceneModel.addControl(landscape)
// discard { rootNode.attachChild(sceneModel) }
// bulletAppState.getPhysicsSpace.add(landscape)
// bulletAppState.getPhysicsSpace.add(player)
val al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(1.3f));
// app.rootNode.addLight(al);
val dl = new DirectionalLight();
dl.setColor(ColorRGBA.White);
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
// app.rootNode.addLight(dl);
new GameLevel(
model = sceneModel,
physicsControl = landscape,
ambientLight = al,
directionalLight = dl
)
}
def apply( def apply(
assetManager: wow.doge.mygame.utils.wrappers.jme.AssetManager, assetManager: wow.doge.mygame.utils.wrappers.jme.AssetManager,
viewPort: ViewPort viewPort: ViewPort

View File

@ -15,6 +15,8 @@ import wow.doge.mygame.utils.wrappers.jme.AppNode2
import wow.doge.mygame.utils.wrappers.jme.CollisionShapeFactory import wow.doge.mygame.utils.wrappers.jme.CollisionShapeFactory
import wow.doge.mygame.utils.wrappers.jme.PhysicsSpace import wow.doge.mygame.utils.wrappers.jme.PhysicsSpace
// case class Blah(humbug: String)
class GameLevel( class GameLevel(
val model: Spatial, val model: Spatial,
val physicsControl: RigidBodyControl, val physicsControl: RigidBodyControl,

View File

@ -11,11 +11,18 @@ import com.simsilica.es.Filters
class EntityQuery(ed: EntityData) { class EntityQuery(ed: EntityData) {
private var cfilter: Option[ComponentFilter[_ <: EntityComponent]] = None private var cfilter: Option[ComponentFilter[_ <: EntityComponent]] = None
@SuppressWarnings(Array("org.wartremover.warts.MutableDataStructures"))
private val buf = collection.mutable.ListBuffer.empty[Class[_]] private val buf = collection.mutable.ListBuffer.empty[Class[_]]
def filter[T <: EntityComponent](field: String, value: Object)(implicit def filter[T <: EntityComponent](field: String, value: Object)(implicit
ev: ClassTag[T] ev: ClassTag[T]
): EntityQuery = { ): EntityQuery = {
@SuppressWarnings(
Array(
"org.wartremover.warts.AsInstanceOf",
"org.wartremover.warts.Equals"
)
)
val c = ev.runtimeClass.asInstanceOf[Class[T]] val c = ev.runtimeClass.asInstanceOf[Class[T]]
cfilter = Try(Filters.fieldEquals(c, field, value)).toOption cfilter = Try(Filters.fieldEquals(c, field, value)).toOption
this this
@ -24,6 +31,12 @@ class EntityQuery(ed: EntityData) {
def filterOr[T <: EntityComponent](operands: ComponentFilter[_ <: T]*)( def filterOr[T <: EntityComponent](operands: ComponentFilter[_ <: T]*)(
implicit ev: ClassTag[T] implicit ev: ClassTag[T]
): EntityQuery = { ): EntityQuery = {
@SuppressWarnings(
Array(
"org.wartremover.warts.AsInstanceOf",
"org.wartremover.warts.Equals"
)
)
val c = ev.runtimeClass.asInstanceOf[Class[T]] val c = ev.runtimeClass.asInstanceOf[Class[T]]
cfilter = Try(Filters.or(c, operands: _*)).toOption cfilter = Try(Filters.or(c, operands: _*)).toOption
this this
@ -32,6 +45,12 @@ class EntityQuery(ed: EntityData) {
def filterAnd[T <: EntityComponent](operands: ComponentFilter[_ <: T]*)( def filterAnd[T <: EntityComponent](operands: ComponentFilter[_ <: T]*)(
implicit ev: ClassTag[T] implicit ev: ClassTag[T]
): EntityQuery = { ): EntityQuery = {
@SuppressWarnings(
Array(
"org.wartremover.warts.AsInstanceOf",
"org.wartremover.warts.Equals"
)
)
val c = ev.runtimeClass.asInstanceOf[Class[T]] val c = ev.runtimeClass.asInstanceOf[Class[T]]
cfilter = Try(Filters.and(c, operands: _*)).toOption cfilter = Try(Filters.and(c, operands: _*)).toOption
this this
@ -45,9 +64,8 @@ class EntityQuery(ed: EntityData) {
this this
} }
def components[T <: EntityComponent](lst: Class[T]*): EntitySet = { def components[T <: EntityComponent](lst: Class[T]*): EntitySet =
ed.getEntities(lst: _*) ed.getEntities(lst: _*)
}
def result: EntitySet = def result: EntitySet =
cfilter.fold(ed.getEntities(buf.toList: _*)) { filters => cfilter.fold(ed.getEntities(buf.toList: _*)) { filters =>

View File

@ -1,30 +1,75 @@
package wow.doge.mygame.implicits package wow.doge.mygame.implicits
import javafx.beans.value.ObservableValue import javafx.beans.property.ObjectProperty
import javafx.beans.{value => jfxbv} import javafx.collections.ObservableList
import javafx.event.ActionEvent
import javafx.event.EventHandler
import javafx.scene.{input => jfxsi} import javafx.scene.{input => jfxsi}
import javafx.{event => jfxe} import javafx.{event => jfxe}
import monix.bio.Task
import monix.eval.Coeval
import monix.execution.Ack import monix.execution.Ack
import monix.execution.Cancelable import monix.execution.Cancelable
import monix.execution.Scheduler
import monix.execution.cancelables.CompositeCancelable
import monix.execution.cancelables.SingleAssignCancelable
import monix.reactive.Observable import monix.reactive.Observable
import monix.reactive.Observer
import monix.reactive.OverflowStrategy import monix.reactive.OverflowStrategy
import monix.tail.Iterant
import monix.{eval => me}
import org.gerweck.scalafx.util._
import scalafx.Includes._
import scalafx.beans.property.Property import scalafx.beans.property.Property
import scalafx.beans.property.ReadOnlyProperty
import scalafx.collections.ObservableBuffer
import scalafx.event.subscriptions.Subscription
import scalafx.scene.Scene import scalafx.scene.Scene
import scalafx.scene.control.ButtonBase import scalafx.scene.control.ButtonBase
import scalafx.scene.control.MenuItem
trait JavaFXMonixObservables {
import JavaFXMonixObservables._
implicit def extendedScene(scene: Scene) = new SceneExt(scene)
implicit def extendedProperty[T, J](
propery: Property[T, J]
): PropertyExt[T, J] =
new PropertyExt(propery)
implicit def extendedObjectPropety[A](prop: ObjectProperty[A]) =
new ObjectPropertyExt[A](prop)
implicit def extendedReadOnlyObjectPropety[T, J](
prop: ReadOnlyProperty[T, J]
) =
new ReadOnlyPropertyExt[T, J](prop)
implicit def extendedObservableList[A](
list: ObservableBuffer[A]
) = new ObservableListExt(list)
implicit def extendedStringObservableList(
list: ObservableList[String]
) = new StringObservableListExt(list)
implicit def extendedObjectPropertyObservableList[A](
prop: ObjectProperty[ObservableList[A]]
) = new ObjectPropertyObservableListExt(prop)
implicit def extendedButton(button: ButtonBase) = new ButtonBaseExt(button)
implicit def extendedMenuItem(item: MenuItem) = new MenuItemExt(item)
// implicit val implShowForOsRelPath = Show.fromToString[os.Path]
implicit def osRelPath2String(path: os.RelPath): String = path.toString()
}
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
object JavaFXMonixObservables { object JavaFXMonixObservables {
implicit final class SceneObservables(private val scene: Scene) final class SceneExt(private val scene: Scene) extends AnyVal {
extends AnyVal {
def observableMousePressed(): Observable[jfxsi.MouseEvent] = { def observableMousePressed(): Observable[jfxsi.MouseEvent] = {
import monix.execution.cancelables.SingleAssignCancelable import monix.execution.cancelables.SingleAssignCancelable
Observable.create(OverflowStrategy.Unbounded) { sub => Observable.create(OverflowStrategy.Unbounded) { sub =>
val c = SingleAssignCancelable() val c = SingleAssignCancelable()
val l = new jfxe.EventHandler[jfxsi.MouseEvent] { val l = new jfxe.EventHandler[jfxsi.MouseEvent] {
override def handle(event: jfxsi.MouseEvent): Unit = { override def handle(event: jfxsi.MouseEvent): Unit =
if (sub.onNext(event) == Ack.Stop) c.cancel() if (sub.onNext(event) == Ack.Stop) c.cancel()
} }
}
scene.onMousePressed = l scene.onMousePressed = l
c := Cancelable(() => c := Cancelable(() =>
@ -36,17 +81,17 @@ object JavaFXMonixObservables {
c c
} }
} }
def observableMouseDragged(): Observable[jfxsi.MouseEvent] = { def observableMouseDragged(): Observable[jfxsi.MouseEvent] = {
import monix.execution.cancelables.SingleAssignCancelable import monix.execution.cancelables.SingleAssignCancelable
Observable.create(OverflowStrategy.Unbounded) { sub => Observable.create(OverflowStrategy.Unbounded) { sub =>
val c = SingleAssignCancelable() val c = SingleAssignCancelable()
val l = new jfxe.EventHandler[jfxsi.MouseEvent] { val l = new jfxe.EventHandler[jfxsi.MouseEvent] {
override def handle(event: jfxsi.MouseEvent): Unit = { override def handle(event: jfxsi.MouseEvent): Unit =
if (sub.onNext(event) == Ack.Stop) c.cancel() if (sub.onNext(event) == Ack.Stop) c.cancel()
} }
}
scene.onMouseDragged = l scene.onMouseDragged = l;
c := Cancelable(() => c := Cancelable(() =>
scene.removeEventHandler( scene.removeEventHandler(
jfxsi.MouseEvent.MOUSE_DRAGGED, jfxsi.MouseEvent.MOUSE_DRAGGED,
@ -58,47 +103,225 @@ object JavaFXMonixObservables {
} }
} }
implicit final class BindObs[A, B](private val prop: Property[A, B]) final class PropertyExt[T, J](private val prop: Property[T, J])
extends AnyVal { extends AnyVal {
def <--[T](op: Observable[(ObservableValue[_ <: B], B, B)] => T) = { def -->[J1 >: J](sub: Observer[J1]) =
op(prop.observableChange()) prop.onChange((a, b, c) => if (c != null) sub.onNext(c))
}
def observableChange(): Observable[(ObservableValue[_ <: B], B, B)] = { def ==>(op: Property[T, J]) =
op <== prop
def <--(
obs: Observable[T]
)(implicit s: Scheduler, c: CompositeCancelable): Unit =
c += obs.doOnNextF(v => Coeval(prop.value = v)).subscribe()
def asOption = prop.map(Option(_))
def observableChange[J1 >: J]: Observable[J1] = {
import monix.execution.cancelables.SingleAssignCancelable import monix.execution.cancelables.SingleAssignCancelable
Observable.create(OverflowStrategy.Unbounded) { sub => Observable.create(OverflowStrategy.Unbounded) { sub =>
val c = SingleAssignCancelable() val c = SingleAssignCancelable()
val listener = new jfxbv.ChangeListener[B] { val canc =
override def changed( prop.onChange((a, b, c1) =>
observable: ObservableValue[_ <: B], if (c1 != null && sub.onNext(c1) == Ack.Stop) c.cancel()
oldValue: B, )
newValue: B
): Unit = {
sub.onNext((observable, oldValue, newValue))
}
}
prop.addListener(listener) c := Cancelable(() => canc.cancel())
c := Cancelable(() => prop.removeListener(listener))
c c
} }
} }
} }
implicit final class OnActionObservable( final class ObjectPropertyExt[A](private val prop: ObjectProperty[A])
private val button: ButtonBase extends AnyVal {
) extends AnyVal {
def observableAction(): Observable[jfxe.ActionEvent] = { @SuppressWarnings(Array("org.wartremover.warts.Throw"))
def -->(sub: Observer[A]) =
prop.onChange((a, b, c) =>
if (c != null)
if (sub.onNext(c) == Ack.Stop) throw new Exception("boom")
)
def ==>(op: Property[A, A]) =
prop.onChange((a, b, c) => if (c != null) op() = c)
def <--(obs: Observable[A])(implicit s: Scheduler) =
obs.doOnNextF(v => Coeval(prop() = v)).subscribe()
def observableChange[J1 >: A]: Observable[J1] = {
import monix.execution.cancelables.SingleAssignCancelable import monix.execution.cancelables.SingleAssignCancelable
Observable.create(OverflowStrategy.Unbounded) { sub => Observable.create(OverflowStrategy.Unbounded) { sub =>
val c = SingleAssignCancelable() val c = SingleAssignCancelable()
val l = new jfxe.EventHandler[jfxe.ActionEvent] {
override def handle(event: jfxe.ActionEvent): Unit = { val canc = prop.onChange((_, _, c1) =>
if (sub.onNext(event) == Ack.Stop) c.cancel() if (c1 != null && sub.onNext(c1) == Ack.Stop) c.cancel()
)
c := Cancelable(() => canc.cancel())
c
} }
} }
}
final class ObservableListExt[A](
private val buffer: ObservableBuffer[A]
) extends AnyVal {
// def -->(sub: Observer[A]) =
// buffer.onChange((a, b, c) => if (c != null) sub.onNext(c))
// def -->(op: Property[A, A]) = {
// buffer.onChange((a, b, c) => if (c != null) op() = c)
// }
def <--(
obs: Observable[A]
)(implicit s: Scheduler, c: CompositeCancelable): Unit =
c += obs
.doOnNextF(v =>
for {
_ <- Coeval(
println(s"Current Thread: ${Thread.currentThread().getName}")
)
_ <- Coeval(buffer.clear())
_ <- Coeval(buffer += v)
} yield ()
)
.subscribe()
def observableChange[J1 >: A]: Observable[J1] = {
import monix.execution.cancelables.SingleAssignCancelable
Observable.create(OverflowStrategy.Unbounded) { sub =>
val c = SingleAssignCancelable()
implicit val s = sub.scheduler
val canc =
buffer.onChange((buf, _) =>
loop(sub, buf.toIterable.iterator, c).runToFuture
)
c := Cancelable(() => canc.cancel())
c
}
}
private def loop(
sub: Observer[A],
it: Iterator[A],
c: Cancelable
): Task[Unit] =
if (it.hasNext) {
val next = it.next()
Task.deferFuture(sub.onNext(next)).flatMap {
case Ack.Continue => loop(sub, it, c)
case Ack.Stop => Task(c.cancel())
}
} else Task.unit
}
final class StringObservableListExt(
private val buffer: ObservableList[String]
) extends AnyVal {
// def ++=[T](that: Seq[T])(implicit S: Show[T]): Unit =
// buffer ++= that.map(S.show)
// def ++=[T](that: Seq[T])(implicit C: CssPath[T]): Unit =
// buffer ++= that.map(C.path)
}
final class ReadOnlyPropertyExt[T, J](
private val prop: ReadOnlyProperty[T, J]
) extends AnyVal {
def -->[J1 >: J](sub: Observer[J1]) =
prop.onChange((a, b, c) => if (c != null) sub.onNext(c))
def ==>(op: Property[T, J]) =
op <== prop
def observableChange[J1 >: J]: Observable[J1] = {
import monix.execution.cancelables.SingleAssignCancelable
Observable.create(OverflowStrategy.Unbounded) { sub =>
val c = SingleAssignCancelable()
val canc = prop.onChange((a, b, c1) =>
if (c1 != null && sub.onNext(c1) == Ack.Stop) c.cancel()
)
c := Cancelable(() => canc.cancel())
c
}
}
}
final class ObjectPropertyObservableListExt[A](
private val prop: ObjectProperty[ObservableList[A]]
) extends AnyVal {
def <--(obs: Observable[Seq[A]])(implicit s: Scheduler) =
obs.doOnNext(v => me.Task(prop() = ObservableBuffer.from(v))).subscribe()
def -->(sub: Observer[A])(implicit s: Scheduler) = {
val c = SingleAssignCancelable()
val subs: Subscription = prop.onChange((a, b, c1) =>
if (c1 != null)
Iterant[Task]
.fromIterable(c1.toIterable)
.consume
.use(consume(sub, c, _))
.runToFuture
)
c := Cancelable(() => subs.cancel())
}
private def loop(sub: Observer[A], it: Iterator[A]): Task[Unit] =
if (it.hasNext) {
val next = it.next()
Task.deferFuture(sub.onNext(next)).flatMap {
case Ack.Continue => loop(sub, it)
case Ack.Stop => Task.unit
}
} else Task.unit
private def consume(
sub: Observer[A],
c: Cancelable,
consumer: Iterant.Consumer[Task, A]
): Task[Unit] =
consumer.pull.flatMap {
case Left(value) => Task.unit
case Right(value) =>
Task.deferFuture(sub.onNext(value)).flatMap {
case Ack.Continue => consume(sub, c, consumer)
case Ack.Stop => Task(c.cancel())
}
}
}
final class ObjectPropertyActionEvent(
private val prop: ObjectProperty[EventHandler[ActionEvent]]
) extends AnyVal {
// def <--(obs: Observable[ActionEvent])(implicit s: Scheduler) = {
// obs.doOnNext(v => me.Task(prop() = ObservableBuffer.from(v))).subscribe()
// }
// def -->(sub: Observer[ActionEvent]) =
// prop().
}
// def emit(prop: ObjectProperty[EventHandler[ActionEvent]]) =
final class ButtonBaseExt(private val button: ButtonBase) extends AnyVal {
def observableAction: Observable[jfxe.ActionEvent] = {
import monix.execution.cancelables.SingleAssignCancelable
Observable.create(OverflowStrategy.DropNew(50)) { sub =>
val c = SingleAssignCancelable()
val l = new jfxe.EventHandler[jfxe.ActionEvent] {
override def handle(event: jfxe.ActionEvent): Unit =
if (sub.onNext(event) == Ack.Stop) c.cancel()
}
button.onAction = l button.onAction = l
c := Cancelable(() => c := Cancelable(() =>
@ -111,4 +334,27 @@ object JavaFXMonixObservables {
} }
} }
} }
final class MenuItemExt(private val item: MenuItem) extends AnyVal {
def observableAction: Observable[jfxe.ActionEvent] = {
import monix.execution.cancelables.SingleAssignCancelable
Observable.create(OverflowStrategy.DropNew(50)) { sub =>
val c = SingleAssignCancelable()
val l = new jfxe.EventHandler[jfxe.ActionEvent] {
override def handle(event: jfxe.ActionEvent): Unit =
if (sub.onNext(event) == Ack.Stop) c.cancel()
}
item.onAction = l
c := Cancelable(() =>
item.removeEventHandler(
jfxe.ActionEvent.ACTION,
l
)
)
c
}
}
}
} }

View File

@ -9,6 +9,7 @@ import akka.actor.typed.Props
import akka.actor.typed.Scheduler import akka.actor.typed.Scheduler
import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.ActorContext
import akka.util.Timeout import akka.util.Timeout
import cats.Show
import com.jayfella.jme.jfx.JavaFxUI import com.jayfella.jme.jfx.JavaFxUI
import com.jme3.app.Application import com.jme3.app.Application
import com.jme3.app.SimpleApplication import com.jme3.app.SimpleApplication
@ -61,7 +62,6 @@ import monix.reactive.OverflowStrategy
import monix.reactive.observers.Subscriber import monix.reactive.observers.Subscriber
import org.slf4j.Logger 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.utils.wrappers.jme.PhysicsSpace import wow.doge.mygame.utils.wrappers.jme.PhysicsSpace
final case class ActionEvent(binding: Action, value: Boolean, tpf: Float) final case class ActionEvent(binding: Action, value: Boolean, tpf: Float)
@ -87,7 +87,7 @@ final case class CollisionEvent(
appliedImpulse: Function0[Float] appliedImpulse: Function0[Float]
) )
package object implicits { package object implicits extends JavaFXMonixObservables {
type PrePhysicsTickEvent = PhysicsTickEvent type PrePhysicsTickEvent = PhysicsTickEvent
type PhysicsTickObservable = type PhysicsTickObservable =
Observable[Either[PrePhysicsTickEvent, PhysicsTickEvent]] Observable[Either[PrePhysicsTickEvent, PhysicsTickEvent]]
@ -102,6 +102,12 @@ package object implicits {
} }
implicit final class StateManagerExt(private val asm: AppStateManager) implicit final class StateManagerExt(private val asm: AppStateManager)
extends AnyVal { extends AnyVal {
@SuppressWarnings(
Array(
"org.wartremover.warts.AsInstanceOf",
"org.wartremover.warts.Equals"
)
)
def state[S <: AppState]()(implicit c: ClassTag[S]): S = def state[S <: AppState]()(implicit c: ClassTag[S]): S =
asm.getState(c.runtimeClass.asInstanceOf[Class[S]]) asm.getState(c.runtimeClass.asInstanceOf[Class[S]])
@ -121,26 +127,6 @@ package object implicits {
def viewPort = sa.getViewPort() def viewPort = sa.getViewPort()
def rootNode = sa.getRootNode() def rootNode = sa.getRootNode()
def observableTick: Observable[Float] =
Observable.create(OverflowStrategy.Unbounded) { sub =>
val c = SingleAssignCancelable()
val as = new MyBaseState {
override def init(): Unit = {}
override def update(tpf: Float) =
if (sub.onNext(tpf) == Ack.Stop)
c.cancel()
override def stop(): Unit = {}
override def onEnable() = {}
override def onDisable() = {}
}
sa.stateManager.attach(as)
c := Cancelable(() => sa.stateManager.detach(as))
c
}
} }
implicit final class AssetManagerExt(private val am: AssetManager) implicit final class AssetManagerExt(private val am: AssetManager)
@ -493,6 +479,7 @@ package object implicits {
* @see [[ActionEvent]] * @see [[ActionEvent]]
* @see [[enumObservableAction]] * @see [[enumObservableAction]]
*/ */
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def observableAction(mappingNames: String*): Observable[ActionEvent] = def observableAction(mappingNames: String*): Observable[ActionEvent] =
Observable.create(OverflowStrategy.DropOld(10)) { sub => Observable.create(OverflowStrategy.DropOld(10)) { sub =>
val c = SingleAssignCancelable() val c = SingleAssignCancelable()
@ -537,6 +524,7 @@ package object implicits {
* @see [[EnumActionEvent]] * @see [[EnumActionEvent]]
* @see [[enumAnalogObservable]] * @see [[enumAnalogObservable]]
*/ */
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def enumObservableAction[T <: EnumEntry]( def enumObservableAction[T <: EnumEntry](
mappingEnum: Enum[T] mappingEnum: Enum[T]
): Observable[EnumActionEvent[T]] = ): Observable[EnumActionEvent[T]] =
@ -563,6 +551,7 @@ package object implicits {
c c
} }
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def enumEntryObservableAction[T <: EnumEntry]( def enumEntryObservableAction[T <: EnumEntry](
mappingEnumEntry: T mappingEnumEntry: T
): Observable[EnumActionEvent[T]] = ): Observable[EnumActionEvent[T]] =
@ -590,6 +579,7 @@ package object implicits {
c c
} }
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def analogObservable(mappingNames: String*): Observable[AnalogEvent] = def analogObservable(mappingNames: String*): Observable[AnalogEvent] =
Observable.create(OverflowStrategy.DropOld(50)) { sub => Observable.create(OverflowStrategy.DropOld(50)) { sub =>
val c = SingleAssignCancelable() val c = SingleAssignCancelable()
@ -613,6 +603,7 @@ package object implicits {
c c
} }
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def enumAnalogObservable[T <: EnumEntry]( def enumAnalogObservable[T <: EnumEntry](
mappingEnum: Enum[T] mappingEnum: Enum[T]
): Observable[EnumAnalogEvent[T]] = ): Observable[EnumAnalogEvent[T]] =
@ -643,6 +634,7 @@ package object implicits {
implicit final class PhysicsSpaceExt(private val space: jmeb.PhysicsSpace) implicit final class PhysicsSpaceExt(private val space: jmeb.PhysicsSpace)
extends AnyVal { extends AnyVal {
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def collisionObservable(): Observable[CollisionEvent] = def collisionObservable(): Observable[CollisionEvent] =
Observable.create(OverflowStrategy.DropOld(50)) { sub => Observable.create(OverflowStrategy.DropOld(50)) { sub =>
val c = SingleAssignCancelable() val c = SingleAssignCancelable()
@ -670,6 +662,7 @@ package object implicits {
c c
} }
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def prePhysicsTickObservable(): Observable[PrePhysicsTickEvent] = def prePhysicsTickObservable(): Observable[PrePhysicsTickEvent] =
Observable.create(OverflowStrategy.DropOld(50)) { sub => Observable.create(OverflowStrategy.DropOld(50)) { sub =>
val c = SingleAssignCancelable() val c = SingleAssignCancelable()
@ -699,6 +692,7 @@ package object implicits {
c c
} }
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def physicsTickObservable(): Observable[PhysicsTickEvent] = def physicsTickObservable(): Observable[PhysicsTickEvent] =
Observable.create(OverflowStrategy.DropOld(50)) { sub => Observable.create(OverflowStrategy.DropOld(50)) { sub =>
val c = SingleAssignCancelable() val c = SingleAssignCancelable()
@ -905,4 +899,6 @@ package object implicits {
) extends AnyVal { ) extends AnyVal {
def toIO = coeval.to[Task].hideErrors.rethrow def toIO = coeval.to[Task].hideErrors.rethrow
} }
implicit val showForOsPath = Show.fromToString[os.Path]
} }

View File

@ -16,7 +16,7 @@ import scalafx.application.JFXApp.PrimaryStage
import scalafx.scene.control.Button import scalafx.scene.control.Button
import scalafx.stage.StageStyle import scalafx.stage.StageStyle
import wow.doge.mygame.executors.Schedulers.FxScheduler import wow.doge.mygame.executors.Schedulers.FxScheduler
import wow.doge.mygame.implicits.JavaFXMonixObservables._ import wow.doge.mygame.implicits._
import wow.doge.mygame.utils.IOUtils._ import wow.doge.mygame.utils.IOUtils._
object Launcher { object Launcher {
sealed trait LauncherResult sealed trait LauncherResult
@ -43,8 +43,7 @@ class Launcher private (props: Launcher.Props) {
} }
private lazy val launchAction = private lazy val launchAction =
launchButton launchButton.observableAction
.observableAction()
.doOnNext(_ => toTask(props.signal.complete(LauncherResult.LaunchGame))) .doOnNext(_ => toTask(props.signal.complete(LauncherResult.LaunchGame)))
private lazy val exitButton = new Button { private lazy val exitButton = new Button {
@ -52,8 +51,7 @@ class Launcher private (props: Launcher.Props) {
} }
private lazy val exitAction = private lazy val exitAction =
exitButton exitButton.observableAction
.observableAction()
.doOnNext(_ => toTask(props.signal.complete(LauncherResult.Exit))) .doOnNext(_ => toTask(props.signal.complete(LauncherResult.Exit)))
private lazy val _scene = private lazy val _scene =

View File

@ -6,7 +6,7 @@ import cats.syntax.eq._
import math.{abs, pow, sqrt} import math.{abs, pow, sqrt}
case class ImVector3f(x: Float, y: Float, z: Float) final case class ImVector3f(x: Float, y: Float, z: Float)
object ImVector3f { object ImVector3f {
//format: off //format: off
val Zero = ImVector3f(0, 0, 0) val Zero = ImVector3f(0, 0, 0)

View File

@ -11,6 +11,7 @@ import akka.actor.typed.scaladsl.AskPattern._
import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.Behaviors
import akka.event.EventStream import akka.event.EventStream
import akka.util.Timeout import akka.util.Timeout
import cats.syntax.show._
import monix.bio.UIO import monix.bio.UIO
import monix.execution.Ack import monix.execution.Ack
import monix.execution.Cancelable import monix.execution.Cancelable
@ -58,6 +59,7 @@ object EventBus {
new EventBus().eventStreamBehavior(eventStream) new EventBus().eventStreamBehavior(eventStream)
} }
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def observable[A, B <: A](eventBus: ActorRef[EventBus.Command[A]])(implicit def observable[A, B <: A](eventBus: ActorRef[EventBus.Command[A]])(implicit
timeout: Timeout, timeout: Timeout,
scheduler: Scheduler, scheduler: Scheduler,
@ -70,7 +72,7 @@ object EventBus {
val c = SingleAssignCancelable() val c = SingleAssignCancelable()
val behavior = Behaviors val behavior = Behaviors
.receive[B] { (ctx, msg) => .receive[B] { (ctx, msg) =>
ctx.log.traceP(s"Emitted $msg") ctx.log.traceP(s"Emitted ${msg.toString}")
if (sub.onNext(msg) == Ack.Stop) { if (sub.onNext(msg) == Ack.Stop) {
c.cancel() c.cancel()
Behaviors.stopped Behaviors.stopped
@ -86,7 +88,7 @@ object EventBus {
.spawnActorL( .spawnActorL(
behavior, behavior,
actorName = actorName =
Some(s"eventBusObservable-${ct.toString.split("""\.""").last}") Some(show"eventBusObservable-${ct.toString.split("""\.""").last}")
) )
.mapError(err => new Throwable(err.toString)) .mapError(err => new Throwable(err.toString))
.tapError { .tapError {

View File

@ -1,5 +1,6 @@
package wow.doge.mygame.subsystems.events package wow.doge.mygame.subsystems.events
import cats.Show
import wow.doge.mygame.game.entities.CharacterStats import wow.doge.mygame.game.entities.CharacterStats
sealed trait Event sealed trait Event
@ -27,9 +28,11 @@ object EntityMovementEvent {
sealed trait StatsEvent extends Event sealed trait StatsEvent extends Event
object StatsEvent { object StatsEvent {
case class DamageEvent( final case class DamageEvent(
hitBy: String, hitBy: String,
victimName: String, victimName: String,
amount: CharacterStats.DamageHealth amount: CharacterStats.DamageHealth
) extends StatsEvent ) extends StatsEvent
implicit val show = Show.fromToString[StatsEvent]
} }

View File

@ -1 +0,0 @@
package wow.doge.mygame.subsystems.events

View File

@ -1,5 +1,7 @@
package wow.doge.mygame.subsystems.events package wow.doge.mygame.subsystems.events
import cats.Show
sealed trait PlayerEvent sealed trait PlayerEvent
sealed trait PlayerMovementEvent extends PlayerEvent sealed trait PlayerMovementEvent extends PlayerEvent
@ -14,6 +16,7 @@ object PlayerMovementEvent {
case object PlayerJumped extends PlayerMovementEvent case object PlayerJumped extends PlayerMovementEvent
// case object PlayerTurnedRight extends PlayerMovementEvent // case object PlayerTurnedRight extends PlayerMovementEvent
// case object PlayerTurnedLeft extends PlayerMovementEvent // case object PlayerTurnedLeft extends PlayerMovementEvent
implicit val show = Show.fromToString[PlayerMovementEvent]
} }
sealed trait PlayerCameraEvent extends PlayerEvent sealed trait PlayerCameraEvent extends PlayerEvent

View File

@ -32,7 +32,7 @@ object Plugin {
} }
object ModdingSystem { object ModdingSystem {
sealed trait Error sealed trait Error extends Product with Serializable
final case class CouldNotDecode(cause: String) extends Error final case class CouldNotDecode(cause: String) extends Error
final case class ParseFailure(cause: io.circe.ParsingFailure) extends Error final case class ParseFailure(cause: io.circe.ParsingFailure) extends Error
final case class DecodingFailure(cause: io.circe.DecodingFailure) final case class DecodingFailure(cause: io.circe.DecodingFailure)
@ -61,7 +61,7 @@ object ModdingSystem {
def findPluginFiles(dir: os.Path): View[os.Path] = def findPluginFiles(dir: os.Path): View[os.Path] =
os.list(dir) os.list(dir)
.view .view
.filter(f => f.ext == "json" && f.baseName.endsWith("plugin")) .filter(f => f.ext === "json" && f.baseName.endsWith("plugin"))
def findAndReadPluginFiles( def findAndReadPluginFiles(
dir: os.Path, dir: os.Path,
@ -215,7 +215,7 @@ object ModdingSystem {
pprint.log(show"Merged = ${res.pluginJson}") pprint.log(show"Merged = ${res.pluginJson}")
} }
case class Result( final case class Result(
readFailures: List[(Plugin, Error)], readFailures: List[(Plugin, Error)],
readSuccesses: List[(Plugin, String)], readSuccesses: List[(Plugin, String)],
parseFailures: List[(Plugin, ParsingFailure)], parseFailures: List[(Plugin, ParsingFailure)],

View File

@ -10,28 +10,31 @@ import ammonite.main.Defaults
import ammonite.runtime.Storage.Folder import ammonite.runtime.Storage.Folder
import ammonite.util.Res import ammonite.util.Res
import ammonite.util.Res.Failure import ammonite.util.Res.Failure
import cats.Show
import cats.effect.Resource import cats.effect.Resource
import cats.effect.concurrent.Deferred import cats.effect.concurrent.Deferred
import cats.syntax.either._ import cats.syntax.either._
import cats.syntax.flatMap._ import cats.syntax.flatMap._
import cats.syntax.show._
import com.softwaremill.macwire._ import com.softwaremill.macwire._
import com.softwaremill.tagging._ import com.softwaremill.tagging._
import groovy.util.GroovyScriptEngine import groovy.util.GroovyScriptEngine
import groovy.util.ResourceException
import io.odin.Logger import io.odin.Logger
import monix.bio.IO import monix.bio.IO
import monix.bio.Task import monix.bio.Task
import monix.bio.UIO import monix.bio.UIO
import monix.catnap.ConcurrentQueue import monix.catnap.ConcurrentQueue
import monix.reactive.Observable
import wow.doge.mygame.implicits._
import monix.{eval => me}
import groovy.util.ResourceException
import monix.catnap.MVar import monix.catnap.MVar
import monix.reactive.Observable
import monix.{eval => me}
import wow.doge.mygame.implicits._
trait Requestable[A] { trait Requestable[A] {
protected def queue: ConcurrentQueue[Task, A] protected def queue: ConcurrentQueue[Task, A]
@SuppressWarnings(Array("org.wartremover.warts.OptionPartial"))
def request[T]( def request[T](
compileRequest: Deferred[Task, T] => A compileRequest: Deferred[Task, T] => A
)(implicit timeout: FiniteDuration) = )(implicit timeout: FiniteDuration) =
@ -52,6 +55,7 @@ class ScriptCompiler private (
// def tell(item: Command) = queue.offer(item) // def tell(item: Command) = queue.offer(item)
} }
@SuppressWarnings(Array("org.wartremover.warts.Any"))
object ScriptCompiler { object ScriptCompiler {
sealed trait State sealed trait State
@ -79,15 +83,14 @@ object ScriptCompiler {
final case class SomeError(reason: String) extends Error final case class SomeError(reason: String) extends Error
sealed trait Command sealed trait Command
final case class Get( final case class GetScript(
path: os.Path, path: os.Path,
result: Deferred[Task, ScriptResult], result: Deferred[Task, ScriptResult],
force: Boolean force: Boolean
) extends Command ) extends Command
final case class GetData(result: Deferred[Task, Data]) // final case class GetData(result: Deferred[Task, Data])
final case class ObservableData(result: Deferred[Task, Observable[Data]]) final case class ObservableData(result: Deferred[Task, Observable[Data]])
extends Command extends Command
// extends Command
// final case class CompileAll(paths: Seq[os.Path]) extends Command // final case class CompileAll(paths: Seq[os.Path]) extends Command
type ScriptsMap = Map[os.Path, Any] type ScriptsMap = Map[os.Path, Any]
@ -117,7 +120,7 @@ object ScriptCompiler {
val defaultGroovyRunner: GroovyScriptEngine = val defaultGroovyRunner: GroovyScriptEngine =
new GroovyScriptEngine(os.pwd.toString) new GroovyScriptEngine(os.pwd.toString)
case class Data(scriptsMap: ScriptsMap) final case class Data(scriptsMap: ScriptsMap)
class SourceMaker( class SourceMaker(
queue: ConcurrentQueue[Task, Command], queue: ConcurrentQueue[Task, Command],
@ -137,14 +140,12 @@ object ScriptCompiler {
case Idle => IO.pure(Idle -> data) case Idle => IO.pure(Idle -> data)
case Active => case Active =>
command match { command match {
case Get(path, result, force) => case GetScript(path, result, force) =>
def getAndUpdate = def getAndUpdate =
worker worker
.request( .request(
ScriptCompilerWorker.CompileAny(path, _) ScriptCompilerWorker.CompileAny(path, _)
)( )(20.seconds)
20.seconds
)
.flatTap(result.complete) .flatTap(result.complete)
.hideErrors .hideErrors
.rethrow .rethrow
@ -238,7 +239,7 @@ object ScriptCompiler {
Task( Task(
Observable Observable
.repeatEvalF(queue.poll) .repeatEvalF(queue.poll)
.doOnNextF(el => logger.debug(s"Got $el")) .doOnNextF(el => logger.debug(show"Got $el"))
.mapParallelUnorderedF(4) { .mapParallelUnorderedF(4) {
case ScriptCompilerWorker.CompileAny(path, result) => case ScriptCompilerWorker.CompileAny(path, result) =>
for { for {
@ -253,7 +254,6 @@ object ScriptCompiler {
) )
) )
} }
// override private val
final class ScriptCompilerWorker( final class ScriptCompilerWorker(
logger: Logger[Task], logger: Logger[Task],
_queue: ConcurrentQueue[Task, ScriptCompilerWorker.CompileRequest] _queue: ConcurrentQueue[Task, ScriptCompilerWorker.CompileRequest]
@ -266,6 +266,10 @@ object ScriptCompiler {
object ScriptCompilerWorker { object ScriptCompilerWorker {
sealed trait CompileRequest sealed trait CompileRequest
object CompileRequest {
implicit val show: Show[CompileRequest] = Show.fromToString
}
final case class CompileAny( final case class CompileAny(
path: os.Path, path: os.Path,
result: Deferred[Task, ScriptResult] result: Deferred[Task, ScriptResult]
@ -287,13 +291,13 @@ object ScriptCompiler {
// ) // )
} yield worker -> fib } yield worker -> fib
Resource Resource
.make(acquire) { case worker -> fib => fib.cancel } .make(acquire.hideErrors) { case worker -> fib => fib.cancel }
.map(_._1) .map(_._1)
} }
} }
def apply(logger: Logger[Task]) = { def apply(logger: Logger[Task]): Resource[UIO, ScriptCompiler] = {
def acquire(worker: ScriptCompilerWorker) = def acquire(worker: ScriptCompilerWorker) =
for { for {
queue <- ConcurrentQueue.bounded[Task, Command](10) queue <- ConcurrentQueue.bounded[Task, Command](10)
@ -302,7 +306,9 @@ object ScriptCompiler {
ScriptCompilerWorker(logger) ScriptCompilerWorker(logger)
.flatMap(worker => .flatMap(worker =>
Resource.make(acquire(worker)) { case (_, fib) => fib.cancel } Resource.make(acquire(worker).hideErrors) {
case (_, fib) => fib.cancel
}
) )
.map(_._1) .map(_._1)
} }

View File

@ -17,7 +17,9 @@ import com.softwaremill.tagging._
import com.typesafe.scalalogging.Logger import com.typesafe.scalalogging.Logger
import groovy.util.GroovyScriptEngine import groovy.util.GroovyScriptEngine
import org.slf4j.event.Level import org.slf4j.event.Level
import wow.doge.mygame.implicits._
@SuppressWarnings(Array("org.wartremover.warts.Any"))
object ScriptActor { object ScriptActor {
/** /**
@ -126,6 +128,7 @@ object ScriptActor {
} }
@SuppressWarnings(Array("org.wartremover.warts.Any"))
class ScriptActor( class ScriptActor(
val scalaRunner: ammonite.Main, val scalaRunner: ammonite.Main,
val kotlinRunner: ScriptActor.KotlinScriptEngine, val kotlinRunner: ScriptActor.KotlinScriptEngine,
@ -137,14 +140,14 @@ class ScriptActor(
def receiveMessage: Behavior[Command] = def receiveMessage: Behavior[Command] =
Behaviors.receiveMessage { Behaviors.receiveMessage {
case CompileAny(path, requester) => case CompileAny(path, requester) =>
context.log.debug(s"Received $path") context.log.debug(show"Received $path")
val res = getScript(path) val res = getScript(path)
context.log.debug(s"result = $res") context.log.debug(s"result = ${res.toString}")
requester ! res requester ! res
Behaviors.same Behaviors.same
case CompileAll(paths, requester) => case CompileAll(paths, requester) =>
context.log.debug(s"Received $paths") context.log.debug(show"Received $paths")
requester ! compileAll(paths) requester ! compileAll(paths)
Behaviors.same Behaviors.same
} }

View File

@ -13,6 +13,7 @@ import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.scaladsl.PoolRouter import akka.actor.typed.scaladsl.PoolRouter
import akka.actor.typed.scaladsl.Routers import akka.actor.typed.scaladsl.Routers
import akka.util.Timeout import akka.util.Timeout
import cats.syntax.show._
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.implicits._
@ -25,7 +26,7 @@ object ScriptCachingActor {
type ScriptsMap = Map[os.Path, ScriptObject] type ScriptsMap = Map[os.Path, ScriptObject]
type ScriptResult = Either[ScriptActor.Error, ScriptObject] type ScriptResult = Either[ScriptActor.Error, ScriptObject]
sealed trait Command sealed trait Command extends Product with Serializable
/** /**
* @param scriptPath path of the script to compile * @param scriptPath path of the script to compile
@ -187,7 +188,7 @@ class ScriptCachingActor(
Behaviors.same Behaviors.same
case Put(scriptPath, script) => case Put(scriptPath, script) =>
ctx.log.debugP(s"Putting $script at path $scriptPath") ctx.log.debugP(show"Putting ${script.toString} at path $scriptPath")
val newState = val newState =
state.modify(_.scriptsMap).using(_ + (scriptPath -> script)) state.modify(_.scriptsMap).using(_ + (scriptPath -> script))
ctx.log.traceP(newState.toString()) ctx.log.traceP(newState.toString())

View File

@ -4,7 +4,11 @@ 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 cats.syntax.eq._
import io.odin.Logger
import monix.bio.Task import monix.bio.Task
import monix.bio.UIO
import wow.doge.mygame.scriptsystem.ScriptCachingActor import wow.doge.mygame.scriptsystem.ScriptCachingActor
import wow.doge.mygame.utils.AkkaUtils import wow.doge.mygame.utils.AkkaUtils
@ -19,6 +23,7 @@ object ScriptInitMode {
} }
class ScriptSystemResource( class ScriptSystemResource(
path: os.Path, path: os.Path,
logger: Logger[Task],
mode: ScriptInitMode = ScriptInitMode.Lazy mode: ScriptInitMode = ScriptInitMode.Lazy
)(implicit )(implicit
spawnProtocol: ActorRef[SpawnProtocol.Command], spawnProtocol: ActorRef[SpawnProtocol.Command],
@ -36,13 +41,17 @@ class ScriptSystemResource(
) )
} yield scriptCacheActor } yield scriptCacheActor
val init2: Resource[UIO, ScriptCompiler] = for {
sc <- ScriptCompiler(logger)
} yield sc
def findScriptFiles(wd: os.Path) = def findScriptFiles(wd: os.Path) =
os.walk os.walk
.stream(wd) .stream(wd)
.filter(p => .filter(p =>
os.isFile(p) && os.isFile(p) &&
(p.ext == "sc" || (p.baseName + "." + p.ext) (p.ext === "sc" || (p.baseName + "." + p.ext)
.contains(".main.kts") || p.ext == "groovy") .contains(".main.kts") || p.ext === "groovy")
) )
.toList .toList

View File

@ -10,6 +10,6 @@ import wow.doge.mygame.utils.wrappers.jme.AppNode2
package object types { package object types {
type RootNode = AppNode2 @@ GameAppTags.RootNode type RootNode = AppNode2 @@ GameAppTags.RootNode
type GuiNode = AppNode2 @@ GameAppTags.GuiNode type GuiNode = AppNode2 @@ GameAppTags.GuiNode
@newtype case class JmeScheduler(value: SchedulerService) @newtype final case class JmeScheduler(value: SchedulerService)
@newtype case class AkkaScheduler(value: Scheduler) @newtype final case class AkkaScheduler(value: Scheduler)
} }

View File

@ -54,7 +54,7 @@ object GenericConsoleStream {
/** /**
* for future use * for future use
*/ */
case class Config(exclusive: Boolean = false) final case class Config(exclusive: Boolean = false)
object Config { object Config {
val default = Config() val default = Config()
} }

View File

@ -8,6 +8,7 @@ import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.scaladsl.TimerScheduler import akka.actor.typed.scaladsl.TimerScheduler
import cats.syntax.show._
import wow.doge.mygame.implicits._ import wow.doge.mygame.implicits._
object GenericTimerActor { object GenericTimerActor {
@ -15,9 +16,9 @@ object GenericTimerActor {
case object Start extends Command case object Start extends Command
case object Stop extends Command case object Stop extends Command
private case object Tick extends Command private case object Tick extends Command
case class TimerKey(seed: Long) final case class TimerKey(seed: Long)
case class Props[T]( final case class Props[T](
target: ActorRef[T], target: ActorRef[T],
messageToSend: T, messageToSend: T,
timeInterval: FiniteDuration timeInterval: FiniteDuration
@ -55,7 +56,7 @@ class GenericTimerActor[T](
val active: Behavior[Command] = val active: Behavior[Command] =
Behaviors.receiveMessage { Behaviors.receiveMessage {
case Start => case Start =>
ctx.log.warnP(s"Timer-${timerKey.seed}: Timer already started") ctx.log.warnP(show"Timer-${timerKey.seed}: Timer already started")
Behaviors.same Behaviors.same
case Tick => case Tick =>
props.target ! props.messageToSend props.target ! props.messageToSend

View File

@ -1,33 +1,65 @@
package wow.doge.mygame.utils package wow.doge.mygame.utils
import monix.reactive.Observable import cats.kernel.Eq
import monix.reactive.OverflowStrategy import cats.syntax.show._
import com.typesafe.scalalogging.Logger
import monix.bio.Task
import monix.execution.Ack
import monix.execution.Cancelable import monix.execution.Cancelable
import monix.execution.cancelables.SingleAssignCancelable import monix.execution.cancelables.SingleAssignCancelable
import monix.execution.Ack import monix.reactive.Observable
import monix.reactive.OverflowStrategy
object MonixDirectoryWatcher { object MonixDirectoryWatcher {
import better.files._ import better.files._
import io.methvin.better.files._ import io.methvin.better.files._
private val logger = Logger[MonixDirectoryWatcher.type]
sealed trait WatchEvent extends Product with Serializable
final case class CreateEvent(file: File, count: Int) extends WatchEvent
final case class ModifyEvent(file: File, count: Int) extends WatchEvent
final case class DeleteEvent(file: File, count: Int) extends WatchEvent
object WatchEvent {
implicit val eq = Eq.fromUniversalEquals[WatchEvent]
}
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def apply(path: os.Path) = def apply(path: os.Path) =
Observable.create[String](OverflowStrategy.DropNew(50)) { sub => Task.deferAction(implicit s =>
Task(
Observable
.create[WatchEvent](OverflowStrategy.DropNew(50)) { sub =>
import sub.scheduler import sub.scheduler
val c = SingleAssignCancelable() val c = SingleAssignCancelable()
val myDir = File(path.toString) val watcher =
val watcher = new RecursiveFileMonitor(myDir) { new RecursiveFileMonitor(
File(path.toString),
logger = logger.underlying
) {
override def onCreate(file: File, count: Int) = override def onCreate(file: File, count: Int) =
println(s"$file got created") // println(show"$file got created")
override def onModify(file: File, count: Int) = if (sub.onNext(CreateEvent(file, count)) == Ack.Stop)
// println(s"$file got modified $count times") c.cancel()
if (sub.onNext(file.name) == Ack.Stop) c.cancel() override def onModify(file: File, count: Int) = {
pprint.log(show"${file.toString} got modified $count times")
if (sub.onNext(ModifyEvent(file, count)) == Ack.Stop)
c.cancel()
}
override def onDelete(file: File, count: Int) = override def onDelete(file: File, count: Int) =
println(s"$file got deleted") // println(show"$file got deleted")
if (sub.onNext(DeleteEvent(file, count)) == Ack.Stop)
c.cancel()
} }
watcher.start()(scheduler) watcher.start()(scheduler)
c := Cancelable(() => watcher.stop()) c := Cancelable(() => watcher.stop())
c c
} }
.publish
.refCount
)
)
} }

View File

@ -15,7 +15,7 @@ object ReaderDemo {
val t2 = r.run("s").rethrow val t2 = r.run("s").rethrow
// Kleisli[IO, String, Unit](s => IO.unit) // Kleisli[IO, String, Unit](s => IO.unit)
case class Environment(str: String, num: Int) final case class Environment(str: String, num: Int)
def fun1: Reader[String, UIO[Unit]] = Reader(str => UIO(println(str))) def fun1: Reader[String, UIO[Unit]] = Reader(str => UIO(println(str)))
def fun2: Reader[Int, UIO[Unit]] = Reader(num => UIO(println(num))) def fun2: Reader[Int, UIO[Unit]] = Reader(num => UIO(println(num)))

View File

@ -1,6 +1,6 @@
package wow.doge.mygame.utils package wow.doge.mygame.utils
case class Display( final case class Display(
width: Int, width: Int,
height: Int, height: Int,
title: String, title: String,
@ -18,4 +18,4 @@ object Display {
frameRate = -1 frameRate = -1
) )
} }
case class GlobalSettings(display: Display = Display.default) final case class GlobalSettings(display: Display = Display.default)

View File

@ -6,16 +6,15 @@ import monix.execution.atomic.AtomicAny
* Useless * Useless
*/ */
sealed abstract class Tree[+T] sealed abstract class Tree[+T]
case class Node[T](data: T, children: AtomicAny[LazyList[Tree[T]]]) final case class Node[T](data: T, children: AtomicAny[LazyList[Tree[T]]])
extends Tree[T] { extends Tree[T] {
def add(data: T) = { def add(data: T) =
children.transform(children => children.transform(children =>
Node(data, AtomicAny(LazyList[Tree[T]]())) #:: children Node(data, AtomicAny(LazyList[Tree[T]]())) #:: children
) )
}
} }
// case object Leaf extends Tree[Nothing] // case object Leaf extends Tree[Nothing]
case class Data(data: Int) final case class Data(data: Int)
class TreeManager[T] { class TreeManager[T] {
// val root: AtomicAny[Tree[T]] = AtomicAny(Leaf) // val root: AtomicAny[Tree[T]] = AtomicAny(Leaf)

View File

@ -0,0 +1,67 @@
package wow.doge.mygame.util.controls
import monix.bio.Task
import monix.execution.Cancelable
import monix.execution.Scheduler
import monix.execution.cancelables.CompositeCancelable
import monix.reactive.Observable
import monix.reactive.Observer
import monix.{eval => me}
final class ActionObservableExecutor[T](private val delegate: Observable[T]) {
//format: off
def -->(sub: Observer[T])(implicit s: Scheduler, c: CompositeCancelable): Unit =
//format: on
c += delegate
.doOnNext(el => me.Task.deferFuture(sub.onNext(el)).void)
.subscribe()
//format: off
def -->(f: T => Task[Unit])(implicit s: Scheduler, c: CompositeCancelable): Unit =
//format: on
c += delegate.doOnNextF(f).subscribe()
//format: off
def split(lst: (ActionObservableBuilder[T] => Cancelable)*)(implicit s: Scheduler, c: CompositeCancelable): Unit =
//format: on
c += delegate
.publishSelector(conn =>
Observable(
lst.map(f =>
Observable.unit.doOnNext(_ =>
me.Task(c += f(new ActionObservableBuilder[T](conn))).void
)
): _*
).merge
)
.subscribe()
}
//format: off
final class ActionObservableBuilder[A](private val observableAction: Observable[A]) {
//format: on
def useEval[T](v: me.Task[T]) =
new ActionObservableExecutor[T](observableAction.mapEval(_ => v))
def useEval[T](cb: A => me.Task[T]) =
new ActionObservableExecutor[T](observableAction.mapEval(cb))
def use = new ActionObservableExecutor(observableAction)
def useIterableEval[T](cb: A => collection.immutable.Iterable[T]) =
new ActionObservableExecutor[T](
observableAction.flatMap(a =>
Observable.suspend(Observable.fromIterable(cb(a)))
)
)
def doOnNext(cb: A => me.Task[Unit]): ActionObservableBuilder[A] =
new ActionObservableBuilder(observableAction.doOnNext(cb))
def mapEval[B](cb: A => me.Task[B]) =
new ActionObservableBuilder(observableAction.mapEval(cb))
def underlying = observableAction
}

View File

@ -0,0 +1,47 @@
package wow.doge.mygame.util.controls
import javafx.{scene => jfxs}
import org.kordamp.ikonli.{javafx => ikonlifx}
import scalafx.scene.paint.Paint
import scalafx.scene.text.Text
@SuppressWarnings(
Array("org.wartremover.warts.Null", "org.wartremover.warts.Equals")
)
object FontIcon {
implicit def sfxText2jfx(v: FontIcon): jfxs.text.Text =
if (v != null) v.delegate else null
}
// extends Shape(delegate)
// with PositionDelegate[ikonlifx.FontIcon]
// with SFXDelegate[ikonlifx.FontIcon]
class FontIcon(override val delegate: ikonlifx.FontIcon = new ikonlifx.FontIcon)
extends Text(delegate) {
// def iconCode_=(v: Ikon) = delegate.setIconCode(v)
def iconColor = delegate.getIconColor()
def iconColor_=(color: Paint) = delegate.setIconColor(color)
def iconSize = delegate.getIconSize()
def iconSize_=(size: Int) = delegate.setIconSize(size)
def iconLiteral = delegate.getIconLiteral()
def iconLiteral_=(literal: IconLiteral) =
delegate.setIconLiteral(literal.value)
def iconLiteral_=(literal: String) = delegate.setIconLiteral(literal)
}
sealed abstract class IconLiteral(val value: String)
object IconLiteral {
// fab-accusoft
case object Gmi10k extends IconLiteral("gmi-10k")
}

View File

@ -0,0 +1,42 @@
package wow.doge.mygame.util.controls
import com.jfoenix.{controls => jfoenixc}
import javafx.{scene => jfxs}
import scalafx.Includes._
import scalafx.beans.property.ObjectProperty
import scalafx.scene.Node
import scalafx.scene.control.Button
import wow.doge.mygame.implicits._
import jfxs.{paint => jfxsp}
@SuppressWarnings(
Array("org.wartremover.warts.Null", "org.wartremover.warts.Equals")
)
object JFXButton {
implicit def sfxButton2jfx(v: JFXButton): jfoenixc.JFXButton =
if (v != null) v.delegate else null
}
class JFXButton(
override val delegate: jfoenixc.JFXButton = new jfoenixc.JFXButton
) extends Button(delegate) {
/**
* Creates a button with the specified text as its label.
*/
def this(text: String) = this(new jfoenixc.JFXButton(text))
/**
* Creates a button with the specified text and icon for its label.
*/
def this(text: String, graphic: Node) =
this(new jfoenixc.JFXButton(text, graphic))
def ripplerFill: ObjectProperty[jfxsp.Paint] = delegate.ripplerFillProperty
def ripplerFill_=(b: jfxsp.Paint): Unit = ripplerFill() = b
def obsAction = new ActionObservableBuilder(this.observableAction)
}

View File

@ -0,0 +1,22 @@
package wow.doge.mygame.util.controls
import com.jfoenix.{controls => jfoenixc}
import scalafx.scene.layout.Region
import scalafx.scene.layout.StackPane
class JFXDialog(
override val delegate: jfoenixc.JFXDialog = new jfoenixc.JFXDialog
) extends StackPane(delegate) {
def show() = delegate.show()
def show(sp: StackPane) = delegate.show(sp)
def content = delegate.getContent()
def content_=(r: Region) = delegate.setContent(r)
def overlayClose = delegate.overlayCloseProperty()
def overlayClose_=(v: Boolean) = delegate.setOverlayClose(v)
def cacheContainer = delegate.cacheContainerProperty()
def cacheContainer_=(v: Boolean) = delegate.setCacheContainer(v)
}
object JFXDialog {
implicit def sfxJfXDialog2Jfx(v: JFXDialog): jfoenixc.JFXDialog = v.delegate
}

View File

@ -0,0 +1,57 @@
package wow.doge.mygame.util.controls
import com.jfoenix.{controls => jfoenixc}
import javafx.scene.{control => jfxsc}
import scalafx.Includes._
import scalafx.beans.property.ReadOnlyObjectProperty
import scalafx.delegate.SFXDelegate
import scalafx.scene.control.IndexedCell
import scalafx.scene.control.ListCell
import scalafx.scene.control.ListView
@SuppressWarnings(
Array("org.wartremover.warts.Null", "org.wartremover.warts.Equals")
)
object JFXListCell {
implicit def sfxListCell2jfx[T](
l: JFXListCell[T]
): ListCell[T] =
if (l != null) l.delegate else null
}
class JFXListCell[T](
override val delegate: jfoenixc.JFXListCell[T] =
new jfoenixc.JFXListCell[T] {
override def updateItem(
item: T,
empty: Boolean
): Unit = {
super.updateItem(item, empty)
// setText(null)
setText(getText())
setGraphic(getGraphic())
// setGraphic(null)
// remove empty (Trailing cells)
// setMouseTransparent(true)
// setStyle("-fx-background-color:TRANSPARENT;")
}
override def makeChildrenTransparent(): Unit = {}
}
) extends IndexedCell(delegate)
with SFXDelegate[jfoenixc.JFXListCell[T]] {
/**
* The ListView associated with this Cell.
*/
def listView: ReadOnlyObjectProperty[jfxsc.ListView[T]] =
delegate.listViewProperty
/**
* Updates the ListView associated with this Cell.
*/
def updateListView(listView: ListView[T]): Unit =
delegate.updateListView(listView)
// delegate.cell
}

View File

@ -0,0 +1,40 @@
package wow.doge.mygame.util.controls
import com.jfoenix.{controls => jfoenixc}
import monix.execution.Scheduler
import monix.reactive.Observable
import scalafx.Includes._
import scalafx.collections.ObservableBuffer
import scalafx.scene.control.ListView
@SuppressWarnings(
Array("org.wartremover.warts.Null", "org.wartremover.warts.Equals")
)
object JFXListView {
implicit def sfxListView2jfx[T](l: JFXListView[T]): jfoenixc.JFXListView[T] =
if (l != null) l.delegate else null
}
// extends Control(delegate)
// with SFXDelegate[jfoenixc.JFXListView[T]]
class JFXListView[T](
override val delegate: jfoenixc.JFXListView[T] = new jfoenixc.JFXListView[T]
) extends ListView[T] {
// def items_=(
// v: Observable[ObservableBuffer[T]]
// )(implicit s: Scheduler): Unit = {
// v.foreach { items() = _ }
// }
def items_=(v: Observable[Seq[T]])(implicit s: Scheduler): Unit =
v.map(ObservableBuffer.from).foreach(items() = _)
def depth = delegate.depthProperty()
def depth_=(depth: Int) = delegate.setDepth(depth)
def expanded = delegate.expandedProperty()
def expanded_=(v: Boolean) = expanded() = v
}

View File

@ -0,0 +1,11 @@
package wow.doge.mygame.utils.controls
// import com.jfoenix.controls.JFXProgressBar
import com.jfoenix.{controls => jfoenixc}
import scalafx.scene.control.ProgressBar
class JFXProgressBar(
override val delegate: jfoenixc.JFXProgressBar = new jfoenixc.JFXProgressBar
) extends ProgressBar(delegate) {
def secondaryProgress = delegate.getSecondaryProgress()
def secondaryProgress_=(v: Double) = delegate.setSecondaryProgress(v)
}

View File

@ -0,0 +1,37 @@
package wow.doge.mygame.util.controls
import com.jfoenix.{controls => jfoenixc}
import scalafx.scene.Node
import scalafx.scene.layout.StackPane
import scalafx.scene.paint.Paint
class JFXRippler(
override val delegate: jfoenixc.JFXRippler = new jfoenixc.JFXRippler
) extends StackPane(delegate) {
import JFXRippler._
def control = delegate.getControl()
def control_=(v: Node) = delegate.setControl(v)
def enabled_=(v: Boolean) = delegate.setEnabled(v)
def ripplerPos = delegate.getPosition()
def ripplerPos_=(pos: RipplerPos) = delegate.setPosition(pos)
def ripplerDisabled = delegate.ripplerDisabledProperty()
def ripplerDisabled_=(v: Boolean) = delegate.setRipplerDisabled(v)
def ripplerFill = delegate.ripplerFillProperty()
def ripplerFill_=(v: Paint) = delegate.setRipplerFill(v)
def ripplerRecenter = delegate.ripplerRecenterProperty()
def ripplerRecenter_=(v: Boolean) = delegate.setRipplerRecenter(v)
def ripplerRadius = delegate.ripplerRadiusProperty()
def ripplerRadius_=(v: Int) = delegate.setRipplerRadius(v)
}
object JFXRippler {
abstract class RipplerPos(val delegate: jfoenixc.JFXRippler.RipplerPos)
case object Front extends RipplerPos(jfoenixc.JFXRippler.RipplerPos.FRONT)
case object Back extends RipplerPos(jfoenixc.JFXRippler.RipplerPos.BACK)
object RipplerPos {
implicit def sfxRipplerPos2jfxRipplerPos(
v: RipplerPos
): jfoenixc.JFXRippler.RipplerPos = v.delegate
}
implicit def sfxRippler2jfxRippler(v: JFXRippler): jfoenixc.JFXRippler =
v.delegate
}

View File

@ -0,0 +1,32 @@
package wow.doge.mygame.util.controls
import com.jfoenix.{controls => jfoenixc}
import scalafx.scene.control.ProgressIndicator
@SuppressWarnings(
Array("org.wartremover.warts.Null", "org.wartremover.warts.Equals")
)
object JFXSpinner {
implicit def sfxSpinner2jfx(
v: JFXSpinner
): jfoenixc.JFXSpinner = if (v != null) v.delegate else null
}
// extends Control(delegate)
// with SFXDelegate[jfoenixc.JFXSpinner]
/**
* Wraps [[JFoenix JFXSpinner]]
*/
class JFXSpinner(
override val delegate: jfoenixc.JFXSpinner = new jfoenixc.JFXSpinner
) extends ProgressIndicator(delegate) {
def radius = delegate.getRadius()
def radius_=(radius: Double) = delegate.setRadius(radius)
def startingAngle = delegate.startingAngleProperty()
def startingAngle_=(angle: Double) = delegate.setStartingAngle(angle)
}

View File

@ -0,0 +1,43 @@
package wow.doge.mygame.util.controls
import com.jfoenix.{controls => jfoenixc}
import scalafx.Includes._
import scalafx.beans.property.BooleanProperty
import scalafx.scene.control.TextArea
import scalafx.scene.paint.Paint
@SuppressWarnings(
Array("org.wartremover.warts.Null", "org.wartremover.warts.Equals")
)
object JFXTextArea {
implicit def sfxTextArea2jfx(v: JFXTextArea): jfoenixc.JFXTextArea =
if (v != null) v.delegate else null
}
// extends TextInputControl(delegate)
// with SFXDelegate[jfoenixc.JFXTextArea]
class JFXTextArea(
override val delegate: jfoenixc.JFXTextArea = new jfoenixc.JFXTextArea()
) extends TextArea(delegate) {
/**
* Creates a TextArea with initial text content.
*
* @param text - A string for text content.
*/
def this(text: String) = this(new jfoenixc.JFXTextArea(text))
def labelFloat = delegate.labelFloatProperty()
def labelFloat_=(v: Boolean) = delegate.setLabelFloat(v)
def focusColor: Paint = delegate.getFocusColor()
def focusColor_=(color: Paint) = delegate.setFocusColor(color)
def unFocusColor = delegate.getUnFocusColor()
def unFocusColor_=(color: Paint) = delegate.setUnFocusColor(color)
def disableAnimation: BooleanProperty = delegate.disableAnimationProperty()
def disableAnimation_=(disable: Boolean) =
delegate.setDisableAnimation(disable)
}

View File

@ -0,0 +1,38 @@
package wow.doge.mygame.util.controls
import com.jfoenix.{controls => jfoenixc}
import scalafx.Includes._
import scalafx.beans.property.BooleanProperty
import scalafx.scene.control.TextField
import scalafx.scene.paint.Paint
@SuppressWarnings(
Array("org.wartremover.warts.Null", "org.wartremover.warts.Equals")
)
object JFXTextField {
implicit def sfxTextField2jfx(v: JFXTextField): jfoenixc.JFXTextField =
if (v != null) v.delegate else null
}
// TextInputControl(delegate)
// with AlignmentDelegate[jfoenixc.JFXTextField]
// with SFXDelegate[jfoenixc.JFXTextField] {
class JFXTextField(
override val delegate: jfoenixc.JFXTextField = new jfoenixc.JFXTextField
) extends TextField(delegate) {
def labelFloat = delegate.labelFloatProperty()
def labelFloat_=(v: Boolean) = delegate.setLabelFloat(v)
def focusColor: Paint = delegate.getFocusColor()
def focusColor_=(color: Paint) = delegate.setFocusColor(color)
def unFocusColor = delegate.getUnFocusColor()
def unFocusColor_=(color: Paint) = delegate.setUnFocusColor(color)
def disableAnimation: BooleanProperty = delegate.disableAnimationProperty()
def disableAnimation_=(disable: Boolean) =
delegate.setDisableAnimation(disable)
}

View File

@ -0,0 +1,63 @@
package wow.doge.mygame.util.controls
import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject
import com.jfoenix.{controls => jfoenixc}
import javafx.scene.{control => jfxsc}
import scalafx.collections.ObservableBuffer
import scalafx.scene.control.TreeItem
import scalafx.scene.control.TreeTableView
class RecursiveTreeItem[G <: RecursiveTreeObject[G]](
override val delegate: jfoenixc.RecursiveTreeItem[G] =
new jfoenixc.RecursiveTreeItem[G]((item: RecursiveTreeObject[G]) =>
item.getChildren()
)
) extends TreeItem[G](delegate) {
def this(value: G) =
this(
new jfoenixc.RecursiveTreeItem[G](
value,
(item: RecursiveTreeObject[G]) => item.getChildren()
)
)
def this(items: ObservableBuffer[G]) =
this(
new jfoenixc.RecursiveTreeItem[G](
items,
(item: RecursiveTreeObject[G]) => item.getChildren()
)
)
}
object RecursiveTreeItem {
implicit def sfxTreeItem2jfxTreeItem[G <: RecursiveTreeObject[G]](
v: RecursiveTreeItem[G]
): jfoenixc.RecursiveTreeItem[G] = v.delegate
}
// @formatter:off
class JFXTreeTableView[S <: RecursiveTreeObject[S]](
override val delegate: jfoenixc.JFXTreeTableView[S] = new jfoenixc.JFXTreeTableView[S]
) extends TreeTableView(delegate) {
def this(root: TreeItem[S]) = this(new jfoenixc.JFXTreeTableView[S](root))
// def this(root: TreeItem[S], items: ObservableBuffer[S]) = this(new jfoenixc.JFXTreeTableView[S](root, items))
// @formatter:on
def currentItemsCount = delegate.currentItemsCountProperty()
def predicate = delegate.predicateProperty()
// delegate.set
// override def treeColumn_=(v: TreeTableColumn[S, _]): Unit = ???
// delegate.setTreeColumn()
}
// @formatter:off
@SuppressWarnings(Array("org.wartremover.warts.Null","org.wartremover.warts.Equals"))
object JFXTreeTableView {
implicit def sfxTreeTableView2jfx[S <: RecursiveTreeObject[S]](
v: JFXTreeTableView[S]
): jfxsc.TreeTableView[S] = if (v != null) v.delegate else null
}
// @formatter:on

View File

@ -0,0 +1,7 @@
package wow.doge.mygame.util.controls
import scalafx.scene.{control => sfxc}
import wow.doge.mygame.implicits._
class MenuItem extends sfxc.MenuItem {
def obsAction = new ActionObservableBuilder(this.observableAction)
}

View File

@ -20,6 +20,9 @@ class AssetManager(assetManager: jmea.AssetManager) {
case ex: AssetLoadException => case ex: AssetLoadException =>
IO.raiseError(AssetLoadError(ex.getMessage)) IO.raiseError(AssetLoadError(ex.getMessage))
} }
@SuppressWarnings(
Array("org.wartremover.warts.AsInstanceOf", "org.wartremover.warts.Equals")
)
def loadModelAs[T <: Spatial]( def loadModelAs[T <: Spatial](
path: os.RelPath path: os.RelPath
)(implicit ct: ClassTag[T]): IO[Error, T] = )(implicit ct: ClassTag[T]): IO[Error, T] =
@ -28,6 +31,9 @@ class AssetManager(assetManager: jmea.AssetManager) {
UIO(model.asInstanceOf[T]) UIO(model.asInstanceOf[T])
else IO.raiseError(CouldNotCastError) else IO.raiseError(CouldNotCastError)
) )
@SuppressWarnings(
Array("org.wartremover.warts.AsInstanceOf", "org.wartremover.warts.Equals")
)
def loadAssetAs[T](path: os.RelPath)(implicit ct: ClassTag[T]): IO[Error, T] = def loadAssetAs[T](path: os.RelPath)(implicit ct: ClassTag[T]): IO[Error, T] =
IO(assetManager.loadAsset(path.toString)) IO(assetManager.loadAsset(path.toString))
.onErrorHandleWith { .onErrorHandleWith {
@ -46,9 +52,9 @@ class AssetManager(assetManager: jmea.AssetManager) {
} }
object AssetManager { object AssetManager {
sealed trait Error sealed trait Error extends Product with Serializable
case class AssetNotFound(message: String) extends Error final case class AssetNotFound(message: String) extends Error
case class AssetLoadError(message: String) extends Error final case class AssetLoadError(message: String) extends Error
case object CouldNotCastError extends Error case object CouldNotCastError extends Error
object Error { object Error {
implicit val show = Show.fromToString[Error] implicit val show = Show.fromToString[Error]

View File

@ -9,7 +9,7 @@ import monix.bio.IO
object CollisionShapeFactory { object CollisionShapeFactory {
sealed trait Error sealed trait Error
case class WrongArgumentError(reason: String) extends Error final case class WrongArgumentError(reason: String) extends Error
object Error { object Error {
implicit val show = Show.fromToString[Error] implicit val show = Show.fromToString[Error]

View File

@ -1,15 +1,16 @@
package wow.doge.mygame package wow.doge.mygame
import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.scaladsl.ActorContext
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.BeforeAndAfterAll
import akka.actor.typed.ActorSystem
import scala.concurrent.duration._
import akka.actor.typed.ActorRef
import akka.actor.typed.scaladsl.AskPattern._
import akka.util.Timeout
import scala.concurrent.Await import scala.concurrent.Await
import scala.concurrent.duration._
import akka.actor.typed.ActorRef
import akka.actor.typed.ActorSystem
import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.scaladsl.AskPattern._
import akka.actor.typed.scaladsl.Behaviors
import akka.util.Timeout
import org.scalatest.BeforeAndAfterAll
import org.scalatest.funsuite.AnyFunSuite
class ActorTimeoutTest extends AnyFunSuite with BeforeAndAfterAll { class ActorTimeoutTest extends AnyFunSuite with BeforeAndAfterAll {
import ActorTimeoutTest._ import ActorTimeoutTest._
@ -30,7 +31,7 @@ class ActorTimeoutTest extends AnyFunSuite with BeforeAndAfterAll {
object ActorTimeoutTest { object ActorTimeoutTest {
object MyActor { object MyActor {
sealed trait Command sealed trait Command
case class GetInt(replyTo: ActorRef[Int]) extends Command final case class GetInt(replyTo: ActorRef[Int]) extends Command
class Props() { class Props() {
def create = def create =

View File

@ -1,21 +1,17 @@
package wow.doge.mygame package wow.doge.mygame
import org.scalatest.funsuite.AnyFunSuite
import com.jme3.anim.AnimClip
import wow.doge.mygame.implicits._
import wow.doge.mygame.utils.wrappers.jme.AssetManager
import com.jme3.asset.DesktopAssetManager
import com.jme3.scene.Spatial
import monix.bio.UIO
import scala.concurrent.duration._ import scala.concurrent.duration._
import com.jme3.scene.Node
import cats.syntax.all._
import com.jme3.anim.AnimComposer import com.jme3.anim.AnimComposer
import com.jme3.anim.SkinningControl import com.jme3.anim.SkinningControl
import com.jme3.anim.tween.action.BaseAction
import com.jme3.anim.tween.Tweens import com.jme3.anim.tween.Tweens
import scala.jdk.javaapi.CollectionConverters._ import com.jme3.anim.tween.action.BaseAction
import com.jme3.anim.tween.Tween
import com.jme3.anim.tween.action.ClipAction import com.jme3.anim.tween.action.ClipAction
import cats.syntax.all._ import com.jme3.asset.DesktopAssetManager
import com.jme3.scene.Node
import monix.bio.UIO
import org.scalatest.funsuite.AnyFunSuite
import wow.doge.mygame.utils.wrappers.jme.AssetManager
class AnimTest extends AnyFunSuite { class AnimTest extends AnyFunSuite {
import monix.execution.Scheduler.Implicits.global import monix.execution.Scheduler.Implicits.global

View File

@ -1,18 +1,19 @@
package wow.doge.mygame package wow.doge.mygame
import org.scalatest.funsuite.AnyFunSuite import scala.annotation.nowarn
import monix.execution.Scheduler.Implicits.global
import cats.syntax.eq._ import cats.syntax.eq._
import com.jme3.{asset => jmea}
import com.jme3.asset.DesktopAssetManager import com.jme3.asset.DesktopAssetManager
import com.jme3.material.Material
import com.jme3.material.MaterialDef
import com.jme3.scene.Geometry
import com.jme3.scene.Node
import com.jme3.{asset => jmea}
import monix.execution.Scheduler.Implicits.global
import org.scalatest.funsuite.AnyFunSuite
import wow.doge.mygame.utils.wrappers.jme.AssetManager import wow.doge.mygame.utils.wrappers.jme.AssetManager
import wow.doge.mygame.utils.wrappers.jme.AssetManager.AssetNotFound import wow.doge.mygame.utils.wrappers.jme.AssetManager.AssetNotFound
import com.jme3.scene.Geometry
import wow.doge.mygame.utils.wrappers.jme.AssetManager.CouldNotCastError import wow.doge.mygame.utils.wrappers.jme.AssetManager.CouldNotCastError
import com.jme3.scene.Node
import com.jme3.material.MaterialDef
import com.jme3.material.Material
import scala.annotation.nowarn
@nowarn("msg=method get in class LeftProjection is deprecated") @nowarn("msg=method get in class LeftProjection is deprecated")
@nowarn("msg=method right in class Either is deprecated") @nowarn("msg=method right in class Either is deprecated")

View File

@ -1,15 +1,17 @@
package wow.doge.mygame package wow.doge.mygame
import org.scalatest.funsuite.AnyFunSuite
import com.jme3.scene.Spatial
import com.jme3.collision.{Collidable, CollisionResults}
import com.jme3.bounding.BoundingVolume
import com.jme3.scene.Spatial.DFSMode
import com.jme3.scene.SceneGraphVisitor
import java.util.Queue import java.util.Queue
import wow.doge.mygame.utils.wrappers.jme.CollisionShapeFactory
import monix.execution.Scheduler.Implicits.global
import cats.syntax.eq._ import cats.syntax.eq._
import com.jme3.bounding.BoundingVolume
import com.jme3.collision.Collidable
import com.jme3.collision.CollisionResults
import com.jme3.scene.SceneGraphVisitor
import com.jme3.scene.Spatial
import com.jme3.scene.Spatial.DFSMode
import monix.execution.Scheduler.Implicits.global
import org.scalatest.funsuite.AnyFunSuite
import wow.doge.mygame.utils.wrappers.jme.CollisionShapeFactory
class CollisionShapeFactoryTest extends AnyFunSuite { class CollisionShapeFactoryTest extends AnyFunSuite {
test("Test for WrongArgumentError") { test("Test for WrongArgumentError") {

View File

@ -1,30 +1,62 @@
package wow.doge.mygame package wow.doge.mygame
import org.scalatest.funsuite.AnyFunSuite
import cats.effect.{Resource => CResource}
import monix.eval.Task
import scala.concurrent.duration._ import scala.concurrent.duration._
class FileWatcherTest extends AnyFunSuite { import cats.syntax.show._
test("1") { import monix.bio.IO
import better.files._ import monix.eval.Task
import io.methvin.better.files._ import monix.reactive.Observable
import org.scalatest.funsuite.AnyFunSuite
import wow.doge.mygame.implicits._
import wow.doge.mygame.utils.MonixDirectoryWatcher
val myDir = class FileWatcherTest extends AnyFunSuite {
File((os.pwd / "assets" / "scripts").toString) // test("1") {
val watcher = new RecursiveFileMonitor(myDir) { // import better.files._
override def onCreate(file: File, count: Int) = // import io.methvin.better.files._
println(s"$file got created")
override def onModify(file: File, count: Int) = // val myDir =
println(s"$file got modified $count times") // File((os.pwd / "assets" / "scripts").toString)
override def onDelete(file: File, count: Int) = // val watcher = new RecursiveFileMonitor(myDir) {
println(s"$file got deleted") // override def onCreate(file: File, count: Int) =
} // println(show"$file got created")
// override def onModify(file: File, count: Int) =
// println(show"$file got modified $count times")
// override def onDelete(file: File, count: Int) =
// println(show"$file got deleted")
// }
// import monix.execution.Scheduler.Implicits.global
// CResource
// .make(Task { watcher.start(); watcher })(w => Task(w.stop()))
// .use(_ => Task.never)
// .runSyncUnsafe(10.seconds)
// }
test("2") {
val obsT = MonixDirectoryWatcher(os.pwd / "assets" / "scripts")
import monix.execution.Scheduler.Implicits.global import monix.execution.Scheduler.Implicits.global
CResource obsT
.make(Task { watcher.start(); watcher })(w => Task(w.stop())) .flatMap(
.use(_ => Task.never) _.takeUntil(Observable.unit.delayExecution(2.seconds))
.runSyncUnsafe(10.seconds) .doOnNext {
case MonixDirectoryWatcher.CreateEvent(file, count) =>
Task(println(show"${file.toString} got created"))
case MonixDirectoryWatcher.DeleteEvent(file, count) =>
Task(println(show"${file.toString} got deleted"))
case MonixDirectoryWatcher.ModifyEvent(file, count) =>
Task(pprint.log(show"${file.toString} got modified $count times"))
}
.completedL
.flatMap(_ => Task.sleep(3.seconds))
.toIO
)
.onErrorHandleWith {
case ex: java.nio.file.ClosedWatchServiceException => IO.unit
case ex: java.lang.UnsupportedOperationException => IO.unit
}
.runSyncUnsafe(16.seconds)
} }
} }

View File

@ -1,10 +1,10 @@
package wow.doge.mygame package wow.doge.mygame
import org.scalatest.funsuite.AnyFunSuite
import wow.doge.mygame.math.ImVector3f
import com.typesafe.scalalogging.LazyLogging
import cats.syntax.eq._ import cats.syntax.eq._
import cats.syntax.show._ import cats.syntax.show._
import com.typesafe.scalalogging.LazyLogging
import org.scalatest.funsuite.AnyFunSuite
import wow.doge.mygame.math.ImVector3f
class ImVector3fTest extends AnyFunSuite with LazyLogging { class ImVector3fTest extends AnyFunSuite with LazyLogging {
test("maxvalue") { test("maxvalue") {

View File

@ -1,11 +1,11 @@
package wow.doge.mygame package wow.doge.mygame
import org.scalatest.funsuite.AnyFunSuite import cats.syntax.eq._
import wow.doge.mygame.subsystems.moddingsystem.ModdingSystem
import monix.execution.Scheduler.Implicits.global
import io.circe.Printer import io.circe.Printer
import monix.bio.UIO import monix.bio.UIO
import cats.syntax.eq._ import monix.execution.Scheduler.Implicits.global
import org.scalatest.funsuite.AnyFunSuite
import wow.doge.mygame.subsystems.moddingsystem.ModdingSystem
class ModdingSystemTest extends AnyFunSuite { class ModdingSystemTest extends AnyFunSuite {
val printer = Printer.spaces2 val printer = Printer.spaces2

View File

@ -1,12 +1,12 @@
package wow.doge.mygame package wow.doge.mygame
import org.scalatest.funsuite.AnyFunSuite
import monix.bio.Task
import scala.concurrent.duration._ import scala.concurrent.duration._
import monix.execution.Scheduler.Implicits.global
import wow.doge.mygame.subsystems.scriptsystem.ScriptCompiler
import io.odin.consoleLogger import io.odin.consoleLogger
import wow.doge.mygame.implicits._ import monix.bio.Task
import monix.execution.Scheduler.Implicits.global
import org.scalatest.funsuite.AnyFunSuite
import wow.doge.mygame.subsystems.scriptsystem.ScriptCompiler
class MonixScriptCompilerTest extends AnyFunSuite { class MonixScriptCompilerTest extends AnyFunSuite {
@ -16,13 +16,13 @@ class MonixScriptCompilerTest extends AnyFunSuite {
for { for {
// _ <- // _ <-
// scriptCompiler.source // scriptCompiler.source
// .doOnNextF(el => Task(println(s"Got $el"))) // .doOnNextF(el => Task(println(show"Got $el")))
// .completedL // .completedL
// .toIO // .toIO
// .hideErrors // .hideErrors
// .startAndForget // .startAndForget
response <- scriptCompiler.request( response <- scriptCompiler.request(
ScriptCompiler.Get( ScriptCompiler.GetScript(
os.pwd / "assets" / "scripts" / "scala" / "hello2.sc", os.pwd / "assets" / "scripts" / "scala" / "hello2.sc",
_, _,
false false

View File

@ -1,16 +1,14 @@
package wow.doge.mygame package wow.doge.mygame
import cats.data.ReaderT import cats.data.ReaderT
import monix.bio.UIO
import org.scalatest.funsuite.AnyFunSuite
import monix.execution.Scheduler.Implicits.global
import monix.bio.IO
import cats.mtl.Ask
import cats.mtl.implicits._
import cats.effect.LiftIO import cats.effect.LiftIO
import monix.bio.Task import cats.mtl.Ask
import cats.data.Kleisli import monix.bio.IO
import monix.bio.IOLift import monix.bio.IOLift
import monix.execution.Scheduler.Implicits.global
import org.scalatest.funsuite.AnyFunSuite
final case class Environment(str: String, num: Int)
class ReaderT_Test extends AnyFunSuite { class ReaderT_Test extends AnyFunSuite {
@ -24,8 +22,6 @@ class ReaderT_Test extends AnyFunSuite {
// val t2 = r.run("s").rethrow // val t2 = r.run("s").rethrow
// Kleisli[IO, String, Unit](s => IO.unit) // Kleisli[IO, String, Unit](s => IO.unit)
case class Environment(str: String, num: Int)
// test("runReaderT_Test") { // test("runReaderT_Test") {
// def fun1: ReaderT[UIO, String, Unit] = ReaderT(str => UIO(println(str))) // def fun1: ReaderT[UIO, String, Unit] = ReaderT(str => UIO(println(str)))
// def fun2: ReaderT[UIO, Int, Unit] = ReaderT(num => UIO(println(num))) // def fun2: ReaderT[UIO, Int, Unit] = ReaderT(num => UIO(println(num)))

View File

@ -2,8 +2,8 @@ package wow.doge.mygame
import cats.data.Reader import cats.data.Reader
import monix.bio.UIO import monix.bio.UIO
import org.scalatest.funsuite.AnyFunSuite
import monix.execution.Scheduler.Implicits.global import monix.execution.Scheduler.Implicits.global
import org.scalatest.funsuite.AnyFunSuite
class ReaderTest extends AnyFunSuite { class ReaderTest extends AnyFunSuite {
@ -17,8 +17,6 @@ class ReaderTest extends AnyFunSuite {
// val t2 = r.run("s").rethrow // val t2 = r.run("s").rethrow
// Kleisli[IO, String, Unit](s => IO.unit) // Kleisli[IO, String, Unit](s => IO.unit)
case class Environment(str: String, num: Int)
def fun1: Reader[String, UIO[Unit]] = Reader(str => UIO(println(str))) def fun1: Reader[String, UIO[Unit]] = Reader(str => UIO(println(str)))
def fun2: Reader[Int, UIO[Unit]] = Reader(num => UIO(println(num))) def fun2: Reader[Int, UIO[Unit]] = Reader(num => UIO(println(num)))