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
.bloop
.ammonite
.bsp
# Scala-IDE specific
.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.sonatypeRepo("snapshots")
lazy val jmeVersion = "3.3.2-stable"
val jmeVersion = "3.3.2-stable"
lazy val osName = System.getProperty("os.name") match {
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.typelevel" %% "cats-mtl" % "1.1.1",
"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
// Add JavaFX dependencies
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(
"-encoding",
@ -126,7 +133,8 @@ lazy val root = (project in file(".")).settings(
// 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(
"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"
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("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
.unsafeRunSync()
{
ArraySeq(release1, release2, release3).foreach(r =>
sys.addShutdownHook(r.unsafeRunSync())
)
}
ArraySeq(release1, release2, release3).foreach(r =>
sys.addShutdownHook(r.unsafeRunSync())
)
val loggers: PartialFunction[String, Logger[IO]] = {
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.NodeWrapper2
sealed trait AppError
sealed trait AppError extends Product with Serializable
object AppError {
final case class TimeoutError(reason: String) extends AppError
object TimeoutError {

View File

@ -2,17 +2,18 @@ package wow.doge.mygame
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 cats.effect.ExitCode
import cats.effect.Resource
import cats.implicits._
import io.odin._
import io.odin.consoleLogger
import io.odin.fileLogger
import io.odin.json.Formatter
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 wow.doge.mygame.ActorSystemResource
import wow.doge.mygame.executors.ExecutorsModule

View File

@ -1,5 +1,7 @@
package wow.doge.mygame
import java.util.concurrent.TimeoutException
import scala.concurrent.duration._
import akka.actor.typed.ActorRef
@ -8,6 +10,8 @@ import akka.util.Timeout
import cats.effect.Resource
import cats.effect.concurrent.Deferred
import cats.syntax.eq._
import cats.syntax.show._
import com.jayfella.jme.jfx.JavaFxUI
import com.jme3.asset.plugins.ZipLocator
import com.jme3.bullet.control.BetterCharacterControl
import com.jme3.input.InputManager
@ -28,9 +32,14 @@ import monix.bio.IO
import monix.bio.Task
import monix.bio.UIO
import monix.eval.Coeval
import monix.execution.cancelables.CompositeCancelable
import monix.execution.exceptions.DummyException
import monix.reactive.Observable
import scalafx.scene.control.Label
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.executors.Schedulers
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.StatsEvent.DamageEvent
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.ScriptSystemResource
import wow.doge.mygame.types._
import wow.doge.mygame.utils.AkkaUtils
import wow.doge.mygame.utils.GenericConsoleStream
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.PhysicsSpace
class MainApp(
@ -79,8 +92,8 @@ class MainApp(
) {
implicit val as = scheduler.value
val scriptSystemInit =
new ScriptSystemResource(os.pwd, ScriptInitMode.Eager).init
val scriptSystemResource: Resource[UIO, ScriptCompiler] =
new ScriptSystemResource(os.pwd, logger, ScriptInitMode.Eager).init2
val eventsModule = new EventsModule(scheduler, spawnProtocol)
@ -101,7 +114,9 @@ class MainApp(
IOUtils
.toIO(
obs
.doOnNextF(pme => Coeval(pprint.log(s"Received event $pme")).void)
.doOnNextF(pme =>
Coeval(pprint.log(show"Received event $pme")).void
)
.completedL
.startAndForget
)
@ -114,7 +129,7 @@ class MainApp(
viewPort <- gameApp.viewPort
physicsSpace <- UIO.pure(gameApp.physicsSpace)
_ <- logger.infoU("before")
// jfxUI <- gameApp.jfxUI
jfxUI <- gameApp.jfxUI.hideErrors
consoleTextArea <- UIO(new TextArea {
text = "hello \n"
editable = false
@ -122,6 +137,7 @@ class MainApp(
// maxHeight = 150
// maxWidth = 300
})
// _ <- Task(consoleStream := consoleTextArea)
// _ <- Task(jfxUI += consoleTextArea)
_ <- logger.infoU("after")
@ -132,14 +148,48 @@ class MainApp(
.executeOn(gameApp.scheduler.value)
} 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(
tickEventBus: GameEventBus[TickEvent]
): Resource[UIO, Either[AppError, Fiber[Nothing, Unit]]] =
wire[GameAppResource].resource.evalMap {
case Right(gameApp -> gameAppFib) =>
eval(tickEventBus, gameApp, gameAppFib).attempt
case Left(error) => IO.terminate(new Exception(error.toString))
}
for {
r1 <- wire[GameAppResource].resource.evalMap {
case Right(gameApp -> gameAppFib) =>
eval(tickEventBus, gameApp, gameAppFib).attempt
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 {
// scriptSystem <- scriptSystemInit
@ -185,7 +235,8 @@ class MainAppDelegate(
viewPort: ViewPort,
enqueueR: Function1[() => Unit, Unit],
rootNode: RootNode,
schedulers: Schedulers
schedulers: Schedulers,
jfxUI: JavaFxUI
)(implicit
spawnProtocol: ActorRef[SpawnProtocol.Command],
timeout: Timeout,
@ -203,7 +254,7 @@ class MainAppDelegate(
os.rel / "assets" / "town.zip",
classOf[ZipLocator]
)
_ <- loggerL.infoU("test")
// _ <- Task(consoleStream.println("text"))
level <- DefaultGameLevel(assetManager, viewPort)
_ <- level.addToGame(rootNode, physicsSpace)
@ -231,45 +282,44 @@ class MainAppDelegate(
_ <-
damageObs
.doOnNextF(event =>
(loggerL.debug(s"Received Damage Event $event") >>
(loggerL.debug(show"Received Damage Event $event") >>
(if (event.victimName === "PlayerNode")
// playerActor !! PlayerActorSupervisor.TakeDamage(event.amount)
playerActor.askL(
PlayerActorSupervisor.TakeDamage2(event.amount, _)
)
playerActor
.askL(PlayerActorSupervisor.TakeDamage(event.amount, _))
.onErrorHandle { case ex: TimeoutException => () }
else IO.unit)).toTask
)
.completedL
.toIO
.hideErrors
.startAndForget
_ <-
Observable
.interval(1.second)
.doOnNextF(_ =>
playerActor
.askL(PlayerActorSupervisor.GetStatus)
.flatMap(s => loggerL.debug(s"Player actor status: $s"))
// _ <-
// Observable
// .interval(1.second)
// .doOnNextF(_ =>
// playerActor
// .askL(PlayerActorSupervisor.GetStatus)
// .flatMap(s => loggerL.debug(show"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(_ =>
// playerActor
// .askL(PlayerActorSupervisor.GetStatus )
// .flatMap(s => loggerL.debug(s"Player actor status: $s"))
// .toTask
// )
.completedL
.toIO
.hideErrors
.startAndForget
// // .flatMap(s =>
// // if (s == Status.Alive)
// // playerActor
// // .askL(PlayerActorSupervisor.CurrentStats )
// // .flatMap(s => loggerL.debug(show"Got state $s"))
// // else IO.unit
// // )
// .toTask
// )
// // .doOnNextF(_ =>
// // playerActor
// // .askL(PlayerActorSupervisor.GetStatus )
// // .flatMap(s => loggerL.debug(show"Player actor status: $s"))
// // .toTask
// // )
// .completedL
// .toIO
// .hideErrors
// .startAndForget
_ <-
physicsSpace.collisionObservable
// .filter(event =>
@ -282,7 +332,7 @@ class MainAppDelegate(
// )
// .doOnNextF(event =>
// loggerL
// .debug(s"$event ${event.appliedImpulse()}")
// .debug(show"$event ${event.appliedImpulse()}")
// .toTask
// )
.filter(_.nodeA.map(_.getName =!= "main-scene_node").getOrElse(false))
@ -295,7 +345,7 @@ class MainAppDelegate(
} yield if (nodeB.getName === "John") nodeA else nodeB)
_ <- Coeval(
victim.foreach { v =>
pprint.log(s"emitted event ${v.getName}")
pprint.log(show"emitted event ${v.getName}")
mainEventBus ! EventBus.Publish(
DamageEvent(
"John",
@ -322,6 +372,63 @@ class MainAppDelegate(
// )
// .executeOn(appScheduler)
// .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 ()
def createPlayerController(
@ -369,70 +476,34 @@ class MainAppDelegate(
.scan(new Quaternion) {
case (rotationBuf, action) =>
action.binding match {
// case PlayerCameraEvent.CameraLeft =>
case PlayerCameraInput.CameraRotateLeft =>
// me.Task {
val rot = rotationBuf
.fromAngleAxis(1 * FastMath.DEG_TO_RAD, Vector3f.UNIT_Y)
cameraPivotNode.rotate(rot)
rotationBuf
// }
// case PlayerCameraEvent.CameraRight =>
case PlayerCameraInput.CameraRotateRight =>
// me.Task {
val rot = rotationBuf
.fromAngleAxis(-1 * FastMath.DEG_TO_RAD, Vector3f.UNIT_Y)
cameraPivotNode.rotate(rot)
rotationBuf
// }
// case PlayerCameraEvent.CameraMovedUp =>
case PlayerCameraInput.CameraRotateUp =>
// me.Task {
val rot = rotationBuf
.fromAngleAxis(-1 * FastMath.DEG_TO_RAD, Vector3f.UNIT_X)
cameraPivotNode.rotate(rot)
rotationBuf
// }
// case PlayerCameraEvent.CameraMovedDown =>
case PlayerCameraInput.CameraRotateDown =>
// me.Task {
val rot = rotationBuf
.fromAngleAxis(1 * FastMath.DEG_TO_RAD, Vector3f.UNIT_X)
cameraPivotNode.rotate(rot)
rotationBuf
// }
}
}
.completedL
.toIO
.hideErrors
.startAndForget
// _ <-
// Observable
// .interval(10.millis)
// .doOnNextF(_ =>
// Coeval {
// val location = playerNode.getWorldTranslation()
// cameraPivotNode.setLocalTranslation(location)
// }
// )
// .completedL
// .toIO
// .hideErrors
// .startAndForget
sched <- UIO.pure(schedulers.async)
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
}
@ -456,7 +527,7 @@ class MainAppDelegate(
npcName,
initialPos
).behavior,
actorName = Some(s"${npcName}-npcActorSupervisor")
actorName = Some(show"${npcName}-npcActorSupervisor")
)
(for {

View File

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

View File

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

View File

@ -5,7 +5,7 @@ import monix.execution.Scheduler
import monix.execution.UncaughtExceptionReporter
final case class Schedulers(
blockingIO: Schedulers.IoScheduler,
io: Schedulers.IoScheduler,
async: Schedulers.AsyncScheduler,
fx: Schedulers.FxScheduler
)
@ -32,8 +32,8 @@ object Schedulers {
)
)
case class AsyncScheduler(value: Scheduler)
case class IoScheduler(value: Scheduler)
case class FxScheduler(value: Scheduler)
final case class AsyncScheduler(value: Scheduler)
final case class IoScheduler(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.scaladsl.AskPattern._
import akka.util.Timeout
import cats.Show
import cats.effect.Resource
import cats.effect.concurrent.Deferred
import cats.syntax.show._
import com.jme3.bullet.BulletAppState
import com.jme3.input.InputManager
import com.jme3.scene.Node
@ -177,6 +179,10 @@ object SpawnSystem {
result: Deferred[Task, Result]
)
object SpawnRequestWrapper {
implicit val show = Show.fromToString[SpawnRequestWrapper]
}
def apply(logger: Logger[Task]) =
for {
spawnChannel <- ConcurrentChannel[Task].of[Complete, SpawnRequestWrapper]
@ -213,7 +219,7 @@ class SpawnSystem(
for {
_ <-
logger
.debug(s"Received spawn request $message")
.debug(show"Received spawn request $message")
_ <- handleSpawn(message)
} yield receive(consumer)
case Left(r) =>

View File

@ -22,12 +22,13 @@ object GameAppActor {
case object Start extends Command
case object Pause extends Command
case object Ping extends Command
case class Stop(stopSignal: ActorRef[CancelableFuture[Unit]]) extends Command
case class GetSpawnProtocol(
final case class Stop(stopSignal: ActorRef[CancelableFuture[Unit]])
extends Command
final case class GetSpawnProtocol(
replyTo: ActorRef[ActorRef[SpawnProtocol.Command]]
) extends Command
case class Props(tickEventBus: GameEventBus[TickEvent]) {
final case class Props(tickEventBus: GameEventBus[TickEvent]) {
def behavior =
Behaviors.setup[Command] { ctx =>
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
import scala.collection.immutable.Queue
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import com.jme3.app.SimpleApplication
@ -28,6 +27,7 @@ class SimpleAppExt(
private val startSignal: CancelablePromise[Unit] = CancelablePromise()
private val terminationSignal: CancelablePromise[Unit] = CancelablePromise()
private implicit val ec = schedulers.async.value
var cancelToken: Option[() => Future[Unit]] = None
@ -87,7 +87,7 @@ class SimpleAppExt(
val scheduler = Scheduler(JMEExecutorService)
}
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()

View File

@ -40,7 +40,7 @@ object TestActor {
// ctx.log.debugP(value.toString())
// Done
// case Failure(exception) =>
// ctx.log.debugP(s"Received Error ${exception.getMessage()}")
// ctx.log.debugP(show"Received Error ${exception.getMessage()}")
// 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 cats.syntax.eq._
import com.jme3.math.FastMath
import com.jme3.math.Quaternion
import com.jme3.math.Vector3f
@ -26,6 +27,7 @@ import wow.doge.mygame.game.subsystems.input.PlayerCameraInput
* @param rotateFn
* @param s
*/
@SuppressWarnings(Array("org.wartremover.warts.Null"))
class CameraMovementControl(
rotationBuf: Quaternion,
obs: Observable[PlayerCameraInput],
@ -49,7 +51,7 @@ class CameraMovementControl(
}
override def controlUpdate(tpf: Float): Unit =
if (_event != null) {
if (_event =!= null) {
_event match {
case PlayerCameraInput.CameraRotateLeft =>
val rot = rotationBuf
@ -75,6 +77,8 @@ class CameraMovementControl(
x$1: RenderManager,
x$2: ViewPort
): Unit = {}
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
override def setSpatial(spatial: Spatial): Unit = {
super.setSpatial(spatial)
if (this.spatial != null)

View File

@ -4,14 +4,18 @@ import akka.actor.typed.ActorRef
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.scaladsl.Behaviors
import cats.Show
import io.estatico.newtype.macros.newtype
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 {
@newtype case class HealHealth(toInt: Int)
@newtype case class DamageHealth(toInt: Int)
@newtype case class Health(toInt: Int)
@newtype final case class HealHealth(toInt: Int)
@newtype final case class DamageHealth(toInt: Int)
@newtype final case class Health(toInt: Int)
object Health {
implicit class HealthOps(private val h: Health) extends AnyVal {
// def +(v: Int): Health = Health(h.toInt + v)
@ -22,9 +26,9 @@ object CharacterStats {
def -(v: DamageHealth): Health = Health(h.toInt - v.toInt)
}
}
@newtype case class HealStamina(toInt: Int)
@newtype case class DamageStamina(toInt: Int)
@newtype case class Stamina(toInt: Int)
@newtype final case class HealStamina(toInt: Int)
@newtype final case class DamageStamina(toInt: Int)
@newtype final case class Stamina(toInt: Int)
object Stamina {
implicit class StaminaOps(private val h: Stamina) extends AnyVal {
// def +(v: Int): Stamina = Stamina(h.toInt + v)
@ -53,18 +57,25 @@ object CharacterStats {
// }
// }
implicit val show = Show.fromToString[CharacterStats]
}
object StatsActor {
sealed trait Command
// case class TakeDamage(value: Int) extends Command
case class TakeDamageResult(
// final case class TakeDamage(value: Int) extends Command
final case class TakeDamageResult(
value: CharacterStats.DamageHealth,
replyTo: ActorRef[(Boolean, CharacterStats)]
) extends Command
case class HealResult(value: HealHealth) extends Command
case class CurrentStats(replyTo: ActorRef[CharacterStats]) extends Command
final case class ConsumeStaminaResult(
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(
startingHealth: CharacterStats.Health,
@ -74,12 +85,12 @@ object StatsActor {
Behaviors.setup[Command] { ctx =>
new StatsActor(ctx, this)
.receive(
State(CharacterStats(startingHealth, startingStamina.toInt))
State(CharacterStats(startingHealth, startingStamina))
)
}
}
case class State(stats: CharacterStats)
final case class State(stats: CharacterStats)
}
class StatsActor(
ctx: ActorContext[StatsActor.Command],
@ -100,11 +111,24 @@ class StatsActor(
// receive(nextState)
case TakeDamageResult(value, replyTo) =>
val nextState = if ((state.stats.hp - value).toInt <= 0) {
replyTo ! true -> state.stats
state.modify(_.stats.hp).setTo(Health(0))
val s = state.modify(_.stats.hp).setTo(Health(0))
replyTo ! true -> s.stats
s
} else {
replyTo ! false -> state.stats
state.modify(_.stats.hp).using(_ - value)
val s = 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)
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.Behaviors
import akka.util.Timeout
import cats.syntax.eq._
import cats.syntax.show._
import monix.execution.CancelableFuture
import monix.execution.CancelablePromise
@ -39,8 +40,8 @@ object NpcActorSupervisor {
signal: CancelableFuture[NpcMovementActor.DoneMoving.type]
) extends Command
private case object DoneMoving extends Command
private case class LogError(err: Throwable) extends Command
private case class MovementFailed(err: Throwable) extends Command
private final case class LogError(err: Throwable) extends Command
private final case class MovementFailed(err: Throwable) extends Command
class Props(
val npcMovementActorBehavior: Behavior[NpcMovementActor.Command],
@ -86,7 +87,7 @@ class NpcActorSupervisor(
def idle(state: State): Behavior[NpcActorSupervisor.Command] =
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] {
case m @ Move(pos) =>
ctx.ask(
@ -113,7 +114,7 @@ class NpcActorSupervisor(
signal: CancelableFuture[NpcMovementActor.DoneMoving.type]
): Behavior[NpcActorSupervisor.Command] =
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
ctx.pipeToSelf(signal) {
case Success(value) => DoneMoving
@ -150,7 +151,7 @@ class NpcActorSupervisor(
}
def logError(err: Throwable) =
ctx.log.errorP(s"npcActor-${props.npcName}: " + err.getMessage)
ctx.log.errorP(show"npcActor-${props.npcName}: " + err.getMessage)
}
object NpcMovementActor {
@ -158,10 +159,10 @@ object NpcMovementActor {
case object DoneMoving
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 StopMoving extends Command
case class MoveTo(
final case class MoveTo(
target: ImVector3f,
doneSignal: ActorRef[CancelableFuture[DoneMoving.type]]
) extends Command
@ -212,7 +213,7 @@ class NpcMovementActor[T](
Behaviors.receiveMessagePartial {
case StopMoving =>
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))
receive(state)
@ -262,19 +263,19 @@ object NpcMovementActorNotUsed {
case event: EntityMovementEvent =>
event match {
case MovedLeft(name, pressed) =>
if (name == npcName)
if (name === npcName)
movementActor ! ImMovementActor.MoveLeft(pressed)
Behaviors.same
case MovedUp(name, pressed) =>
if (name == npcName)
if (name === npcName)
movementActor ! ImMovementActor.MoveUp(pressed)
Behaviors.same
case MovedRight(name, pressed) =>
if (name == npcName)
if (name === npcName)
movementActor ! ImMovementActor.MoveRight(pressed)
Behaviors.same
case MovedDown(name, pressed) =>
if (name == npcName)
if (name === npcName)
movementActor ! ImMovementActor.MoveDown(pressed)
Behaviors.same
}

View File

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

View File

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

View File

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

View File

@ -27,7 +27,8 @@ import wow.doge.mygame.utils.wrappers.jme._
object PlayerController {
sealed trait Error
case class CouldNotCreatePlayerModel(reason: AssetManager.Error) extends Error
final case class CouldNotCreatePlayerModel(reason: AssetManager.Error)
extends Error
object Tags {
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 scala.jdk.javaapi.CollectionConverters._
case class City(x: Float, y: Float, name: String, index: Int)
case class Street(fromNode: City, toNode: City, cost: Float)
final case class City(x: Float, y: Float, name: String, index: Int)
final case class Street(fromNode: City, toNode: City, cost: Float)
extends Connection[City] {
override def getCost(): Float = cost

View File

@ -1,6 +1,9 @@
package wow.doge.mygame.game.subsystems.input
import cats.Show
import cats.kernel.Eq
import enumeratum.EnumEntry._
import enumeratum._
import io.circe.generic.semiauto._
sealed trait PlayerMovementInput extends EnumEntry with UpperSnakecase
object PlayerMovementInput extends Enum[PlayerMovementInput] {
@ -10,6 +13,9 @@ object PlayerMovementInput extends Enum[PlayerMovementInput] {
case object WalkLeft extends PlayerMovementInput
case object WalkBackward 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
@ -17,6 +23,9 @@ object PlayerAnalogMovementInput extends Enum[PlayerAnalogMovementInput] {
val values = findValues
case object TurnRight 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
@ -26,6 +35,10 @@ object PlayerCameraInput extends Enum[PlayerCameraInput] {
case object CameraRotateRight extends PlayerCameraInput
case object CameraRotateUp 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

View File

@ -1,55 +1,14 @@
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.DirectionalLight
import com.jme3.math.ColorRGBA
import com.jme3.math.Vector3f
import com.jme3.renderer.ViewPort
import com.jme3.scene.Spatial
import monix.bio.IO
import monix.bio.UIO
import wow.doge.mygame.AppError
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(
assetManager: wow.doge.mygame.utils.wrappers.jme.AssetManager,
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.PhysicsSpace
// case class Blah(humbug: String)
class GameLevel(
val model: Spatial,
val physicsControl: RigidBodyControl,

View File

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

View File

@ -1,29 +1,74 @@
package wow.doge.mygame.implicits
import javafx.beans.value.ObservableValue
import javafx.beans.{value => jfxbv}
import javafx.beans.property.ObjectProperty
import javafx.collections.ObservableList
import javafx.event.ActionEvent
import javafx.event.EventHandler
import javafx.scene.{input => jfxsi}
import javafx.{event => jfxe}
import monix.bio.Task
import monix.eval.Coeval
import monix.execution.Ack
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.Observer
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.ReadOnlyProperty
import scalafx.collections.ObservableBuffer
import scalafx.event.subscriptions.Subscription
import scalafx.scene.Scene
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 {
implicit final class SceneObservables(private val scene: Scene)
extends AnyVal {
final class SceneExt(private val scene: Scene) extends AnyVal {
def observableMousePressed(): Observable[jfxsi.MouseEvent] = {
import monix.execution.cancelables.SingleAssignCancelable
Observable.create(OverflowStrategy.Unbounded) { sub =>
val c = SingleAssignCancelable()
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()
}
}
scene.onMousePressed = l
@ -36,17 +81,17 @@ object JavaFXMonixObservables {
c
}
}
def observableMouseDragged(): Observable[jfxsi.MouseEvent] = {
import monix.execution.cancelables.SingleAssignCancelable
Observable.create(OverflowStrategy.Unbounded) { sub =>
val c = SingleAssignCancelable()
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()
}
}
scene.onMouseDragged = l
scene.onMouseDragged = l;
c := Cancelable(() =>
scene.removeEventHandler(
jfxsi.MouseEvent.MOUSE_DRAGGED,
@ -58,46 +103,224 @@ 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 {
def <--[T](op: Observable[(ObservableValue[_ <: B], B, B)] => T) = {
op(prop.observableChange())
}
def -->[J1 >: J](sub: Observer[J1]) =
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
Observable.create(OverflowStrategy.Unbounded) { sub =>
val c = SingleAssignCancelable()
val listener = new jfxbv.ChangeListener[B] {
override def changed(
observable: ObservableValue[_ <: B],
oldValue: B,
newValue: B
): Unit = {
sub.onNext((observable, oldValue, newValue))
}
}
val canc =
prop.onChange((a, b, c1) =>
if (c1 != null && sub.onNext(c1) == Ack.Stop) c.cancel()
)
prop.addListener(listener)
c := Cancelable(() => prop.removeListener(listener))
c := Cancelable(() => canc.cancel())
c
}
}
}
implicit final class OnActionObservable(
private val button: ButtonBase
) extends AnyVal {
def observableAction(): Observable[jfxe.ActionEvent] = {
final class ObjectPropertyExt[A](private val prop: ObjectProperty[A])
extends AnyVal {
@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
Observable.create(OverflowStrategy.Unbounded) { 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()
val canc = prop.onChange((_, _, c1) =>
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
@ -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.scaladsl.ActorContext
import akka.util.Timeout
import cats.Show
import com.jayfella.jme.jfx.JavaFxUI
import com.jme3.app.Application
import com.jme3.app.SimpleApplication
@ -61,7 +62,6 @@ import monix.reactive.OverflowStrategy
import monix.reactive.observers.Subscriber
import org.slf4j.Logger
import wow.doge.mygame.math.ImVector3f
import wow.doge.mygame.state.MyBaseState
import wow.doge.mygame.utils.wrappers.jme.PhysicsSpace
final case class ActionEvent(binding: Action, value: Boolean, tpf: Float)
@ -87,7 +87,7 @@ final case class CollisionEvent(
appliedImpulse: Function0[Float]
)
package object implicits {
package object implicits extends JavaFXMonixObservables {
type PrePhysicsTickEvent = PhysicsTickEvent
type PhysicsTickObservable =
Observable[Either[PrePhysicsTickEvent, PhysicsTickEvent]]
@ -102,6 +102,12 @@ package object implicits {
}
implicit final class StateManagerExt(private val asm: AppStateManager)
extends AnyVal {
@SuppressWarnings(
Array(
"org.wartremover.warts.AsInstanceOf",
"org.wartremover.warts.Equals"
)
)
def state[S <: AppState]()(implicit c: ClassTag[S]): S =
asm.getState(c.runtimeClass.asInstanceOf[Class[S]])
@ -121,26 +127,6 @@ package object implicits {
def viewPort = sa.getViewPort()
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)
@ -493,6 +479,7 @@ package object implicits {
* @see [[ActionEvent]]
* @see [[enumObservableAction]]
*/
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def observableAction(mappingNames: String*): Observable[ActionEvent] =
Observable.create(OverflowStrategy.DropOld(10)) { sub =>
val c = SingleAssignCancelable()
@ -537,6 +524,7 @@ package object implicits {
* @see [[EnumActionEvent]]
* @see [[enumAnalogObservable]]
*/
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def enumObservableAction[T <: EnumEntry](
mappingEnum: Enum[T]
): Observable[EnumActionEvent[T]] =
@ -563,6 +551,7 @@ package object implicits {
c
}
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def enumEntryObservableAction[T <: EnumEntry](
mappingEnumEntry: T
): Observable[EnumActionEvent[T]] =
@ -590,6 +579,7 @@ package object implicits {
c
}
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def analogObservable(mappingNames: String*): Observable[AnalogEvent] =
Observable.create(OverflowStrategy.DropOld(50)) { sub =>
val c = SingleAssignCancelable()
@ -613,6 +603,7 @@ package object implicits {
c
}
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def enumAnalogObservable[T <: EnumEntry](
mappingEnum: Enum[T]
): Observable[EnumAnalogEvent[T]] =
@ -643,6 +634,7 @@ package object implicits {
implicit final class PhysicsSpaceExt(private val space: jmeb.PhysicsSpace)
extends AnyVal {
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def collisionObservable(): Observable[CollisionEvent] =
Observable.create(OverflowStrategy.DropOld(50)) { sub =>
val c = SingleAssignCancelable()
@ -670,6 +662,7 @@ package object implicits {
c
}
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def prePhysicsTickObservable(): Observable[PrePhysicsTickEvent] =
Observable.create(OverflowStrategy.DropOld(50)) { sub =>
val c = SingleAssignCancelable()
@ -699,6 +692,7 @@ package object implicits {
c
}
@SuppressWarnings(Array("org.wartremover.warts.Equals"))
def physicsTickObservable(): Observable[PhysicsTickEvent] =
Observable.create(OverflowStrategy.DropOld(50)) { sub =>
val c = SingleAssignCancelable()
@ -905,4 +899,6 @@ package object implicits {
) extends AnyVal {
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.stage.StageStyle
import wow.doge.mygame.executors.Schedulers.FxScheduler
import wow.doge.mygame.implicits.JavaFXMonixObservables._
import wow.doge.mygame.implicits._
import wow.doge.mygame.utils.IOUtils._
object Launcher {
sealed trait LauncherResult
@ -43,8 +43,7 @@ class Launcher private (props: Launcher.Props) {
}
private lazy val launchAction =
launchButton
.observableAction()
launchButton.observableAction
.doOnNext(_ => toTask(props.signal.complete(LauncherResult.LaunchGame)))
private lazy val exitButton = new Button {
@ -52,8 +51,7 @@ class Launcher private (props: Launcher.Props) {
}
private lazy val exitAction =
exitButton
.observableAction()
exitButton.observableAction
.doOnNext(_ => toTask(props.signal.complete(LauncherResult.Exit)))
private lazy val _scene =

View File

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

View File

@ -1,5 +1,6 @@
package wow.doge.mygame.subsystems.events
import cats.Show
import wow.doge.mygame.game.entities.CharacterStats
sealed trait Event
@ -27,9 +28,11 @@ object EntityMovementEvent {
sealed trait StatsEvent extends Event
object StatsEvent {
case class DamageEvent(
final case class DamageEvent(
hitBy: String,
victimName: String,
amount: CharacterStats.DamageHealth
) 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
import cats.Show
sealed trait PlayerEvent
sealed trait PlayerMovementEvent extends PlayerEvent
@ -14,6 +16,7 @@ object PlayerMovementEvent {
case object PlayerJumped extends PlayerMovementEvent
// case object PlayerTurnedRight extends PlayerMovementEvent
// case object PlayerTurnedLeft extends PlayerMovementEvent
implicit val show = Show.fromToString[PlayerMovementEvent]
}
sealed trait PlayerCameraEvent extends PlayerEvent

View File

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

View File

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

View File

@ -17,7 +17,9 @@ import com.softwaremill.tagging._
import com.typesafe.scalalogging.Logger
import groovy.util.GroovyScriptEngine
import org.slf4j.event.Level
import wow.doge.mygame.implicits._
@SuppressWarnings(Array("org.wartremover.warts.Any"))
object ScriptActor {
/**
@ -126,6 +128,7 @@ object ScriptActor {
}
@SuppressWarnings(Array("org.wartremover.warts.Any"))
class ScriptActor(
val scalaRunner: ammonite.Main,
val kotlinRunner: ScriptActor.KotlinScriptEngine,
@ -137,14 +140,14 @@ class ScriptActor(
def receiveMessage: Behavior[Command] =
Behaviors.receiveMessage {
case CompileAny(path, requester) =>
context.log.debug(s"Received $path")
context.log.debug(show"Received $path")
val res = getScript(path)
context.log.debug(s"result = $res")
context.log.debug(s"result = ${res.toString}")
requester ! res
Behaviors.same
case CompileAll(paths, requester) =>
context.log.debug(s"Received $paths")
context.log.debug(show"Received $paths")
requester ! compileAll(paths)
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.Routers
import akka.util.Timeout
import cats.syntax.show._
import com.typesafe.scalalogging.Logger
import org.slf4j.event.Level
import wow.doge.mygame.implicits._
@ -25,7 +26,7 @@ object ScriptCachingActor {
type ScriptsMap = Map[os.Path, 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
@ -187,7 +188,7 @@ class ScriptCachingActor(
Behaviors.same
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 =
state.modify(_.scriptsMap).using(_ + (scriptPath -> script))
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.SpawnProtocol
import akka.util.Timeout
import cats.effect.Resource
import cats.syntax.eq._
import io.odin.Logger
import monix.bio.Task
import monix.bio.UIO
import wow.doge.mygame.scriptsystem.ScriptCachingActor
import wow.doge.mygame.utils.AkkaUtils
@ -19,6 +23,7 @@ object ScriptInitMode {
}
class ScriptSystemResource(
path: os.Path,
logger: Logger[Task],
mode: ScriptInitMode = ScriptInitMode.Lazy
)(implicit
spawnProtocol: ActorRef[SpawnProtocol.Command],
@ -36,13 +41,17 @@ class ScriptSystemResource(
)
} yield scriptCacheActor
val init2: Resource[UIO, ScriptCompiler] = for {
sc <- ScriptCompiler(logger)
} yield sc
def findScriptFiles(wd: os.Path) =
os.walk
.stream(wd)
.filter(p =>
os.isFile(p) &&
(p.ext == "sc" || (p.baseName + "." + p.ext)
.contains(".main.kts") || p.ext == "groovy")
(p.ext === "sc" || (p.baseName + "." + p.ext)
.contains(".main.kts") || p.ext === "groovy")
)
.toList

View File

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

View File

@ -54,7 +54,7 @@ object GenericConsoleStream {
/**
* for future use
*/
case class Config(exclusive: Boolean = false)
final case class Config(exclusive: Boolean = false)
object 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.Behaviors
import akka.actor.typed.scaladsl.TimerScheduler
import cats.syntax.show._
import wow.doge.mygame.implicits._
object GenericTimerActor {
@ -15,9 +16,9 @@ object GenericTimerActor {
case object Start extends Command
case object Stop 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],
messageToSend: T,
timeInterval: FiniteDuration
@ -55,7 +56,7 @@ class GenericTimerActor[T](
val active: Behavior[Command] =
Behaviors.receiveMessage {
case Start =>
ctx.log.warnP(s"Timer-${timerKey.seed}: Timer already started")
ctx.log.warnP(show"Timer-${timerKey.seed}: Timer already started")
Behaviors.same
case Tick =>
props.target ! props.messageToSend

View File

@ -1,33 +1,65 @@
package wow.doge.mygame.utils
import monix.reactive.Observable
import monix.reactive.OverflowStrategy
import cats.kernel.Eq
import cats.syntax.show._
import com.typesafe.scalalogging.Logger
import monix.bio.Task
import monix.execution.Ack
import monix.execution.Cancelable
import monix.execution.cancelables.SingleAssignCancelable
import monix.execution.Ack
import monix.reactive.Observable
import monix.reactive.OverflowStrategy
object MonixDirectoryWatcher {
import 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) =
Observable.create[String](OverflowStrategy.DropNew(50)) { sub =>
import sub.scheduler
Task.deferAction(implicit s =>
Task(
Observable
.create[WatchEvent](OverflowStrategy.DropNew(50)) { sub =>
import sub.scheduler
val c = SingleAssignCancelable()
val c = SingleAssignCancelable()
val myDir = File(path.toString)
val watcher = new RecursiveFileMonitor(myDir) {
override def onCreate(file: File, count: Int) =
println(s"$file got created")
override def onModify(file: File, count: Int) =
// println(s"$file got modified $count times")
if (sub.onNext(file.name) == Ack.Stop) c.cancel()
override def onDelete(file: File, count: Int) =
println(s"$file got deleted")
}
watcher.start()(scheduler)
c := Cancelable(() => watcher.stop())
c
val watcher =
new RecursiveFileMonitor(
File(path.toString),
logger = logger.underlying
) {
override def onCreate(file: File, count: Int) =
// println(show"$file got created")
if (sub.onNext(CreateEvent(file, count)) == 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) =
// println(show"$file got deleted")
if (sub.onNext(DeleteEvent(file, count)) == Ack.Stop)
c.cancel()
}
}
watcher.start()(scheduler)
c := Cancelable(() => watcher.stop())
c
}
.publish
.refCount
)
)
}

View File

@ -15,7 +15,7 @@ object ReaderDemo {
val t2 = r.run("s").rethrow
// 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 fun2: Reader[Int, UIO[Unit]] = Reader(num => UIO(println(num)))

View File

@ -1,6 +1,6 @@
package wow.doge.mygame.utils
case class Display(
final case class Display(
width: Int,
height: Int,
title: String,
@ -18,4 +18,4 @@ object Display {
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
*/
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] {
def add(data: T) = {
def add(data: T) =
children.transform(children =>
Node(data, AtomicAny(LazyList[Tree[T]]())) #:: children
)
}
}
// case object Leaf extends Tree[Nothing]
case class Data(data: Int)
final case class Data(data: Int)
class TreeManager[T] {
// 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 =>
IO.raiseError(AssetLoadError(ex.getMessage))
}
@SuppressWarnings(
Array("org.wartremover.warts.AsInstanceOf", "org.wartremover.warts.Equals")
)
def loadModelAs[T <: Spatial](
path: os.RelPath
)(implicit ct: ClassTag[T]): IO[Error, T] =
@ -28,6 +31,9 @@ class AssetManager(assetManager: jmea.AssetManager) {
UIO(model.asInstanceOf[T])
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] =
IO(assetManager.loadAsset(path.toString))
.onErrorHandleWith {
@ -46,9 +52,9 @@ class AssetManager(assetManager: jmea.AssetManager) {
}
object AssetManager {
sealed trait Error
case class AssetNotFound(message: String) extends Error
case class AssetLoadError(message: String) extends Error
sealed trait Error extends Product with Serializable
final case class AssetNotFound(message: String) extends Error
final case class AssetLoadError(message: String) extends Error
case object CouldNotCastError extends Error
object Error {
implicit val show = Show.fromToString[Error]

View File

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

View File

@ -1,15 +1,16 @@
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.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 {
import ActorTimeoutTest._
@ -30,7 +31,7 @@ class ActorTimeoutTest extends AnyFunSuite with BeforeAndAfterAll {
object ActorTimeoutTest {
object MyActor {
sealed trait Command
case class GetInt(replyTo: ActorRef[Int]) extends Command
final case class GetInt(replyTo: ActorRef[Int]) extends Command
class Props() {
def create =

View File

@ -1,21 +1,17 @@
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 com.jme3.scene.Node
import cats.syntax.all._
import com.jme3.anim.AnimComposer
import com.jme3.anim.SkinningControl
import com.jme3.anim.tween.action.BaseAction
import com.jme3.anim.tween.Tweens
import scala.jdk.javaapi.CollectionConverters._
import com.jme3.anim.tween.Tween
import com.jme3.anim.tween.action.BaseAction
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 {
import monix.execution.Scheduler.Implicits.global

View File

@ -1,18 +1,19 @@
package wow.doge.mygame
import org.scalatest.funsuite.AnyFunSuite
import monix.execution.Scheduler.Implicits.global
import scala.annotation.nowarn
import cats.syntax.eq._
import com.jme3.{asset => jmea}
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.AssetNotFound
import com.jme3.scene.Geometry
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 right in class Either is deprecated")

View File

@ -1,15 +1,17 @@
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 wow.doge.mygame.utils.wrappers.jme.CollisionShapeFactory
import monix.execution.Scheduler.Implicits.global
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 {
test("Test for WrongArgumentError") {

View File

@ -1,30 +1,62 @@
package wow.doge.mygame
import org.scalatest.funsuite.AnyFunSuite
import cats.effect.{Resource => CResource}
import monix.eval.Task
import scala.concurrent.duration._
class FileWatcherTest extends AnyFunSuite {
test("1") {
import better.files._
import io.methvin.better.files._
import cats.syntax.show._
import monix.bio.IO
import monix.eval.Task
import monix.reactive.Observable
import org.scalatest.funsuite.AnyFunSuite
import wow.doge.mygame.implicits._
import wow.doge.mygame.utils.MonixDirectoryWatcher
val myDir =
File((os.pwd / "assets" / "scripts").toString)
val watcher = new RecursiveFileMonitor(myDir) {
override def onCreate(file: File, count: Int) =
println(s"$file got created")
override def onModify(file: File, count: Int) =
println(s"$file got modified $count times")
override def onDelete(file: File, count: Int) =
println(s"$file got deleted")
}
class FileWatcherTest extends AnyFunSuite {
// test("1") {
// import better.files._
// import io.methvin.better.files._
// val myDir =
// File((os.pwd / "assets" / "scripts").toString)
// val watcher = new RecursiveFileMonitor(myDir) {
// 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
CResource
.make(Task { watcher.start(); watcher })(w => Task(w.stop()))
.use(_ => Task.never)
.runSyncUnsafe(10.seconds)
obsT
.flatMap(
_.takeUntil(Observable.unit.delayExecution(2.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
import org.scalatest.funsuite.AnyFunSuite
import wow.doge.mygame.math.ImVector3f
import com.typesafe.scalalogging.LazyLogging
import cats.syntax.eq._
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 {
test("maxvalue") {

View File

@ -1,11 +1,11 @@
package wow.doge.mygame
import org.scalatest.funsuite.AnyFunSuite
import wow.doge.mygame.subsystems.moddingsystem.ModdingSystem
import monix.execution.Scheduler.Implicits.global
import cats.syntax.eq._
import io.circe.Printer
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 {
val printer = Printer.spaces2

View File

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

View File

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