diff --git a/build.sbt b/build.sbt
index 6072f63..d0f09ae 100644
--- a/build.sbt
+++ b/build.sbt
@@ -21,6 +21,7 @@ scalaVersion := "2.13.3"
resolvers += "Jcenter" at "https://jcenter.bintray.com/"
resolvers += "JME Bintray" at "https://bintray.com/jmonkeyengine/com.jme3"
+resolvers += "Jitpack" at "https://jitpack.io"
resolvers += Resolver.mavenLocal
resolvers += Resolver.sonatypeRepo("snapshots")
@@ -48,7 +49,7 @@ lazy val root = (project in file(".")).settings(
organization := "wow.doge",
version := "1.0-SNAPSHOT",
libraryDependencies ++= Seq(
- "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2",
+ // "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2",
// https://mvnrepository.com/artifact/org.jmonkeyengine/jme3-core
"org.jmonkeyengine" % "jme3-core" % jmeVersion,
// https://mvnrepository.com/artifact/org.jmonkeyengine/jme3-desktop
@@ -58,23 +59,18 @@ lazy val root = (project in file(".")).settings(
"org.jmonkeyengine" % "jme3-effects" % jmeVersion,
"org.jmonkeyengine" % "jme3-plugins" % jmeVersion,
"org.jmonkeyengine" % "jme3-blender" % jmeVersion,
-// https://mvnrepository.com/artifact/com.github.stephengold/Minie
"com.github.stephengold" % "Minie" % "3.0.0",
-// https://mvnrepository.com/artifact/com.simsilica/zay-es
"com.simsilica" % "zay-es" % "1.2.1",
"org.typelevel" %% "cats-core" % "2.1.1",
"com.lihaoyi" % "ammonite" % "2.2.0" cross CrossVersion.full,
"org.jetbrains.kotlin" % "kotlin-main-kts" % "1.4.10",
"org.jetbrains.kotlin" % "kotlin-scripting-jsr223" % "1.4.10",
"org.codehaus.groovy" % "groovy-all" % "3.0.6" pomOnly (),
- // "wow.doge" % "game" % "1.0-SNAPSHOT",
"org.scalafx" %% "scalafx" % "14-R19",
"com.typesafe.akka" %% "akka-actor-typed" % "2.6.10",
- // "ch.qos.logback" % "logback-classic" % "1.2.3",
"org.typelevel" %% "cats-core" % "2.1.1",
"org.typelevel" %% "cats-effect" % "2.1.4",
"io.monix" %% "monix" % "3.2.2",
- // "io.monix" %% "monix-bio" % "1.0.0",
"io.monix" %% "monix-bio" % "1.1.0",
"io.circe" %% "circe-core" % "0.13.0",
"io.circe" %% "circe-generic" % "0.13.0",
@@ -85,15 +81,21 @@ lazy val root = (project in file(".")).settings(
"com.github.valskalla" %% "odin-monix" % "0.8.1",
"com.github.valskalla" %% "odin-json" % "0.9.1",
"com.softwaremill.macwire" %% "util" % "2.3.7",
- "com.softwaremill.macwire" %% "macros" % "2.3.6" % "provided",
- "com.softwaremill.macwire" %% "macrosakka" % "2.3.6" % "provided",
+ "com.softwaremill.macwire" %% "macros" % "2.3.7" % "provided",
+ // "com.softwaremill.macwire" %% "macrosakka" % "2.3.6" % "provided",
"com.github.valskalla" %% "odin-slf4j" % "0.8.1",
"com.softwaremill.quicklens" %% "quicklens" % "1.6.1",
"org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.0-RC1",
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
"io.circe" %% "circe-config" % "0.8.0",
"com.beachape" %% "enumeratum-circe" % "1.6.1",
- "com.lihaoyi" %% "os-lib" % "0.7.1"
+ "com.lihaoyi" %% "os-lib" % "0.7.1",
+ // "com.jayfella" % "jme-jfx-11" % "1.1.5",
+ "com.github.goxr3plus" % "FX-BorderlessScene" % "4.4.0",
+ "com.github.Oshan96" % "CustomStage" % "v1.3.1",
+ "com.badlogicgames.gdx" % "gdx-ai" % "1.8.2",
+ "org.recast4j" % "recast" % "1.2.5",
+ "org.recast4j" % "detour" % "1.2.5"
),
// Determine OS version of JavaFX binaries
diff --git a/lib/jme-jfx-11-1.1.5.jar b/lib/jme-jfx-11-1.1.5.jar
new file mode 100644
index 0000000..35efab9
Binary files /dev/null and b/lib/jme-jfx-11-1.1.5.jar differ
diff --git a/src/main/scala/com/jayfella/jme/jfx/package.scala b/src/main/scala/com/jayfella/jme/jfx/package.scala
new file mode 100644
index 0000000..36a431c
--- /dev/null
+++ b/src/main/scala/com/jayfella/jme/jfx/package.scala
@@ -0,0 +1,10 @@
+package com.jayfella.jme
+
+package object jfx {
+// object JavaFxUI {
+// def apply(app: Application) = {
+// JavaFxUI.initialize(app)
+// JavaFxUI.getInstance()
+// }
+// }
+}
diff --git a/src/main/scala/com/jme3/animation/package.scala b/src/main/scala/com/jme3/animation/package.scala
index ee24f30..d85f05a 100644
--- a/src/main/scala/com/jme3/animation/package.scala
+++ b/src/main/scala/com/jme3/animation/package.scala
@@ -4,59 +4,69 @@ import com.jme3.input.Action
package object animation {
- implicit class AnimChannelWrap(private val uval: AnimChannel) extends AnyVal {
+ implicit final class AnimChannelWrap(private val uval: AnimChannel)
+ extends AnyVal {
/**
- * Set the current animation that is played by this AnimChannel.
- *
- * See {@link #setAnim(java.lang.String, float)}.
- * The blendTime argument by default is 150 milliseconds.
- *
- * @param action The action (name) of the animation to play
- */
- def setAnim(action: Action): Unit = uval.setAnim(action.name)
-
- /**
- * Set the current animation that is played by this AnimChannel.
- *
- * This resets the time to zero, and optionally blends the animation
- * over blendTime
seconds with the currently playing animation.
- * Notice that this method will reset the control's speed to 1.0.
- *
- * @param action The action (name) of the animation to play
- * @param blendTime The blend time over which to blend the new animation
- * with the old one. If zero, then no blending will occur and the new
- * animation will be applied instantly.
- */
- def setAnim(action: Action, blendTime: Float): Unit = uval.setAnim(action.name, blendTime)
+ * Set the current animation that is played by this AnimChannel.
+ *
+ * See {@link #setAnim(java.lang.String, float)}.
+ * The blendTime argument by default is 150 milliseconds.
+ *
+ * @param action The action (name) of the animation to play
+ */
+ def setAnim(action: Action): Unit = uval.setAnim(action.name)
+ /**
+ * Set the current animation that is played by this AnimChannel.
+ *
+ * This resets the time to zero, and optionally blends the animation
+ * over blendTime
seconds with the currently playing animation.
+ * Notice that this method will reset the control's speed to 1.0.
+ *
+ * @param action The action (name) of the animation to play
+ * @param blendTime The blend time over which to blend the new animation
+ * with the old one. If zero, then no blending will occur and the new
+ * animation will be applied instantly.
+ */
+ def setAnim(action: Action, blendTime: Float): Unit =
+ uval.setAnim(action.name, blendTime)
}
- implicit class AnimEventListenerWrap(private val uval: AnimEventListener) extends AnyVal {
-
+ implicit final class AnimEventListenerWrap(
+ private val uval: AnimEventListener
+ ) extends AnyVal {
+
/**
- * Invoked when an animation "cycle" is done. For non-looping animations,
- * this event is invoked when the animation is finished playing. For
- * looping animations, this even is invoked each time the animation is restarted.
- *
- * @param control The control to which the listener is assigned.
- * @param channel The channel being altered
- * @param action The new animation action that is done.
- */
- def onAnimCycleDone(control: AnimControl, channel: AnimChannel, action: Action): Unit =
+ * Invoked when an animation "cycle" is done. For non-looping animations,
+ * this event is invoked when the animation is finished playing. For
+ * looping animations, this even is invoked each time the animation is restarted.
+ *
+ * @param control The control to which the listener is assigned.
+ * @param channel The channel being altered
+ * @param action The new animation action that is done.
+ */
+ def onAnimCycleDone(
+ control: AnimControl,
+ channel: AnimChannel,
+ action: Action
+ ): Unit =
uval.onAnimCycleDone(control, channel, action.name)
/**
- * Invoked when a animation is set to play by the user on the given channel.
- *
- * @param control The control to which the listener is assigned.
- * @param channel The channel being altered
- * @param action The new animation action set.
- */
- def onAnimChange(control: AnimControl, channel: AnimChannel, action: Action): Unit =
- uval.onAnimChange(control, channel, action.name)
+ * Invoked when a animation is set to play by the user on the given channel.
+ *
+ * @param control The control to which the listener is assigned.
+ * @param channel The channel being altered
+ * @param action The new animation action set.
+ */
+ def onAnimChange(
+ control: AnimControl,
+ channel: AnimChannel,
+ action: Action
+ ): Unit =
+ uval.onAnimChange(control, channel, action.name)
}
-
-}
\ No newline at end of file
+}
diff --git a/src/main/scala/com/jme3/app/package.scala b/src/main/scala/com/jme3/app/package.scala
index 658ea99..027b473 100644
--- a/src/main/scala/com/jme3/app/package.scala
+++ b/src/main/scala/com/jme3/app/package.scala
@@ -5,12 +5,13 @@ package com.jme3
*/
package object app {
- implicit class SimpleApplicationWrap(private val uval: SimpleApplication) extends AnyVal {
+ implicit final class SimpleApplicationWrap(
+ private val uval: SimpleApplication
+ ) extends AnyVal {
//FIXME: proof of concept, remove later
def testWrap: String = uval.hashCode().toString
-
}
}
diff --git a/src/main/scala/com/jme3/input/controls/package.scala b/src/main/scala/com/jme3/input/controls/package.scala
index ac29ed3..803f425 100644
--- a/src/main/scala/com/jme3/input/controls/package.scala
+++ b/src/main/scala/com/jme3/input/controls/package.scala
@@ -5,31 +5,33 @@ package com.jme3.input
*/
package object controls {
- implicit class ActionListenerWrap(private val uval: ActionListener) extends AnyVal {
+ implicit final class ActionListenerWrap(private val uval: ActionListener)
+ extends AnyVal {
/**
- * Called when an input to which this listener is registered to is invoked.
- *
- * @param action The action (name) of the mapping that was invoked
- * @param isPressed True if the action is "pressed", false otherwise
- * @param tpf The time per frame value.
- */
+ * Called when an input to which this listener is registered to is invoked.
+ *
+ * @param action The action (name) of the mapping that was invoked
+ * @param isPressed True if the action is "pressed", false otherwise
+ * @param tpf The time per frame value.
+ */
def onAction(action: Action, keyPressed: Boolean, tpf: Float): Unit =
uval.onAction(action.name, keyPressed, tpf)
}
- implicit class AnalogListenerWrap(private val uval: AnalogListener) extends AnyVal {
+ implicit final class AnalogListenerWrap(private val uval: AnalogListener)
+ extends AnyVal {
/**
- * Called to notify the implementation that an analog event has occurred.
- *
- * The results of KeyTrigger and MouseButtonTrigger events will have tpf
- * == value.
- *
- * @param action The action (name) of the mapping that was invoked
- * @param value Value of the axis, from 0 to 1.
- * @param tpf The time per frame value.
- */
+ * Called to notify the implementation that an analog event has occurred.
+ *
+ * The results of KeyTrigger and MouseButtonTrigger events will have tpf
+ * == value.
+ *
+ * @param action The action (name) of the mapping that was invoked
+ * @param value Value of the axis, from 0 to 1.
+ * @param tpf The time per frame value.
+ */
def onAnalog(action: Action, value: Float, tpf: Float): Unit =
uval.onAnalog(action.name, value, tpf)
}
diff --git a/src/main/scala/com/jme3/input/package.scala b/src/main/scala/com/jme3/input/package.scala
index fff855f..aa51000 100644
--- a/src/main/scala/com/jme3/input/package.scala
+++ b/src/main/scala/com/jme3/input/package.scala
@@ -8,7 +8,8 @@ import com.jme3.input.controls.Trigger
*/
package object input {
- implicit class InputManagerWrap(private val uval: InputManager) extends AnyVal {
+ implicit final class InputManagerWrap(private val uval: InputManager)
+ extends AnyVal {
def addMapping(action: Action, triggers: Trigger*): Unit =
uval.addMapping(action.name, triggers: _*)
def addListener(listener: InputListener, actions: Action*): Unit =
diff --git a/src/main/scala/com/jme3/scene/package.scala b/src/main/scala/com/jme3/scene/package.scala
index 3b6698b..59db398 100644
--- a/src/main/scala/com/jme3/scene/package.scala
+++ b/src/main/scala/com/jme3/scene/package.scala
@@ -33,14 +33,14 @@ package object scene {
def apply(name: String): Node = new Node(name)
}
- implicit class NodeWrap(private val uval: Node) extends AnyVal {
+ implicit final class NodeWrap(private val uval: Node) extends AnyVal {
def getControlMaybe[T <: Control](controlType: Class[T]): Option[T] =
Option(uval.getControl(controlType))
}
- implicit class SpatialWrap(private val uval: Spatial) extends AnyVal {
+ implicit final class SpatialWrap(private val uval: Spatial) extends AnyVal {
def toNode: Either[ClassCastException, Node] =
uval match {
diff --git a/src/main/scala/org/slf4j/impl/StaticLoggerBuilder.scala b/src/main/scala/org/slf4j/impl/StaticLoggerBuilder.scala
index 529ee98..0cb63ea 100644
--- a/src/main/scala/org/slf4j/impl/StaticLoggerBuilder.scala
+++ b/src/main/scala/org/slf4j/impl/StaticLoggerBuilder.scala
@@ -69,6 +69,9 @@ class StaticLoggerBinder extends OdinLoggerBinder[IO] {
case asyncHttpClient
if asyncHttpClient.startsWith("org.asynchttpclient.netty") =>
defaultConsoleLogger.withMinimalLevel(Level.Warn)
+ case s if s.startsWith("com.jayfella.jme.jfx.util.JfxPlatform") =>
+ defaultConsoleLogger.withMinimalLevel(Level.Info)
+
// case s
// if s.startsWith(
// "wow.doge.mygame.subsystems.movement.PlayerMovementEventHandler"
diff --git a/src/main/scala/wow/doge/mygame/Main.scala b/src/main/scala/wow/doge/mygame/Main.scala
index e4c89d1..4a0a3b6 100644
--- a/src/main/scala/wow/doge/mygame/Main.scala
+++ b/src/main/scala/wow/doge/mygame/Main.scala
@@ -2,7 +2,6 @@ package wow.doge.mygame
import scala.concurrent.duration._
-import _root_.monix.bio.Task
import akka.util.Timeout
import cats.effect.ExitCode
import cats.implicits._
@@ -11,17 +10,19 @@ import io.odin._
import io.odin.json.Formatter
import io.odin.syntax._
import wow.doge.mygame.game.GameAppResource
-import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource
import _root_.monix.bio.BIOApp
+import _root_.monix.bio.Task
import _root_.monix.bio.UIO
import cats.effect.Resource
+import scalafx.scene.control.TextArea
+import wow.doge.mygame.utils.GenericConsoleStream
object Main extends BIOApp with MainModule {
import java.util.logging.{Logger => JLogger, Level}
JLogger.getLogger("").setLevel(Level.SEVERE)
implicit val timeout = Timeout(1.second)
- def appResource =
+ def appResource(consoleStream: GenericConsoleStream[TextArea]) =
for {
logger <-
consoleLogger().withAsync(timeWindow = 1.milliseconds) |+|
@@ -31,89 +32,38 @@ object Main extends BIOApp with MainModule {
).withAsync(timeWindow = 1.milliseconds)
jmeScheduler <- jMESchedulerResource
actorSystem <- actorSystemResource2(logger)
- scriptCacheActor <- new ScriptSystemResource(os.pwd, actorSystem)(
- timeout,
- actorSystem.scheduler
- ).make
- // akkaScheduler = actorSystemResource2.scheduler
// consoleTextArea <- Resource.liftF(Task(new TextArea()))
// consoleStream <- wireWith(JFXConsoleStream.textAreaStream _)
- (gameApp) <- {
+ gameApp <- {
// new BulletAppState()
// bas.setThreadingType(Thr)
// gameAppResource(new StatsAppState())
- wire[GameAppResource].get2
+ wire[GameAppResource].get
}
_ <- Resource.liftF(
- new MainApp(logger, gameApp, actorSystem, jmeScheduler)(
+ new MainApp(
+ logger,
+ gameApp,
+ actorSystem,
+ jmeScheduler,
+ schedulers,
+ consoleStream
+ )(
timeout,
actorSystem.scheduler
- ).gameInit
+ ).program
)
- // fib <- Resource.liftF(
- // gameApp
- // .enqueueL(() =>
- // new MainApp(logger, gameApp, actorSystem, jmeScheduler)(
- // timeout,
- // actorSystem.scheduler
- // )
- // )
- // .start
- // )
- // _ <- Resource.liftF(fib.join.flatMap(_.gameInit)
- // app = gameApp
- // inputManager = gameApp.inputManager
- // assetManager = gameApp.assetManager
- // bulletAppState = new BulletAppState()
- // (playerMovementEventBus, playerCameraEventBus) <- new EventsModule2(
- // actorSystem
- // ).resource
- // b1 = playerMovementEventBus
- // b2 = playerCameraEventBus
-
- // playerPos = ImVector3f.ZERO
- // playerNode = None.taggedWith[Player]
- // modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o".taggedWith[Player]
- // playerController <- Resource.liftF {
- // implicit val s = actorSystem.scheduler
- // wire[PlayerController.Props].create.onErrorHandle(err =>
- // logger.error(err.toString())
- // )
- // }
-
- // gameSystemsInitializerFib <- Resource.make(
- // logger.info("creating game systems initializer") >>
- // gameApp
- // .enqueueL(() => wire[GameSystemsInitializer])
- // .start
- // )(c => logger.info("destroying game systems initializer") >> c.cancel)
- // _ <- Resource.liftF(gameSystemsInitializerFib.join.flatMap(_.init))
} yield ()
- // def createPlayerController(
- // playerMovementEventBus: ActorRef[
- // EventBus.Command[PlayerMovementEvent]
- // ],
- // playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]]
- // ): IO[PlayerController.Error, Unit] = {
- // val playerPos = ImVector3f.ZERO
- // val playerNode = None.taggedWith[Player]
- // val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
- // wire[PlayerController.Props].create
- // }
-
def run(args: List[String]): UIO[ExitCode] = {
- // Console.withOut(
- // new JFXConsoleStream(
- // new scalafx.scene.control.TextArea(),
- // new ByteArrayOutputStream(35)
- // )
- // )(())
- appResource
- .use(_ => Task.unit)
- .onErrorHandle(_.printStackTrace())
- .as(ExitCode.Success)
+ lazy val consoleStream = GenericConsoleStream.textAreaStream()
+ Console.withOut(consoleStream)(
+ appResource(consoleStream)
+ .use(_ => Task.unit)
+ .onErrorHandle(_.printStackTrace())
+ .as(ExitCode.Success)
+ )
}
}
diff --git a/src/main/scala/wow/doge/mygame/MainApp.scala b/src/main/scala/wow/doge/mygame/MainApp.scala
index 5bed4f7..b287386 100644
--- a/src/main/scala/wow/doge/mygame/MainApp.scala
+++ b/src/main/scala/wow/doge/mygame/MainApp.scala
@@ -20,7 +20,7 @@ import monix.bio.IO
import monix.bio.Task
import wow.doge.mygame.events.EventBus
import wow.doge.mygame.game.GameApp2
-import wow.doge.mygame.game.nodes.Player
+import wow.doge.mygame.game.nodes.PlayerTag
import wow.doge.mygame.game.nodes.PlayerController
import wow.doge.mygame.game.subsystems.input.GameInputHandler
import wow.doge.mygame.implicits._
@@ -32,12 +32,32 @@ import wow.doge.mygame.game.subsystems.level.DefaultGameLevel
import com.jme3.renderer.ViewPort
import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource
import wow.doge.mygame.subsystems.scriptsystem.ScriptInitMode
+import wow.doge.mygame.launcher.Launcher
+import wow.doge.mygame.executors.Schedulers
+import scalafx.application.JFXApp.PrimaryStage
+import scalafx.geometry.Insets
+import scalafx.scene.Scene
+import scalafx.scene.control.Button
+import scalafx.scene.layout.StackPane
+import scalafx.scene.paint.Color
+import scalafx.scene.shape.Rectangle
+import scalafx.Includes._
+import scala.concurrent.duration._
+import cats.effect.concurrent.Deferred
+import monix.bio.Fiber
+import wow.doge.mygame.launcher.Launcher.LauncherResult
+import scalafx.scene.control.TextArea
+import com.jayfella.jme.jfx.JavaFxUI
+import wow.doge.mygame.utils.GenericConsoleStream
+import java.io.PrintStream
class MainApp(
logger: Logger[Task],
gameApp: GameApp2,
spawnProtocol: ActorSystem[SpawnProtocol.Command],
- jmeThread: monix.execution.Scheduler
+ jmeThread: monix.execution.Scheduler,
+ schedulers: Schedulers,
+ consoleStream: GenericConsoleStream[TextArea]
)(implicit
@annotation.unused timeout: Timeout,
@annotation.unused scheduler: Scheduler
@@ -46,39 +66,96 @@ class MainApp(
lazy val scriptSystemInit =
new ScriptSystemResource(os.pwd, spawnProtocol, ScriptInitMode.Eager).init
- lazy val gameInit: Task[Unit] = for {
- eventsModule <- Task(new EventsModule2(spawnProtocol))
- playerMovementEventBus <- eventsModule.playerMovementEventBusTask
- playerCameraEventBus <- eventsModule.playerCameraEventBusTask
- gameAppFib <- gameApp.start.executeOn(jmeThread).start
- /**
- * schedule a fiber to run on the JME thread and wait for it's completion
- * before proceeding forward, as a signal that JME thread has been
- * initialized, otherwise we'll get NPEs trying to access the fields
- * of the game app
- */
- initFib <- gameApp.enqueueL(() => Task("done")).start
- _ <- initFib.join
- inputManager <- gameApp.inputManager
- assetManager <- gameApp.assetManager
- stateManager <- gameApp.stateManager
- camera <- gameApp.camera
- rootNode <- gameApp.rootNode
- enqueueR <- Task(gameApp.enqueue _)
- viewPort <- gameApp.viewPort
- bulletAppState <- Task(new BulletAppState())
- appScheduler <- Task(gameApp.scheduler)
- // enqueueL <- Task(gameApp.enqueueL _)
- _ <- wire[MainAppDelegate].init(gameApp.scheduler)
- _ <- gameAppFib.join
- } yield ()
+ def gameInit: Task[Fiber[Throwable, Unit]] =
+ for {
+ eventsModule <- Task(new EventsModule2(spawnProtocol))
+ playerMovementEventBus <- eventsModule.playerMovementEventBusTask
+ playerCameraEventBus <- eventsModule.playerCameraEventBusTask
+ gameAppFib <- gameApp.start.executeOn(jmeThread).start
+ /**
+ * schedule a task to run on the JME thread and wait for it's completion
+ * before proceeding forward, as a signal that JME thread has been
+ * initialized, otherwise we'll get NPEs trying to access the fields
+ * of the game app
+ */
+ res <- gameApp.enqueueL(() => Task("done")).flatten
+
+ _ <- logger.info(s"Result = $res")
+ inputManager <- gameApp.inputManager
+ assetManager <- gameApp.assetManager
+ stateManager <- gameApp.stateManager
+ camera <- gameApp.camera
+ rootNode <- gameApp.rootNode
+ enqueueR <- Task(gameApp.enqueue _)
+ viewPort <- gameApp.viewPort
+ _ <- logger.info("before")
+ // jfxUI <- Task(JavaFxUI.initialize(gameApp.app))
+ // .executeOn(gameApp.scheduler) >> Task.sleep(500.millis) >> Task(
+ // JavaFxUI.getInstance()
+ // )
+ // .start
+ jfxUI <- gameApp.jfxUI
+ consoleTextArea <- Task(new TextArea {
+ text = "hello"
+ editable = false
+ wrapText = true
+ // maxHeight = 150
+ // maxWidth = 300
+ })
+ _ <- Task(consoleStream := consoleTextArea)
+ _ <- Task(jfxUI += consoleTextArea)
+ // consoleStream <- Task(
+ // GenericConsoleStream.textAreaStream(consoleTextArea)
+ // )
+ _ <- logger.info("after")
+ bulletAppState <- Task(new BulletAppState())
+ _ <- Task(stateManager.attach(bulletAppState))
+ _ <- logger.info("Initializing console stream")
+ // _ <- Task(GenericConsoleStream.textAreaStream(consoleTextArea)).bracket(
+ // consoleStream =>
+ // Task { System.setOut(consoleStream) } >> wire[MainAppDelegate]
+ // .init(gameApp.scheduler, consoleStream)
+ // // consoleLogger
+ // // Console.withOut(consoleStream)(
+ // // wire[MainAppDelegate].init(gameApp.scheduler, consoleStream)
+ // // )
+ // )(stream => Task(stream.close()).onErrorHandle(_.printStackTrace()))
+ // _ <- Task { System.setOut(new PrintStream(consoleStream, true)) }
+ // _ <- Task {
+ // Console.withOut(consoleStream)(println("hello"))
+ // }
+ _ <- wire[MainAppDelegate].init(gameApp.scheduler)
+ } yield (gameAppFib)
lazy val program = for {
scriptSystem <- scriptSystemInit
- game <- gameInit
+ /**
+ * Signal for synchronization between the JavaFX launcher and the in-game JavaFX GUI
+ * Without this, we get a "Toolkit already initialized" excResult. The launch button
+ * in the launcher completes the signal. The game init process which listens for this
+ * signal can then continue
+ */
+ launchSignal <- Deferred[Task, Launcher.LauncherResult]
+ launcher <- new Launcher.Props(schedulers, launchSignal).create
+ cancelToken <- launcher.init()
+ launchResult <- launchSignal.get
+ _ <- cancelToken.cancel
+ _ <-
+ if (launchResult == LauncherResult.Exit)
+ logger.info("Exiting")
+ else gameInit.flatMap(_.join)
+ // _ <- Task.sleep(2000.millis)
+ // gameAppFib <- gameInit
+ /**
+ * Wait for game window to close
+ */
+ // _ <- gameAppFib.join
} yield ()
}
+/**
+ * Class with all dependencies in one place for easy wiring
+ */
class MainAppDelegate(
gameApp: GameApp2,
spawnProtocol: ActorSystem[SpawnProtocol.Command],
@@ -101,16 +178,20 @@ class MainAppDelegate(
@annotation.unused scheduler: Scheduler
) {
- def init(appScheduler: monix.execution.Scheduler) =
+ def init(
+ appScheduler: monix.execution.Scheduler
+ // consoleStream: GenericConsoleStream[TextArea]
+ ) =
for {
_ <- loggerL.info("Initializing Systems")
- _ <- Task(stateManager.attach(bulletAppState))
_ <- Task(
assetManager.registerLocator(
(os.rel / "assets" / "town.zip"),
classOf[ZipLocator]
)
)
+ _ <- loggerL.info("test hmm")
+ // _ <- Task(consoleStream.println("text"))
_ <- DefaultGameLevel(assetManager, viewPort)
.addToGame(
rootNode,
@@ -131,7 +212,7 @@ class MainAppDelegate(
@annotation.unused
val playerPos = ImVector3f.ZERO
@annotation.unused
- val playerNode = None.taggedWith[Player]
+ val playerNode = None.taggedWith[PlayerTag]
@annotation.unused
val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
wire[PlayerController.Props].create
diff --git a/src/main/scala/wow/doge/mygame/game/GameApp.scala b/src/main/scala/wow/doge/mygame/game/GameApp.scala
index b364403..fc29785 100644
--- a/src/main/scala/wow/doge/mygame/game/GameApp.scala
+++ b/src/main/scala/wow/doge/mygame/game/GameApp.scala
@@ -16,81 +16,26 @@ import wow.doge.mygame.executors.GUIExecutorService
import wow.doge.mygame.executors.Schedulers
class GameApp(
- // actorSystem: ActorSystem[SpawnProtocol.Command],
schedulers: Schedulers,
appStates: AppState*
) extends SimpleApplication(appStates: _*) {
import GameApp._
- // implicit val timeout = Timeout(10.seconds)
- // implicit val scheduler = actorSystem.scheduler
- // private lazy val taskQueueS = new ConcurrentLinkedQueue[MyTask[_]]()
+ /**
+ * A non blocking synchronized queue using an immutable scala queue and monix's atomic class
+ */
private lazy val taskQueue2 = Atomic(Queue.empty[MyTask[_]])
private val tickSubject =
ConcurrentSubject[Float](multicast = MulticastStrategy.publish)(
schedulers.async
)
- // (scheduler)
-
- override def simpleInitApp(): Unit = {
-
- println("gameapp" + Thread.currentThread().getName())
-
- // val ship = ed.createEntity()
- // val mbState = stateManager().state[EntityDataState]().map(_.getEntityData())
- // val mbState = Try(
- // stateManager()
- // .state[TestAppState]()
- // .entity
- // ).toOption.flatten.toRight(println("empty"))
- // // .flatMap(_.entity)
- // val x = mbState.flatMap(
- // _.query
- // .filter[TestComponent]("name", new Object())
- // // .filterOr[TestEntity](
- // // Filters
- // // .fieldEquals(classOf[TestEntity], "", null)
- // // )
- // .component[Tag]()
- // .component[TestComponent]()
- // .result
- // .toRight(println("failed"))
- // )
-
- // rootNode
- // .child(geom)
- // .child(geom)
- // .child(geom)
- // .child(geom)
- // .child(geom)
- // .child(geom)
- // .child(geom)
- // .child(geom)
- // Future(println("hello"))(jmeEC(this))
- // val wbActor: Future[ActorRef[Greeter.Greet]] = actorSystem.ask(
- // SpawnProtocol.Spawn(
- // behavior = Greeter(),
- // name = "listener",
- // DispatcherSelector.fromConfig("jme-dispatcher"),
- // _
- // )
- // )
-
- // wbActor.map(a => a.ask(Greeter.Greet("hello", _)).map(println))
-
- }
def tickObservable: Observable[Float] = tickSubject
- override def simpleUpdate(tpf: Float): Unit = {
- // val rot2 = rot.fromAngleAxis(FastMath.PI, new Vector3f(0, 0, 1))
- // val rotation = geom.getLocalRotation()
- // rotation.add(rot2)
- // geom.rotate(rot2)
+ override def simpleInitApp(): Unit = {}
- // geom.updateModelBound()
- // geom.updateGeometricState()
+ override def simpleUpdate(tpf: Float): Unit = {
tickSubject.onNext(tpf)
}
@@ -101,32 +46,14 @@ class GameApp(
def enqueueScala[T](cb: () => T): CancelableFuture[T] = {
val p = Promise[T]()
- // p.success(cb())
- // taskQueueS.add(MyTask(p, cb))
taskQueue2.transform(_ :+ MyTask(p, cb))
p.future
}
-// taskQueue2.transform(_ :+ MyTask(p, cb))
-// p
+
def enqueueL[T](cb: () => T): Task[T] =
- // Task(Promise[T]()).flatMap { p =>
- // Task(taskQueue2.transform(_ :+ MyTask(p, cb))) >>
- // Task.fromCancelablePromise(p)
- // }
- // Task.fromCancelablePromise {
- // val p = Promise[T]()
- // taskQueue2.transform(_ :+ MyTask(p, cb))
- // p
- // }
Task.deferFuture(enqueueScala(cb))
- // taskQueueS.add(MyTask(p, cb))
-
override protected def runQueuedTasks(): Unit = {
- // Option(taskQueueS.poll()).foreach {
- // case MyTask(p, cb) =>
- // p.success(cb())
- // }
taskQueue2.transform { current =>
current.dequeueOption.fold(current) {
case (MyTask(p, cb), updated) =>
@@ -139,8 +66,9 @@ class GameApp(
}
object JMEExecutorService extends GUIExecutorService {
- override def execute(command: Runnable) =
- enqueue(command)
+ override def execute(command: Runnable): Unit =
+ enqueueScala(() => command.run())
+ // enqueue(command)
// new SingleThreadEventExecutor()
// sys.addShutdownHook(JMEExecutorService.shutdown())
}
@@ -150,3 +78,55 @@ class GameApp(
object GameApp {
private[game] case class MyTask[T](p: Promise[T], cb: () => T)
}
+
+// val ship = ed.createEntity()
+// val mbState = stateManager().state[EntityDataState]().map(_.getEntityData())
+// val mbState = Try(
+// stateManager()
+// .state[TestAppState]()
+// .entity
+// ).toOption.flatten.toRight(println("empty"))
+// // .flatMap(_.entity)
+// val x = mbState.flatMap(
+// _.query
+// .filter[TestComponent]("name", new Object())
+// // .filterOr[TestEntity](
+// // Filters
+// // .fieldEquals(classOf[TestEntity], "", null)
+// // )
+// .component[Tag]()
+// .component[TestComponent]()
+// .result
+// .toRight(println("failed"))
+// )
+
+// rootNode
+// .child(geom)
+// .child(geom)
+// .child(geom)
+// .child(geom)
+// .child(geom)
+// .child(geom)
+// .child(geom)
+// .child(geom)
+// Future(println("hello"))(jmeEC(this))
+// val wbActor: Future[ActorRef[Greeter.Greet]] = actorSystem.ask(
+// SpawnProtocol.Spawn(
+// behavior = Greeter(),
+// name = "listener",
+// DispatcherSelector.fromConfig("jme-dispatcher"),
+// _
+// )
+// )
+
+// wbActor.map(a => a.ask(Greeter.Greet("hello", _)).map(println))
+
+// Task(Promise[T]()).flatMap { p =>
+// Task(taskQueue2.transform(_ :+ MyTask(p, cb))) >>
+// Task.fromCancelablePromise(p)
+// }
+// Task.fromCancelablePromise {
+// val p = Promise[T]()
+// taskQueue2.transform(_ :+ MyTask(p, cb))
+// p
+// }
diff --git a/src/main/scala/wow/doge/mygame/game/GameApp2.scala b/src/main/scala/wow/doge/mygame/game/GameApp2.scala
index e3c231f..54a9f28 100644
--- a/src/main/scala/wow/doge/mygame/game/GameApp2.scala
+++ b/src/main/scala/wow/doge/mygame/game/GameApp2.scala
@@ -6,11 +6,16 @@ import com.jme3.asset.AssetManager
import com.jme3.input.InputManager
import monix.bio.IO
import monix.bio.Task
+import com.jme3.scene.Node
+import monix.catnap.Semaphore
+import com.jme3.scene.Spatial
+import wow.doge.mygame.game.GameApp2.SynchedObject
+import wow.doge.mygame.game.subsystems.ui.JFxUI
sealed trait Error
case object FlyCamNotExists extends Error
-class GameApp2(app: GameApp) {
+class GameApp2(val app: GameApp) {
def stateManager: Task[AppStateManager] = Task(app.getStateManager())
def inputManager: Task[InputManager] = Task(app.getInputManager())
def assetManager: Task[AssetManager] = Task(app.getAssetManager())
@@ -22,6 +27,7 @@ class GameApp2(app: GameApp) {
def camera = Task(app.getCamera())
def viewPort = Task(app.getViewPort())
def rootNode = Ref[Task].of(app.getRootNode())
+ def rootNode2 = SynchedObject(app.getRootNode())
def enqueue(cb: () => Unit) =
app.enqueue(new Runnable {
override def run() = cb()
@@ -31,5 +37,35 @@ class GameApp2(app: GameApp) {
def start = Task(app.start())
def stop = Task(app.stop())
def scheduler = app.scheduler
+ def jfxUI = JFxUI(app)
}
+
+object GameApp2 {
+
+ class WrappedNode(node: Node, lock: Semaphore[Task]) {
+
+ def +=(spat: Spatial) = lock.withPermit(Task(node.attachChild(spat)))
+ }
+
+ /**
+ * Synchronization wrapper for a mutable object
+ *
+ * @param obj the mutable object
+ * @param lock lock for synchronization
+ */
+ class SynchedObject[A](obj: A, lock: Semaphore[Task]) {
+ def modify(f: A => Unit): Task[Unit] =
+ lock.withPermit(Task(f(obj)))
+
+ def flatModify(f: A => Task[Unit]): Task[Unit] =
+ lock.withPermit(f(obj))
+
+ def get: Task[A] = lock.withPermit(Task(obj))
+ }
+
+ object SynchedObject {
+ def apply[A](obj: A) =
+ Semaphore[Task](1).flatMap(lock => Task(new SynchedObject(obj, lock)))
+ }
+}
diff --git a/src/main/scala/wow/doge/mygame/game/GameModule.scala b/src/main/scala/wow/doge/mygame/game/GameModule.scala
index 7aabcdc..c7378e2 100644
--- a/src/main/scala/wow/doge/mygame/game/GameModule.scala
+++ b/src/main/scala/wow/doge/mygame/game/GameModule.scala
@@ -17,7 +17,7 @@ class GameAppResource(
jmeScheduler: Scheduler,
schedulers: Schedulers
) {
- def get: Resource[Task, (GameApp2, Fiber[Throwable, Unit])] =
+ def get2: Resource[Task, (GameApp2, Fiber[Throwable, Unit])] =
Resource.make(
for {
_ <- logger.info("Creating game app")
@@ -37,7 +37,7 @@ class GameAppResource(
} yield (app2 -> fib)
)(logger.info("Closing game app") >> _._2.cancel)
- def get2: Resource[Task, GameApp2] =
+ def get: Resource[Task, GameApp2] =
Resource.make(
for {
_ <- logger.info("Creating game app")
@@ -45,9 +45,12 @@ class GameAppResource(
app2 <- Task {
val settings = new AppSettings(true)
settings.setVSync(true)
- settings.setUseInput(true)
- // new FlyCamAppState
- // settings.setFrameRate(250)
+
+ /**
+ * disables the launcher
+ * We'll be making our own launcher anyway
+ */
+ app.setShowSettings(false)
app.setSettings(settings)
// JMERunner.runner = app
new GameApp2(app)
diff --git a/src/main/scala/wow/doge/mygame/game/GameSystemsInitializer.scala b/src/main/scala/wow/doge/mygame/game/GameSystemsInitializer.scala
index 90f1dc7..ead2fc0 100644
--- a/src/main/scala/wow/doge/mygame/game/GameSystemsInitializer.scala
+++ b/src/main/scala/wow/doge/mygame/game/GameSystemsInitializer.scala
@@ -22,7 +22,7 @@ import monix.bio.IO
import monix.bio.Task
import monix.reactive.Consumer
import wow.doge.mygame.events.EventBus
-import wow.doge.mygame.game.nodes.Player
+import wow.doge.mygame.game.nodes.PlayerTag
import wow.doge.mygame.game.nodes.PlayerController
import wow.doge.mygame.game.subsystems.input.GameInputHandler
import wow.doge.mygame.implicits._
@@ -86,7 +86,7 @@ class GameSystemsInitializer(
@annotation.unused
val playerPos = ImVector3f.ZERO
@annotation.unused
- val playerNode = None.taggedWith[Player]
+ val playerNode = None.taggedWith[PlayerTag]
@annotation.unused
val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
wire[PlayerController.Props].create
diff --git a/src/main/scala/wow/doge/mygame/game/nodes/PlayerController.scala b/src/main/scala/wow/doge/mygame/game/nodes/PlayerController.scala
index 7a69d92..2dcc339 100644
--- a/src/main/scala/wow/doge/mygame/game/nodes/PlayerController.scala
+++ b/src/main/scala/wow/doge/mygame/game/nodes/PlayerController.scala
@@ -32,7 +32,7 @@ import wow.doge.mygame.subsystems.movement.ImMovementActor
import wow.doge.mygame.utils.AkkaUtils
// class PlayerNode(val name: String) extends Node(name) {}
-sealed trait Player
+sealed trait PlayerTag
sealed trait PlayerCameraNode
object PlayerController {
@@ -54,7 +54,7 @@ object PlayerController {
],
playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]],
_playerPhysicsControl: Option[BetterCharacterControl],
- _playerNode: Option[Node with Player] = None,
+ _playerNode: Option[Node with PlayerTag] = None,
_cameraNode: Option[CameraNode with PlayerCameraNode] = None,
appScheduler: monix.execution.Scheduler
)(implicit timeout: Timeout, scheduler: Scheduler) {
@@ -68,7 +68,7 @@ object PlayerController {
playerPhysicsControl <- IO(
_playerPhysicsControl
.getOrElse(defaultPlayerPhysicsControl)
- .taggedWith[Player]
+ .taggedWith[PlayerTag]
)
playerNode <- IO.fromEither(
_playerNode.fold(
@@ -179,7 +179,7 @@ object Methods {
def spawnMovementActor(
enqueueR: Function1[() => Unit, Unit],
spawnProtocol: ActorRef[SpawnProtocol.Command],
- movable: BetterCharacterControl @@ Player,
+ movable: BetterCharacterControl @@ PlayerTag,
playerMovementEventBus: ActorRef[
EventBus.Command[PlayerMovementEvent]
],
diff --git a/src/main/scala/wow/doge/mygame/game/nodes/PlayerEventListeners.scala b/src/main/scala/wow/doge/mygame/game/nodes/PlayerEventListeners.scala
index 1b9f7f6..2b49910 100644
--- a/src/main/scala/wow/doge/mygame/game/nodes/PlayerEventListeners.scala
+++ b/src/main/scala/wow/doge/mygame/game/nodes/PlayerEventListeners.scala
@@ -22,7 +22,7 @@ object PlayerMovementEventListener {
Logger[PlayerMovementEventListener.type].underlying
),
Behaviors.setup[PlayerMovementEvent](ctx =>
- Behaviors.receiveMessage {
+ Behaviors.receiveMessagePartial {
case PlayerMovedLeft(pressed) =>
movementActor ! ImMovementActor.MovedLeft(pressed)
Behaviors.same
@@ -69,7 +69,7 @@ object PlayerCameraEventListener {
Logger[PlayerCameraEventListener.type].underlying
),
Behaviors.setup[PlayerCameraEvent](ctx =>
- Behaviors.receiveMessage {
+ Behaviors.receiveMessagePartial {
case CameraMovedUp =>
enqueueR(() => {
diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/ai/GdxAiTest.scala b/src/main/scala/wow/doge/mygame/game/subsystems/ai/GdxAiTest.scala
new file mode 100644
index 0000000..124a72d
--- /dev/null
+++ b/src/main/scala/wow/doge/mygame/game/subsystems/ai/GdxAiTest.scala
@@ -0,0 +1,33 @@
+package wow.doge.mygame.game.subsystems.ai
+
+import com.badlogic.gdx.ai.pfa.Connection
+import wow.doge.mygame.game.subsystems.ai.gdx.MyIndexedGraph
+import scala.collection.immutable.ArraySeq
+// 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)
+ extends Connection[City] {
+
+ override def getCost(): Float = cost
+
+ override def getFromNode(): City = fromNode
+
+ override def getToNode(): City = toNode
+
+}
+
+class CityGraph extends MyIndexedGraph[City] {
+
+ override def getConnections(
+ city: City
+ ): IndexedSeq[Connection[City]] =
+ ArraySeq(Street(City(0f, 0f, "egw", 0), City(0f, 0f, "egw", 0), 1))
+ // or Vector(Street(City(0f, 0f, "egw", 0), City(0f, 0f, "egw", 0), 1))
+
+ override def getIndex(city: City): Int = ???
+
+ override def getNodeCount(): Int = ???
+
+}
diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/ai/gdx/Graph.java b/src/main/scala/wow/doge/mygame/game/subsystems/ai/gdx/Graph.java
new file mode 100644
index 0000000..e62df12
--- /dev/null
+++ b/src/main/scala/wow/doge/mygame/game/subsystems/ai/gdx/Graph.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright 2014 See AUTHORS file.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+package wow.doge.mygame.game.subsystems.ai.gdx;
+
+import com.badlogic.gdx.ai.pfa.Connection;
+
+import com.badlogic.gdx.utils.Array;
+// import java.lang.Iterable;
+import java.util.List;
+import scala.collection.immutable.IndexedSeq;
+
+/**
+ * A graph is a collection of nodes, each one having a collection of outgoing
+ * {@link Connection connections}.
+ *
+ * @param Type of node
+ *
+ * @author davebaol
+ */
+public interface Graph {
+
+ /**
+ * Returns the connections outgoing from the given node.
+ *
+ * @param fromNode the node whose outgoing connections will be returned
+ * @return the array of connections outgoing from the given node.
+ */
+ public IndexedSeq> getConnections(N fromNode);
+}
diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/ai/gdx/IndexedAStarPathFinder.java b/src/main/scala/wow/doge/mygame/game/subsystems/ai/gdx/IndexedAStarPathFinder.java
new file mode 100644
index 0000000..85e7e8a
--- /dev/null
+++ b/src/main/scala/wow/doge/mygame/game/subsystems/ai/gdx/IndexedAStarPathFinder.java
@@ -0,0 +1,371 @@
+/*******************************************************************************
+ * Copyright 2014 See AUTHORS file.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+package wow.doge.mygame.game.subsystems.ai.gdx;
+
+import com.badlogic.gdx.ai.pfa.Connection;
+import com.badlogic.gdx.ai.pfa.GraphPath;
+import com.badlogic.gdx.ai.pfa.Heuristic;
+import com.badlogic.gdx.ai.pfa.PathFinder;
+import com.badlogic.gdx.ai.pfa.PathFinderQueue;
+import com.badlogic.gdx.ai.pfa.PathFinderRequest;
+import com.badlogic.gdx.utils.Array;
+import com.badlogic.gdx.utils.BinaryHeap;
+import com.badlogic.gdx.utils.TimeUtils;
+import java.util.List;
+import wow.doge.mygame.game.subsystems.ai.gdx.Graph;
+import wow.doge.mygame.game.subsystems.ai.gdx.MyIndexedGraph;
+import scala.collection.immutable.IndexedSeq;
+
+/**
+ * A fully implemented {@link PathFinder} that can perform both interruptible
+ * and non-interruptible pathfinding.
+ *
+ * This implementation is a common variation of the A* algorithm that is faster
+ * than the general A*.
+ *
+ * In the general A* implementation, data are held for each node in the open or
+ * closed lists, and these data are held as a NodeRecord instance. Records are
+ * created when a node is first considered and then moved between the open and
+ * closed lists, as required. There is a key step in the algorithm where the
+ * lists are searched for a node record corresponding to a particular node. This
+ * operation is something time-consuming.
+ *
+ * The indexed A* algorithm improves execution speed by using an array of all
+ * the node records for every node in the graph. Nodes must be numbered using
+ * sequential integers (see {@link MyIndexedGraph#getIndex(Object)}), so we
+ * don't need to search for a node in the two lists at all. We can simply use
+ * the node index to look up its record in the array (creating it if it is
+ * missing). This means that the close list is no longer needed. To know whether
+ * a node is open or closed, we use the {@link NodeRecord#category category} of
+ * the node record. This makes the search step very fast indeed (in fact, there
+ * is no search, and we can go straight to the information we need).
+ * Unfortunately, we can't get rid of the open list because we still need to be
+ * able to retrieve the element with the lowest cost. However, we use a
+ * {@link BinaryHeap} for the open list in order to keep performance as high as
+ * possible.
+ *
+ * @param Type of node
+ *
+ * @author davebaol
+ */
+public class IndexedAStarPathFinder implements PathFinder {
+ MyIndexedGraph graph;
+ NodeRecord[] nodeRecords;
+ BinaryHeap> openList;
+ NodeRecord current;
+ public Metrics metrics;
+
+ /** The unique ID for each search run. Used to mark nodes. */
+ private int searchId;
+
+ private static final int UNVISITED = 0;
+ private static final int OPEN = 1;
+ private static final int CLOSED = 2;
+
+ public IndexedAStarPathFinder(MyIndexedGraph graph) {
+ this(graph, false);
+ }
+
+ @SuppressWarnings("unchecked")
+ public IndexedAStarPathFinder(MyIndexedGraph graph, boolean calculateMetrics) {
+ this.graph = graph;
+ this.nodeRecords = (NodeRecord[]) new NodeRecord[graph.getNodeCount()];
+ this.openList = new BinaryHeap>();
+ if (calculateMetrics)
+ this.metrics = new Metrics();
+ }
+
+ @Override
+ public boolean searchConnectionPath(N startNode, N endNode, Heuristic heuristic,
+ GraphPath> outPath) {
+
+ // Perform AStar
+ boolean found = search(startNode, endNode, heuristic);
+
+ if (found) {
+ // Create a path made of connections
+ generateConnectionPath(startNode, outPath);
+ }
+
+ return found;
+ }
+
+ @Override
+ public boolean searchNodePath(N startNode, N endNode, Heuristic heuristic, GraphPath outPath) {
+
+ // Perform AStar
+ boolean found = search(startNode, endNode, heuristic);
+
+ if (found) {
+ // Create a path made of nodes
+ generateNodePath(startNode, outPath);
+ }
+
+ return found;
+ }
+
+ protected boolean search(N startNode, N endNode, Heuristic heuristic) {
+
+ initSearch(startNode, endNode, heuristic);
+
+ // Iterate through processing each node
+ do {
+ // Retrieve the node with smallest estimated total cost from the open list
+ current = openList.pop();
+ current.category = CLOSED;
+
+ // Terminate if we reached the goal node
+ if (current.node == endNode)
+ return true;
+
+ visitChildren(endNode, heuristic);
+
+ } while (openList.size > 0);
+
+ // We've run out of nodes without finding the goal, so there's no solution
+ return false;
+ }
+
+ @Override
+ public boolean search(PathFinderRequest request, long timeToRun) {
+
+ long lastTime = TimeUtils.nanoTime();
+
+ // We have to initialize the search if the status has just changed
+ if (request.statusChanged) {
+ initSearch(request.startNode, request.endNode, request.heuristic);
+ request.statusChanged = false;
+ }
+
+ // Iterate through processing each node
+ do {
+
+ // Check the available time
+ long currentTime = TimeUtils.nanoTime();
+ timeToRun -= currentTime - lastTime;
+ if (timeToRun <= PathFinderQueue.TIME_TOLERANCE)
+ return false;
+
+ // Retrieve the node with smallest estimated total cost from the open list
+ current = openList.pop();
+ current.category = CLOSED;
+
+ // Terminate if we reached the goal node; we've found a path.
+ if (current.node == request.endNode) {
+ request.pathFound = true;
+
+ generateNodePath(request.startNode, request.resultPath);
+
+ return true;
+ }
+
+ // Visit current node's children
+ visitChildren(request.endNode, request.heuristic);
+
+ // Store the current time
+ lastTime = currentTime;
+
+ } while (openList.size > 0);
+
+ // The open list is empty and we've not found a path.
+ request.pathFound = false;
+ return true;
+ }
+
+ protected void initSearch(N startNode, N endNode, Heuristic heuristic) {
+ if (metrics != null)
+ metrics.reset();
+
+ // Increment the search id
+ if (++searchId < 0)
+ searchId = 1;
+
+ // Initialize the open list
+ openList.clear();
+
+ // Initialize the record for the start node and add it to the open list
+ NodeRecord startRecord = getNodeRecord(startNode);
+ startRecord.node = startNode;
+ startRecord.connection = null;
+ startRecord.costSoFar = 0;
+ addToOpenList(startRecord, heuristic.estimate(startNode, endNode));
+
+ current = null;
+ }
+
+ protected void visitChildren(N endNode, Heuristic heuristic) {
+ // Get current node's outgoing connections
+ IndexedSeq> connections = graph.getConnections(current.node);
+
+ // Loop through each connection in turn
+ for (int i = 0; i < connections.size(); i++) {
+ if (metrics != null)
+ metrics.visitedNodes++;
+
+ Connection connection = connections.apply(i);
+
+ // Get the cost estimate for the node
+ N node = connection.getToNode();
+ float nodeCost = current.costSoFar + connection.getCost();
+
+ float nodeHeuristic;
+ NodeRecord nodeRecord = getNodeRecord(node);
+ if (nodeRecord.category == CLOSED) { // The node is closed
+
+ // If we didn't find a shorter route, skip
+ if (nodeRecord.costSoFar <= nodeCost)
+ continue;
+
+ // We can use the node's old cost values to calculate its heuristic
+ // without calling the possibly expensive heuristic function
+ nodeHeuristic = nodeRecord.getEstimatedTotalCost() - nodeRecord.costSoFar;
+ } else if (nodeRecord.category == OPEN) { // The node is open
+
+ // If our route is no better, then skip
+ if (nodeRecord.costSoFar <= nodeCost)
+ continue;
+
+ // Remove it from the open list (it will be re-added with the new cost)
+ openList.remove(nodeRecord);
+
+ // We can use the node's old cost values to calculate its heuristic
+ // without calling the possibly expensive heuristic function
+ nodeHeuristic = nodeRecord.getEstimatedTotalCost() - nodeRecord.costSoFar;
+ } else { // the node is unvisited
+
+ // We'll need to calculate the heuristic value using the function,
+ // since we don't have a node record with a previously calculated value
+ nodeHeuristic = heuristic.estimate(node, endNode);
+ }
+
+ // Update node record's cost and connection
+ nodeRecord.costSoFar = nodeCost;
+ nodeRecord.connection = connection;
+
+ // Add it to the open list with the estimated total cost
+ addToOpenList(nodeRecord, nodeCost + nodeHeuristic);
+ }
+
+ }
+
+ protected void generateConnectionPath(N startNode, GraphPath> outPath) {
+
+ // Work back along the path, accumulating connections
+ // outPath.clear();
+ while (current.node != startNode) {
+ outPath.add(current.connection);
+ current = nodeRecords[graph.getIndex(current.connection.getFromNode())];
+ }
+
+ // Reverse the path
+ outPath.reverse();
+ }
+
+ protected void generateNodePath(N startNode, GraphPath outPath) {
+
+ // Work back along the path, accumulating nodes
+ // outPath.clear();
+ while (current.connection != null) {
+ outPath.add(current.node);
+ current = nodeRecords[graph.getIndex(current.connection.getFromNode())];
+ }
+ outPath.add(startNode);
+
+ // Reverse the path
+ outPath.reverse();
+ }
+
+ protected void addToOpenList(NodeRecord nodeRecord, float estimatedTotalCost) {
+ openList.add(nodeRecord, estimatedTotalCost);
+ nodeRecord.category = OPEN;
+ if (metrics != null) {
+ metrics.openListAdditions++;
+ metrics.openListPeak = Math.max(metrics.openListPeak, openList.size);
+ }
+ }
+
+ protected NodeRecord getNodeRecord(N node) {
+ int index = graph.getIndex(node);
+ NodeRecord nr = nodeRecords[index];
+ if (nr != null) {
+ if (nr.searchId != searchId) {
+ nr.category = UNVISITED;
+ nr.searchId = searchId;
+ }
+ return nr;
+ }
+ nr = nodeRecords[index] = new NodeRecord();
+ nr.node = node;
+ nr.searchId = searchId;
+ return nr;
+ }
+
+ /**
+ * This nested class is used to keep track of the information we need for each
+ * node during the search.
+ *
+ * @param Type of node
+ *
+ * @author davebaol
+ */
+ static class NodeRecord extends BinaryHeap.Node {
+ /** The reference to the node. */
+ N node;
+
+ /** The incoming connection to the node */
+ Connection connection;
+
+ /** The actual cost from the start node. */
+ float costSoFar;
+
+ /** The node category: {@link #UNVISITED}, {@link #OPEN} or {@link #CLOSED}. */
+ int category;
+
+ /** ID of the current search. */
+ int searchId;
+
+ /** Creates a {@code NodeRecord}. */
+ public NodeRecord() {
+ super(0);
+ }
+
+ /** Returns the estimated total cost. */
+ public float getEstimatedTotalCost() {
+ return getValue();
+ }
+ }
+
+ /**
+ * A class used by {@link IndexedAStarPathFinder} to collect search metrics.
+ *
+ * @author davebaol
+ */
+ public static class Metrics {
+ public int visitedNodes;
+ public int openListAdditions;
+ public int openListPeak;
+
+ public Metrics() {
+ }
+
+ public void reset() {
+ visitedNodes = 0;
+ openListAdditions = 0;
+ openListPeak = 0;
+ }
+ }
+}
diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/ai/gdx/MyIndexedGraph.java b/src/main/scala/wow/doge/mygame/game/subsystems/ai/gdx/MyIndexedGraph.java
new file mode 100644
index 0000000..652700b
--- /dev/null
+++ b/src/main/scala/wow/doge/mygame/game/subsystems/ai/gdx/MyIndexedGraph.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright 2014 See AUTHORS file.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+package wow.doge.mygame.game.subsystems.ai.gdx;
+
+import wow.doge.mygame.game.subsystems.ai.gdx.Graph;
+
+/**
+ * A graph for the {@link IndexedAStarPathFinder}.
+ *
+ * @param Type of node
+ *
+ * @author davebaol
+ */
+public interface MyIndexedGraph extends Graph {
+
+ /**
+ * Returns the unique index of the given node.
+ *
+ * @param node the node whose index will be returned
+ * @return the unique index of the given node.
+ */
+ public int getIndex(N node);
+
+ /** Returns the number of nodes in this graph. */
+ public int getNodeCount();
+
+}
diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala b/src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala
index ca82781..b8457d7 100644
--- a/src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala
+++ b/src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala
@@ -65,30 +65,6 @@ object GameInputHandler {
def setupKeys(inputManager: InputManager) =
inputManager
- // .withMapping(
- // PlayerMovementInput.WalkLeft.entryName,
- // new KeyTrigger(KeyInput.KEY_A)
- // // new KeyTrigger(KeyInput.KEY_LEFT)
- // )
- // .withMapping(
- // PlayerMovementInput.WalkRight.entryName,
- // new KeyTrigger(KeyInput.KEY_D)
- // // new KeyTrigger(KeyInput.KEY_RIGHT)
- // )
- // .withMapping(
- // PlayerMovementInput.WalkForward.entryName,
- // new KeyTrigger(KeyInput.KEY_W)
- // // new KeyTrigger(KeyInput.KEY_UP)
- // )
- // .withMapping(
- // PlayerMovementInput.WalkBackward.entryName,
- // new KeyTrigger(KeyInput.KEY_S)
- // // new KeyTrigger(KeyInput.KEY_DOWN)
- // )
- // .withMapping(
- // PlayerMovementInput.Jump.entryName,
- // new KeyTrigger(KeyInput.KEY_SPACE)
- // )
.withMapping(
PlayerAnalogInput.TurnRight.entryName,
new KeyTrigger(KeyInput.KEY_RIGHT),
diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/level/DefaultGameLevel.scala b/src/main/scala/wow/doge/mygame/game/subsystems/level/DefaultGameLevel.scala
index fb55178..d1eeacc 100644
--- a/src/main/scala/wow/doge/mygame/game/subsystems/level/DefaultGameLevel.scala
+++ b/src/main/scala/wow/doge/mygame/game/subsystems/level/DefaultGameLevel.scala
@@ -17,8 +17,8 @@ object DefaultGameLevel {
lazy val sceneModel: Spatial = assetManager.loadModel("main.scene")
lazy val sceneShape = CollisionShapeFactory.createMeshShape(
sceneModel.toNode match {
- case util.Right(node) => node
- case util.Left(ex) =>
+ case Right(node) => node
+ case Left(ex) =>
throw new NotImplementedError("No fallback sceneshape")
}
)
@@ -40,7 +40,7 @@ object DefaultGameLevel {
dl.setColor(ColorRGBA.White);
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
// app.rootNode.addLight(dl);
- new Level(
+ new GameLevel(
model = sceneModel,
physicsControl = landscape,
ambientLight = al,
diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/level/Level.scala b/src/main/scala/wow/doge/mygame/game/subsystems/level/GameLevel.scala
similarity index 79%
rename from src/main/scala/wow/doge/mygame/game/subsystems/level/Level.scala
rename to src/main/scala/wow/doge/mygame/game/subsystems/level/GameLevel.scala
index a5ca94e..c260071 100644
--- a/src/main/scala/wow/doge/mygame/game/subsystems/level/Level.scala
+++ b/src/main/scala/wow/doge/mygame/game/subsystems/level/GameLevel.scala
@@ -10,7 +10,7 @@ import monix.bio.Task
import com.jme3.scene.Node
import wow.doge.mygame.implicits._
-class Level(
+class GameLevel(
model: Spatial,
physicsControl: RigidBodyControl,
ambientLight: AmbientLight,
@@ -19,14 +19,8 @@ class Level(
def addToGame(rootNode: Ref[Task, Node], physicsSpace: PhysicsSpace) = {
for {
_ <- rootNode.update(_ :+ model)
- _ <- rootNode.update { r =>
- r.addLight(ambientLight)
- r
- }
- _ <- rootNode.update { r =>
- r.addLight(directionalLight)
- r
- }
+ _ <- rootNode.update(_ :+ ambientLight)
+ _ <- rootNode.update(_ :+ directionalLight)
_ <- Task(physicsSpace += model)
_ <- Task(physicsSpace += physicsControl)
} yield ()
diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/ui/JmeJfx.scala b/src/main/scala/wow/doge/mygame/game/subsystems/ui/JmeJfx.scala
new file mode 100644
index 0000000..5bf3cfc
--- /dev/null
+++ b/src/main/scala/wow/doge/mygame/game/subsystems/ui/JmeJfx.scala
@@ -0,0 +1,43 @@
+package wow.doge.mygame.game.subsystems.ui
+
+import com.jme3.app.Application
+import com.jayfella.jme.jfx.JavaFxUI
+import scalafx.application.Platform
+import monix.execution.CancelablePromise
+import monix.bio.Task
+import cats.effect.concurrent.Deferred
+import scala.concurrent.duration._
+import wow.doge.mygame.game.GameApp
+
+object JFxUI {
+ def apply(app: GameApp) =
+ Task(JavaFxUI.initialize(app))
+ .executeOn(app.scheduler) >> Task.sleep(500.millis) >> Task(
+ JavaFxUI.getInstance()
+ )
+ // Task {
+ // Platform.runLater(() => {
+ // println("here jfx")
+ // JavaFxUI.initialize(app)
+ // println("here2 jfx2")
+ // val inst = JavaFxUI.getInstance()
+ // println(inst)
+ // })
+ // }
+ // Task.fromFuture {
+ // val p = CancelablePromise[JavaFxUI]()
+ // Platform.runLater(() => {
+ // println("here")
+ // JavaFxUI.initialize(app)
+ // println("here2")
+ // val inst = JavaFxUI.getInstance()
+ // println(inst)
+ // p.success(inst)
+ // })
+ // p.future
+ // }
+// for {
+// d <- Deferred[Task, JavaFxUI]
+// _ <- Task(JavaFxUI.initialize(app))
+// } yield ()
+}
diff --git a/src/main/scala/wow/doge/mygame/implicits/JavaFXMonixObservables.scala b/src/main/scala/wow/doge/mygame/implicits/JavaFXMonixObservables.scala
new file mode 100644
index 0000000..34b69d6
--- /dev/null
+++ b/src/main/scala/wow/doge/mygame/implicits/JavaFXMonixObservables.scala
@@ -0,0 +1,88 @@
+package wow.doge.mygame.implicits
+
+import javafx.{
+ collections => jfxc,
+ event => jfxe,
+ geometry => jfxg,
+ scene => jfxs,
+ util => jfxu
+}
+import javafx.scene.{input => jfxsi, layout => jfxsl, paint => jfxsp}
+import scalafx.scene.Scene
+import monix.execution.Cancelable
+import monix.reactive.OverflowStrategy
+import monix.reactive.Observable
+import monix.execution.Ack
+import scalafx.scene.control.ButtonBase
+
+object JavaFXMonixObservables {
+
+ implicit final class SceneObservables(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 = {
+ if (sub.onNext(event) == Ack.Stop) c.cancel()
+ }
+ }
+
+ scene.onMousePressed = l
+ c := Cancelable(() =>
+ scene.removeEventHandler(
+ jfxsi.MouseEvent.MOUSE_PRESSED,
+ l
+ )
+ )
+ 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 = {
+ if (sub.onNext(event) == Ack.Stop) c.cancel()
+ }
+ }
+
+ scene.onMouseDragged = l
+ c := Cancelable(() =>
+ scene.removeEventHandler(
+ jfxsi.MouseEvent.MOUSE_DRAGGED,
+ l
+ )
+ )
+ c
+ }
+ }
+ }
+
+ implicit final class OnActionObservable(
+ private val button: ButtonBase
+ ) extends AnyVal {
+ def observableAction(): Observable[jfxe.ActionEvent] = {
+ 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()
+ }
+ }
+
+ button.onAction = l
+ c := Cancelable(() =>
+ button.removeEventHandler(
+ jfxe.ActionEvent.ACTION,
+ l
+ )
+ )
+ c
+ }
+ }
+ }
+}
diff --git a/src/main/scala/wow/doge/mygame/implicits/TestEnum.scala b/src/main/scala/wow/doge/mygame/implicits/TestEnum.scala
deleted file mode 100644
index d568b2b..0000000
--- a/src/main/scala/wow/doge/mygame/implicits/TestEnum.scala
+++ /dev/null
@@ -1,43 +0,0 @@
-package wow.doge.mygame.implicits
-
-import enumeratum._
-
-sealed trait TestEnum extends EnumEntry
-
-object TestEnum extends Enum[TestEnum] {
- val values = findValues
- case object Test2 extends TestEnum
-}
-
-sealed trait Greeting extends EnumEntry
-
-object Greeting extends Enum[Greeting] {
-
- /*
- `findValues` is a protected method that invokes a macro to find all `Greeting` object declarations inside an `Enum`
-
- You use it to implement the `val values` member
- */
- val values = findValues
-
- case object Hello extends Greeting
- case object GoodBye extends Greeting
- case object Hi extends Greeting
- case object Bye extends Greeting
-
-}
-object ObsTest {}
-
-sealed trait PlayerMovementEnum extends EnumEntry {
- def test: String
-}
-
-object PlayerMovementEnum extends Enum[PlayerMovementEnum] {
- val values = findValues
- case object MOVE_RIGHT extends PlayerMovementEnum {
- val test = "hmm"
- }
- case object MOVE_LEFT extends PlayerMovementEnum {
- val test = "mmh"
- }
-}
diff --git a/src/main/scala/wow/doge/mygame/implicits/observables/package.scala b/src/main/scala/wow/doge/mygame/implicits/observables/package.scala
new file mode 100644
index 0000000..d587ffe
--- /dev/null
+++ b/src/main/scala/wow/doge/mygame/implicits/observables/package.scala
@@ -0,0 +1,18 @@
+package wow.doge.mygame.implicits
+
+import javafx.{
+ collections => jfxc,
+ event => jfxe,
+ geometry => jfxg,
+ scene => jfxs,
+ util => jfxu
+}
+import javafx.scene.{input => jfxsi, layout => jfxsl, paint => jfxsp}
+import scalafx.scene.Scene
+import monix.execution.Cancelable
+import monix.reactive.OverflowStrategy
+import monix.reactive.Observable
+import monix.execution.Ack
+import scalafx.scene.control.Button
+
+package object observables {}
diff --git a/src/main/scala/wow/doge/mygame/implicits/package.scala b/src/main/scala/wow/doge/mygame/implicits/package.scala
index 0d76f9b..e670a14 100644
--- a/src/main/scala/wow/doge/mygame/implicits/package.scala
+++ b/src/main/scala/wow/doge/mygame/implicits/package.scala
@@ -6,7 +6,6 @@ import scala.reflect.ClassTag
import akka.actor.typed.ActorRef
import akka.actor.typed.Scheduler
import akka.util.Timeout
-import cats.effect.concurrent.Ref
import com.jme3.app.Application
import com.jme3.app.SimpleApplication
import com.jme3.app.state.AppState
@@ -49,6 +48,8 @@ import monix.reactive.OverflowStrategy
import monix.reactive.observers.Subscriber
import wow.doge.mygame.math.ImVector3f
import wow.doge.mygame.state.MyBaseState
+import com.jme3.light.Light
+import com.jayfella.jme.jfx.JavaFxUI
case class ActionEvent(binding: Action, value: Boolean, tpf: Float)
case class EnumActionEvent[T <: EnumEntry](
@@ -70,7 +71,7 @@ package object implicits {
type PhysicsTickObservable =
Observable[Either[PrePhysicsTickEvent, PhysicsTickEvent]]
- implicit class JMEAppExt(private val app: Application) extends AnyVal {
+ implicit final class JMEAppExt(private val app: Application) extends AnyVal {
def enqueueR(cb: () => Unit) =
app.enqueue(new Runnable {
@@ -78,7 +79,7 @@ package object implicits {
})
}
- implicit class StateManagerExt(private val asm: AppStateManager)
+ implicit final class StateManagerExt(private val asm: AppStateManager)
extends AnyVal {
def state[S <: AppState]()(implicit c: ClassTag[S]): S =
asm.getState(c.runtimeClass.asInstanceOf[Class[S]])
@@ -87,8 +88,9 @@ package object implicits {
}
- implicit class SimpleApplicationExt[T <: SimpleApplication](private val sa: T)
- extends AnyVal {
+ implicit final class SimpleApplicationExt[T <: SimpleApplication](
+ private val sa: T
+ ) extends AnyVal {
def stateManager: AppStateManager = sa.getStateManager()
def inputManager: InputManager = sa.getInputManager()
def assetManager: AssetManager = sa.getAssetManager()
@@ -121,7 +123,8 @@ package object implicits {
}
}
- implicit class AssetManagerExt(private val am: AssetManager) extends AnyVal {
+ implicit final class AssetManagerExt(private val am: AssetManager)
+ extends AnyVal {
def registerLocator(
assetPath: os.RelPath,
locator: Class[_ <: AssetLocator]
@@ -134,13 +137,13 @@ package object implicits {
}
}
- implicit class BulletAppStateExt(private val bas: BulletAppState)
+ implicit final class BulletAppStateExt(private val bas: BulletAppState)
extends AnyVal {
def physicsSpace = bas.getPhysicsSpace()
def speed = bas.getSpeed()
}
- implicit class BetterCharacterControlExt(
+ implicit final class BetterCharacterControlExt(
private val bcc: BetterCharacterControl
) {
def withJumpForce(force: ImVector3f) = {
@@ -149,11 +152,12 @@ package object implicits {
}
}
- implicit class SpatialExt[T <: Spatial](private val spat: T) extends AnyVal {
- def asRef = Ref[Task].of(spat)
+ implicit final class SpatialExt[T <: Spatial](private val spat: T)
+ extends AnyVal {
+ // def asRef = Ref[Task].of(spat)
}
- implicit class NodeExt[T <: Node](private val n: T) extends AnyVal {
+ implicit final class NodeExt[T <: Node](private val n: T) extends AnyVal {
/**
* Attaches the given child
@@ -167,18 +171,13 @@ package object implicits {
}
/**
- * Gets the list of children as a monix observable
- *
- * @return
+ * @return Gets the list of children as a monix observable
*/
- // def children = n.getChildren().asScala.toSeq
def observableChildren =
Observable.fromIterable(n.getChildren().asScala)
/**
- * A copy of the list of children of this node as a lazy list
- *
- * @return
+ * @return A copy of the list of children of this node as a lazy list
*/
def children = LazyList.from(n.getChildren().asScala)
@@ -199,6 +198,11 @@ package object implicits {
n
}
+ def :+(light: Light) = {
+ n.addLight(light)
+ n
+ }
+
def -=(spatial: Spatial) = n.detachChild(spatial)
def :-(spatial: Spatial) = {
@@ -206,6 +210,11 @@ package object implicits {
n
}
+ def :-(light: Light) = {
+ n.removeLight(light)
+ n
+ }
+
def depthFirst(cb: Spatial => Unit) =
n.depthFirstTraversal(new SceneGraphVisitor() {
override def visit(s: Spatial) = cb(s)
@@ -313,7 +322,7 @@ package object implicits {
}
- implicit class CameraNodeExt(private val cn: CameraNode) {
+ implicit final class CameraNodeExt(private val cn: CameraNode) {
def withControlDir(controlDir: ControlDirection) = {
cn.setControlDir(controlDir)
cn
@@ -325,14 +334,15 @@ package object implicits {
}
}
- implicit class EntityDataExt(private val ed: EntityData) extends AnyVal {
+ implicit final class EntityDataExt(private val ed: EntityData)
+ extends AnyVal {
def query = new EntityQuery(ed)
// def entities[T <: EntityComponent](entities: Seq[T])
}
- implicit class EntityExt(private val e: EntityId) extends AnyVal {
+ implicit final class EntityExt(private val e: EntityId) extends AnyVal {
def withComponents(classes: EntityComponent*)(implicit
ed: EntityData
): EntityId = {
@@ -341,7 +351,8 @@ package object implicits {
}
}
- implicit class ActorRefExt[Req](private val a: ActorRef[Req]) extends AnyVal {
+ implicit final class ActorRefExt[Req](private val a: ActorRef[Req])
+ extends AnyVal {
import akka.actor.typed.scaladsl.AskPattern._
/**
@@ -374,7 +385,7 @@ package object implicits {
// ask(replyTo)(timeout, scheduler)
// }
- implicit class InputManagerExt(private val inputManager: InputManager)
+ implicit final class InputManagerExt(private val inputManager: InputManager)
extends AnyVal {
def withMapping(mapping: String, triggers: Trigger*): InputManager = {
inputManager.addMapping(mapping, triggers: _*)
@@ -507,7 +518,7 @@ package object implicits {
}
}
- implicit class PhysicsSpaceExt(private val space: PhysicsSpace)
+ implicit final class PhysicsSpaceExt(private val space: PhysicsSpace)
extends AnyVal {
def collisionObservable(): Observable[PhysicsCollisionEvent] = {
@@ -587,9 +598,11 @@ package object implicits {
space
}
+ // def asRef = Ref[Task].of(space)
+
}
- implicit class Vector3fExt(private val v: Vector3f) extends AnyVal {
+ implicit final class Vector3fExt(private val v: Vector3f) extends AnyVal {
//TODO add more operations
def +=(that: Vector3f) = v.addLocal(that)
def +=(f: Float) = v.addLocal(f, f, f)
@@ -608,7 +621,7 @@ package object implicits {
def immutable = ImVector3f(v.x, v.y, v.z)
}
- implicit class ImVector3fExt(private val v: ImVector3f) extends AnyVal {
+ implicit final class ImVector3fExt(private val v: ImVector3f) extends AnyVal {
def +(that: ImVector3f) = v.copy(v.x + that.x, v.y + that.y, v.z + that.z)
def +(f: Float): ImVector3f = v.copy(v.x + f, v.y + f, v.z + f)
def *(that: ImVector3f) = v.copy(v.x * that.x, v.y * that.y, v.z * that.z)
@@ -628,4 +641,8 @@ package object implicits {
// f.hideErrors
// }
+ implicit final class JavaFxUIExt(private val jfxui: JavaFxUI) extends AnyVal {
+ def +=(node: scalafx.scene.Node) = jfxui.attachChild(node)
+ def -=(node: scalafx.scene.Node) = jfxui.detachChild(node)
+ }
}
diff --git a/src/main/scala/wow/doge/mygame/launcher/DefaultUI.scala b/src/main/scala/wow/doge/mygame/launcher/DefaultUI.scala
new file mode 100644
index 0000000..7dfb948
--- /dev/null
+++ b/src/main/scala/wow/doge/mygame/launcher/DefaultUI.scala
@@ -0,0 +1,102 @@
+package wow.doge.mygame.launcher
+
+import scalafx.geometry.Insets
+import scalafx.scene.Scene
+import scalafx.scene.effect.DropShadow
+import scalafx.scene.layout.HBox
+import scalafx.scene.paint.Color._
+import scalafx.scene.paint._
+import scalafx.scene.text.Text
+import scalafx.scene.control.Button
+import scalafx.scene.layout.VBox
+import scalafx.scene.layout.FlowPane
+import scalafx.geometry.Orientation
+import scalafx.geometry.Pos
+import scalafx.stage.Stage
+
+object DefaultUI {
+ def scene(
+ // stage: Stage,
+ launchButton: Button,
+ exitButton: Button
+ ) =
+ new Scene {
+ fill = Color.rgb(38, 38, 38)
+ content = new VBox {
+ children = Seq(
+ new HBox {
+ padding = Insets(50, 80, 50, 80)
+ children = Seq(
+ new Text {
+ text = "JMonkeyEngine"
+ style = "-fx-font: normal bold 50pt sans-serif"
+ fill = new LinearGradient(endX = 0, stops = Stops(Red, DarkRed))
+ },
+ new Text {
+ text = " Game"
+ style = "-fx-font: italic bold 50pt sans-serif"
+ fill = new LinearGradient(
+ endX = 0,
+ stops = Stops(White, DarkGray)
+ )
+ effect = new DropShadow {
+ color = DarkGray
+ radius = 15
+ spread = 0.25
+ }
+ }
+ )
+ },
+ new FlowPane {
+ hgap = 10
+ padding = Insets(50, 80, 50, 80)
+ orientation = Orientation.Horizontal
+ alignment = Pos.Center
+ children = Seq(launchButton, exitButton)
+ }
+ )
+ }
+ // onMousePressed = (pressEvent) => {
+ // onMouseDragged = (dragEvent) => {
+ // stage.setX(dragEvent.getScreenX() - pressEvent.getSceneX())
+ // stage.setY(dragEvent.getScreenY() - pressEvent.getSceneY())
+ // }
+ // }
+ }
+
+ def box(launchButton: Button, exitButton: Button) =
+ new VBox {
+ children = Seq(
+ new HBox {
+ padding = Insets(50, 80, 50, 80)
+ children = Seq(
+ new Text {
+ text = "JMonkeyEngine"
+ style = "-fx-font: normal bold 50pt sans-serif"
+ fill = new LinearGradient(endX = 0, stops = Stops(Red, DarkRed))
+ },
+ new Text {
+ text = " Game"
+ style = "-fx-font: italic bold 50pt sans-serif"
+ fill = new LinearGradient(
+ endX = 0,
+ stops = Stops(White, DarkGray)
+ )
+ effect = new DropShadow {
+ color = DarkGray
+ radius = 15
+ spread = 0.25
+ }
+ }
+ )
+ },
+ new FlowPane {
+ hgap = 10
+ padding = Insets(50, 80, 50, 80)
+ orientation = Orientation.Horizontal
+ alignment = Pos.Center
+ children = Seq(launchButton, exitButton)
+ }
+ )
+ }
+}
diff --git a/src/main/scala/wow/doge/mygame/launcher/Launcher.scala b/src/main/scala/wow/doge/mygame/launcher/Launcher.scala
new file mode 100644
index 0000000..73671cd
--- /dev/null
+++ b/src/main/scala/wow/doge/mygame/launcher/Launcher.scala
@@ -0,0 +1,153 @@
+package wow.doge.mygame.launcher
+
+import scala.concurrent.duration.FiniteDuration
+import scalafx.application.JFXApp
+import scalafx.application.JFXApp.PrimaryStage
+import wow.doge.mygame.executors.Schedulers
+import cats.effect.Resource
+import monix.bio.Task
+import scala.concurrent.duration._
+import javafx.application.Platform
+import scalafx.scene.control.Button
+import cats.effect.concurrent.Deferred
+import wow.doge.mygame.utils.IOUtils._
+import monix.eval.{Task => ETask}
+import monix.reactive.Observable
+import monix.bio.Fiber
+import scalafx.stage.StageStyle
+import scalafx.Includes._
+import wow.doge.mygame.utils.ResizeHelper
+import scalafx.scene.Scene
+import scalafx.scene.layout.VBox
+import wow.doge.mygame.implicits.JavaFXMonixObservables._
+import monix.catnap.cancelables.SingleAssignCancelableF
+import monix.catnap.CancelableF
+// import wow.doge.mygame.implicits.JavaFXMonixObservables._
+
+// import scala.language.implicitConversions
+
+// object Stage {
+// implicit def sfxStage2jfx(v: Stage): jfxs.Stage = if (v != null) v.delegate else null
+// }
+
+object Launcher {
+ sealed trait LauncherResult
+ object LauncherResult {
+ case object LaunchGame extends LauncherResult
+ case object Exit extends LauncherResult
+ }
+
+ class Props(
+ val schedulers: Schedulers,
+ val signal: Deferred[Task, LauncherResult]
+ ) {
+ // val resource2
+ // : Resource[Task, (LauncherApp, Task[Ref[Task, Stage]], Fiber[Unit])] =
+ // Resource.make(for {
+ // app <- Task(new LauncherApp(this))
+ // fib <- app.init.start
+ // } yield ((app, app.stageRef, fib)))(_._3.cancel)
+ val create = Task(new Launcher(this))
+
+ val resource: Resource[Task, Launcher] =
+ Resource.make(for {
+ app <- Task(new Launcher(this))
+ // fib <- app.init.start
+ } yield (app))(_ => Task.unit)
+ }
+}
+class Launcher private (props: Launcher.Props) {
+ import Launcher._
+
+ private lazy val launchButton = new Button {
+ text = "Launch"
+ }
+ // private lazy val launchButtonObs =
+
+ private lazy val launchAction =
+ launchButton
+ .observableAction()
+ .doOnNext(_ => toTask(props.signal.complete(LauncherResult.LaunchGame)))
+
+ private lazy val exitButton = new Button {
+ text = "Exit"
+ }
+ // private lazy val exitButtonObs =
+
+ private lazy val exitAction =
+ exitButton
+ .observableAction()
+ .doOnNext(_ => toTask(props.signal.complete(LauncherResult.Exit)))
+
+ private lazy val _scene =
+ // new Scene {
+ // content = new VBox
+ // }
+ DefaultUI.scene(launchButton, exitButton)
+
+ private lazy val _stage = new PrimaryStage {
+ scene = _scene
+ }
+
+ private lazy val internal = new JFXApp {
+ stage = _stage
+ stage.initStyle(StageStyle.Undecorated)
+ // ResizeHelper.addResizeListener(stage)
+ }
+
+ private lazy val sceneDragObservable = {
+ lazy val mpo = _scene.observableMousePressed()
+ lazy val mdo = _scene.observableMouseDragged()
+
+ mpo.mergeMap(pressEvent =>
+ mdo.doOnNext(dragEvent =>
+ ETask(
+ _stage.setX(dragEvent.screenX - pressEvent.sceneX)
+ ) >>
+ ETask(
+ _stage.setY(
+ dragEvent.screenY - pressEvent.sceneY
+ )
+ )
+ )
+ )
+ }
+
+ // var stage = internal.stage
+
+ // lazy val stageRef = Ref.of[Task, Stage](internal.stage)
+// stage: => PrimaryStage
+ def init(delay: FiniteDuration = 2000.millis) =
+ for {
+ _ <- Task(Platform.setImplicitExit(false))
+
+ fib <- Task(internal.main(Array.empty)).start
+ _ <- Task.sleep(500.millis)
+ // _ <- Task {
+ // // lazy val _stage = new CustomStageBuilder()
+ // // .setWindowTitle("CustomStage example")
+ // // .setWindowColor("rgb(34,54,122)")
+ // // .build()
+ // internal.stage.scene =
+ // DefaultUI.scene(internal.stage, launchButton, exitButton)
+ // // _stage.setScene(DefaultUI.scene(launchButton, exitButton))
+ // // JFXApp.Stage = _stage
+ // }.executeOn(props.schedulers.fx)
+ // c <- SingleAssignCancelableF[Task]
+ sceneDragFib <- toIO(sceneDragObservable.completedL).start
+ fib2 <- toIO(
+ Observable(launchAction, exitAction).merge
+ .doOnNext(_ =>
+ ETask(internal.stage.close()).executeOn(props.schedulers.fx)
+ )
+ // .doOnNext(_ => toTask(fib.cancel))
+ .completedL
+ ).start
+ c <- CancelableF[Task](fib.cancel >> fib2.cancel >> sceneDragFib.cancel)
+ // _ <- Task {
+ // internal.stage = stage
+ // }.executeOn(props.schedulers.fx)
+ // .delayExecution(delay)
+ } yield (c)
+
+}
diff --git a/src/main/scala/wow/doge/mygame/subsystems/events/MovementEvents.scala b/src/main/scala/wow/doge/mygame/subsystems/events/MovementEvents.scala
index 871c4f6..c6b8e39 100644
--- a/src/main/scala/wow/doge/mygame/subsystems/events/MovementEvents.scala
+++ b/src/main/scala/wow/doge/mygame/subsystems/events/MovementEvents.scala
@@ -3,7 +3,6 @@ package wow.doge.mygame.subsystems.events
import wow.doge.mygame.game.subsystems.movement.CanMove
sealed trait EntityMovementEvent
-
object EntityMovementEvent {
final case class MovedLeft[T: CanMove](pressed: Boolean, movable: T)
extends EntityMovementEvent
@@ -29,5 +28,6 @@ object EntityMovementEvent {
final case object PlayerRotatedLeft extends PlayerMovementEvent
final case object PlayerCameraUp extends PlayerMovementEvent
final case object PlayerCameraDown extends PlayerMovementEvent
+
}
}
diff --git a/src/main/scala/wow/doge/mygame/subsystems/moddingsystem/ModdingSystem.scala b/src/main/scala/wow/doge/mygame/subsystems/moddingsystem/ModdingSystem.scala
index e225134..f85683d 100644
--- a/src/main/scala/wow/doge/mygame/subsystems/moddingsystem/ModdingSystem.scala
+++ b/src/main/scala/wow/doge/mygame/subsystems/moddingsystem/ModdingSystem.scala
@@ -23,9 +23,6 @@ final case class Test1(hello1: String, hello2: String)
final case class Test2(hello1: String)
final case class Plugin(name: String, priority: Int)
object Plugin {
- // @annotation.nowarn(
- // "msg=Block result was adapted via implicit conversion"
- // )
implicit val pluginFormat: Decoder[Plugin] = deriveDecoder
}
diff --git a/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptActor.scala b/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptActor.scala
index f330603..8027fc0 100644
--- a/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptActor.scala
+++ b/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptActor.scala
@@ -29,6 +29,11 @@ object ScriptActor {
result: ActorRef[Either[Error, Any]]
) extends Command
+ final case class CompileAll(
+ paths: Seq[os.Path],
+ result: ActorRef[Map[os.Path, Either[Error, Any]]]
+ ) extends Command
+
lazy val defaultScalaRunner =
ammonite
.Main(
@@ -126,15 +131,18 @@ class ScriptActor(
import ScriptActor._
def receiveMessage: Behavior[Command] =
- Behaviors.receiveMessage { msg =>
- msg match {
- case CompileAny(path, requester) =>
- context.log.debug(s"Received $path")
- val res = getScript(path)
- context.log.debug(s"result = $res")
- requester ! res
- Behaviors.same
- }
+ Behaviors.receiveMessage {
+ case CompileAny(path, requester) =>
+ context.log.debug(s"Received $path")
+ val res = getScript(path)
+ context.log.debug(s"result = $res")
+ requester ! res
+ Behaviors.same
+
+ case CompileAll(paths, requester) =>
+ context.log.debug(s"Received $paths")
+ requester ! compileAll(paths)
+ Behaviors.same
}
def getScript(path: os.Path): Either[Error, Any] =
@@ -148,4 +156,25 @@ class ScriptActor(
case l @ Left(err) => l
}
+ type LOL = Map[os.Path, Either[wow.doge.mygame.state.ScriptActor.Error, Any]]
+
+ def compileAll(
+ paths: Seq[os.Path]
+ ): LOL = {
+ @annotation.tailrec
+ def loop(
+ paths: Seq[os.Path],
+ scriptsMap: Map[
+ os.Path,
+ Either[wow.doge.mygame.state.ScriptActor.Error, Any]
+ ]
+ ): LOL = {
+ paths match {
+ case head :: next => loop(next, scriptsMap + (head -> getScript(head)))
+ case Nil => scriptsMap
+ }
+ }
+ loop(paths, Map.empty)
+ }
+
}
diff --git a/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptCachingActor.scala b/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptCachingActor.scala
index 7e6e3c6..2f90914 100644
--- a/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptCachingActor.scala
+++ b/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptCachingActor.scala
@@ -37,6 +37,11 @@ object ScriptCachingActor {
requester: ActorRef[ScriptResult],
force: Boolean = false
) extends Command
+ // final case class GetAll(
+ // scriptPaths: Seq[os.Path],
+ // requester: ActorRef[Map[os.Path, ScriptResult]],
+ // force: Boolean = false
+ // ) extends Command
final case class GetMap(requester: ActorRef[ScriptsMap]) extends Command
final case class Put(scriptPath: os.Path, script: ScriptObject)
extends Command
@@ -47,6 +52,15 @@ object ScriptCachingActor {
scriptPath: os.Path,
requester: ActorRef[ScriptResult]
) extends Command
+ // private[scriptsystem] final case class DelegateAllToChild(
+ // scriptPaths: Seq[os.Path],
+ // requester: ActorRef[Map[os.Path, ScriptResult]]
+ // ) extends Command
+
+ // private[scriptsystem] final case class ReplyWithPrecompiled(
+ // precompiled: Map[os.Path, ScriptResult],
+ // requester: ActorRef[Map[os.Path, ScriptResult]]
+ // ) extends Command
// final case class Props(
// ctx: ActorContext[Command],
@@ -102,6 +116,51 @@ class ScriptCachingActor(
)
Behaviors.same
+ // case GetAll(scriptPaths, requester, force) =>
+ // import scala.concurrent.duration._
+ // implicit val timeout = Timeout(15.seconds)
+
+ // /**
+ // * Holy complexity batman this is getting too complex
+ // */
+ // if (force) {
+ // scriptPaths
+ // .sliding(
+ // if (scriptPaths.length > 3 && scriptPaths.length % 2 == 0) 2
+ // else 3
+ // )
+ // .foreach(lst =>
+ // ctx.self ! DelegateAllToChild(scriptPaths, requester)
+ // )
+ // } else {
+ // val (failures, successes) = scriptPaths
+ // .partitionMap(path =>
+ // state.scriptsMap.get(path) match {
+ // case Some(value) => Right(path -> value)
+ // case None => Left(path)
+ // }
+ // ) match {
+ // case (failures, successes) =>
+ // import cats.syntax.either._
+ // failures -> Map.from(successes.map {
+ // case (p, obj) => p -> obj.asRight[ScriptActor.Error]
+ // })
+ // }
+ // ctx.ask(scriptActor, ScriptActor.CompileAll(failures, _)) {
+ // case Success(value) =>
+ // val total = successes ++ value
+ // requester ! total
+ // value.foreach {
+ // case (path, res) => res.foreach(r => ctx.self ! Put(path, r))
+ // }
+ // NoOp
+ // case Failure(exception) => NoOp
+ // }
+ // }
+ // // scriptPaths.foreach(p => ctx.self ! Get(p))
+
+ // Behaviors.same
+
case DelegateToChild(scriptActor, scriptPath, requester) =>
import scala.concurrent.duration._
implicit val timeout = Timeout(15.seconds)
@@ -114,6 +173,19 @@ class ScriptCachingActor(
)
Behaviors.same
+ // case DelegateAllToChild(scriptPaths, requester) =>
+ // import scala.concurrent.duration._
+ // implicit val timeout = Timeout(15.seconds)
+ // ctx.ask(scriptActor, ScriptActor.CompileAll(scriptPaths, _)) {
+ // case Success(value) =>
+ // value.foreach {
+ // case (path, res) => res.foreach(r => ctx.self ! Put(path, r))
+ // }
+ // NoOp
+ // case Failure(exception) => NoOp
+ // }
+ // Behaviors.same
+
case GetMap(requester) =>
requester ! state.scriptsMap
Behaviors.same
@@ -128,6 +200,7 @@ class ScriptCachingActor(
case NoOp => Behaviors.same
}
}
+
}
object ScriptActorPool {
diff --git a/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptSystemModule.scala b/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptSystemModule.scala
index 04e3171..5214c4e 100644
--- a/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptSystemModule.scala
+++ b/src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptSystemModule.scala
@@ -35,6 +35,7 @@ class ScriptSystemResource(
Resource.liftF(scriptCacheActor)
}
+ // sys.ask(ref => ScriptCachingActor.GetAll(os.pwd/'assets/'scripts/'scala/"hello2.sc",ref, false))
val init = for {
scriptFiles <- Task(findScriptFiles(os.pwd / "assets" / "scripts"))
diff --git a/src/main/scala/wow/doge/mygame/utils/BorderlessScene.scala b/src/main/scala/wow/doge/mygame/utils/BorderlessScene.scala
new file mode 100644
index 0000000..8fe3f0c
--- /dev/null
+++ b/src/main/scala/wow/doge/mygame/utils/BorderlessScene.scala
@@ -0,0 +1,750 @@
+package wow.doge.mygame.utils
+
+/*
+ * Copyright (c) 2011-2019, ScalaFX Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the ScalaFX Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE SCALAFX PROJECT OR ITS CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import javafx.scene.{input => jfxsi, layout => jfxsl, paint => jfxsp}
+import javafx.{
+ collections => jfxc,
+ event => jfxe,
+ geometry => jfxg,
+ scene => jfxs,
+ util => jfxu
+}
+import scalafx.Includes._
+import scalafx.beans.property.{
+ ObjectProperty,
+ ReadOnlyDoubleProperty,
+ ReadOnlyObjectProperty
+}
+import scalafx.collections._
+import scalafx.delegate.SFXDelegate
+import scalafx.geometry.NodeOrientation
+import scalafx.scene.image.WritableImage
+import scalafx.scene.input.{Dragboard, Mnemonic, TransferMode}
+import scalafx.scene.paint.Paint
+import com.goxr3plus.fxborderlessscene.borderless.{BorderlessScene => BScene}
+
+import scala.language.implicitConversions
+import scalafx.scene.Cursor
+import scalafx.scene._
+import scalafx.stage.Stage
+import scalafx.stage.StageStyle
+
+object BorderlessScene {
+ implicit def sfxScene2jfx(v: BorderlessScene): Scene =
+ if (v != null) v.delegate else null
+}
+
+/**
+ * Wraps [[http://docs.oracle.com/javase/8/javafx/api/javafx/scene/Scene.html]].
+ *
+ * @constructor Create a new ScalaFX Scene with JavaFX Scene as delegate.
+ * @param delegate JavaFX Scene delegated. Its default value is a JavaFX Scene with a
+ * [[http://docs.oracle.com/javase/8/javafx/api/javafx/scene/Group.html Group]] as root Node.
+ */
+class BorderlessScene(
+ override val delegate: BScene
+) extends SFXDelegate[BScene] {
+
+ def this(stage: Stage, stageStyle: StageStyle, parent: Parent) =
+ this(new BScene(stage, stageStyle, parent))
+
+ /**
+ * Returns the root Node of the scene graph
+ */
+ def root: ObjectProperty[jfxs.Parent] = delegate.rootProperty
+
+ /**
+ * Sets the root Node of the scene graph
+ */
+ def root_=(v: Parent): Unit = {
+ root() = v
+ }
+
+ /**
+ * Returns Nodes children from this Scene's `root`.
+ */
+ def getChildren =
+ root.value match {
+ case group: jfxs.Group => group.getChildren
+ case pane: jfxsl.Pane => pane.getChildren
+ case _ =>
+ throw new IllegalStateException(
+ "Cannot access children of root: " + root + "\n" +
+ "Use a class that extends Group or Pane, or override the getChildren method."
+ )
+ }
+
+ /**
+ * Returns scene's antialiasing setting.
+ */
+ def antialiasing: SceneAntialiasing = delegate.getAntiAliasing
+
+ /**
+ * Returns Content's Node children from this Scene's `root`.
+ */
+ def content: jfxc.ObservableList[jfxs.Node] = getChildren
+
+ /**
+ * Sets the list of Nodes children from this Scene's `root`, replacing the prior content. If you want append to
+ * current content, use `add` or similar.
+ *
+ * @param c list of Nodes children from this Scene's `root` to replace prior content.
+ */
+ def content_=(c: Iterable[Node]): Unit = {
+ fillSFXCollection(this.content, c)
+ }
+
+ /**
+ * Sets a Node child, replacing the prior content. If you want append to current content, use `add` or similar.
+ *
+ * @param n Node child to replace prior content.
+ */
+ def content_=(n: Node): Unit = {
+ fillSFXCollectionWithOne(this.content, n)
+ }
+
+ /**
+ * Specifies the type of camera use for rendering this `Scene`.
+ */
+ def camera: ObjectProperty[jfxs.Camera] = delegate.cameraProperty
+
+ def camera_=(v: Camera): Unit = {
+ camera() = v
+ }
+
+ /**
+ * Defines the mouse cursor for this `Scene`.
+ */
+ def cursor: ObjectProperty[jfxs.Cursor] = delegate.cursorProperty
+
+ def cursor_=(v: Cursor): Unit = {
+ cursor() = v
+ }
+
+ /** The effective node orientation of a scene resolves the inheritance of node orientation, returning either left-to-right or right-to-left. */
+ def effectiveNodeOrientation: ReadOnlyObjectProperty[jfxg.NodeOrientation] =
+ delegate.effectiveNodeOrientationProperty
+
+ /**
+ * Specifies the event dispatcher for this scene.
+ */
+ def eventDispatcher: ObjectProperty[jfxe.EventDispatcher] =
+ delegate.eventDispatcherProperty
+
+ def eventDispatcher_=(v: jfxe.EventDispatcher): Unit = {
+ eventDispatcher() = v
+ }
+
+ /**
+ * Defines the background fill of this Scene.
+ */
+ def fill: ObjectProperty[jfxsp.Paint] = delegate.fillProperty
+
+ def fill_=(v: Paint): Unit = {
+ fill() = v
+ }
+
+ /**
+ * The height of this Scene
+ */
+ def height: ReadOnlyDoubleProperty = delegate.heightProperty
+
+ /**
+ * The width of this Scene
+ */
+ def width: ReadOnlyDoubleProperty = delegate.widthProperty
+
+ def nodeOrientation: ObjectProperty[jfxg.NodeOrientation] =
+ delegate.nodeOrientationProperty
+
+ def nodeOrientation_=(v: NodeOrientation): Unit = {
+ ObjectProperty.fillProperty[jfxg.NodeOrientation](this.nodeOrientation, v)
+ }
+
+ /**
+ * Defines a function to be called when a mouse button has been clicked (pressed and released) on this `Scene`.
+ */
+ def onContextMenuRequested = delegate.onContextMenuRequestedProperty
+
+ def onContextMenuRequested_=(
+ v: jfxe.EventHandler[_ >: jfxsi.ContextMenuEvent]
+ ): Unit = {
+ onContextMenuRequested() = v
+ }
+
+ /**
+ * Defines a function to be called when drag gesture has been detected.
+ */
+ def onDragDetected = delegate.onDragDetectedProperty
+
+ def onDragDetected_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
+ onDragDetected() = v
+ }
+
+ /**
+ * Defines a function to be called when this `Scene` is a drag and drop gesture source after its data has been
+ * dropped on a drop target.
+ */
+ def onDragDone = delegate.onDragDoneProperty
+
+ def onDragDone_=(v: jfxe.EventHandler[_ >: jfxsi.DragEvent]): Unit = {
+ onDragDone() = v
+ }
+
+ /**
+ * Defines a function to be called when the mouse button is released on this `Scene` during drag and drop gesture.
+ */
+ def onDragDropped = delegate.onDragDroppedProperty
+
+ def onDragDropped_=(v: jfxe.EventHandler[_ >: jfxsi.DragEvent]): Unit = {
+ onDragDropped() = v
+ }
+
+ /**
+ * Defines a function to be called when drag gesture enters this Scene.
+ */
+ def onDragEntered = delegate.onDragEnteredProperty
+
+ def onDragEntered_=(v: jfxe.EventHandler[_ >: jfxsi.DragEvent]): Unit = {
+ onDragEntered() = v
+ }
+
+ /**
+ * Defines a function to be called when drag gesture exits this Scene.
+ */
+ def onDragExited = delegate.onDragExitedProperty
+
+ def onDragExited_=(v: jfxe.EventHandler[_ >: jfxsi.DragEvent]): Unit = {
+ onDragExited() = v
+ }
+
+ /**
+ * Defines a function to be called when drag gesture progresses within this `Scene`.
+ */
+ def onDragOver = delegate.onDragOverProperty
+
+ def onDragOver_=(v: jfxe.EventHandler[_ >: jfxsi.DragEvent]): Unit = {
+ onDragOver() = v
+ }
+
+ /**
+ * Defines a function to be called when this `Node` has input focus and the input method text has changed.
+ */
+ def onInputMethodTextChanged = delegate.onInputMethodTextChangedProperty
+
+ def onInputMethodTextChanged_=(
+ v: jfxe.EventHandler[_ >: jfxsi.InputMethodEvent]
+ ): Unit = {
+ onInputMethodTextChanged() = v
+ }
+
+ /**
+ * Defines a function to be called when some `Node` of this `Scene` has input focus and a key has been pressed.
+ */
+ def onKeyPressed = delegate.onKeyPressedProperty
+
+ def onKeyPressed_=(v: jfxe.EventHandler[_ >: jfxsi.KeyEvent]): Unit = {
+ onKeyPressed() = v
+ }
+
+ /**
+ * Defines a function to be called when some `Node` of this `Scene` has input focus and a key has been released.
+ */
+ def onKeyReleased = delegate.onKeyReleasedProperty
+
+ def onKeyReleased_=(v: jfxe.EventHandler[_ >: jfxsi.KeyEvent]): Unit = {
+ onKeyReleased() = v
+ }
+
+ /**
+ * Defines a function to be called when some `Node` of this `Scene` has input focus and a key has been typed.
+ */
+ def onKeyTyped = delegate.onKeyTypedProperty
+
+ def onKeyTyped_=(v: jfxe.EventHandler[_ >: jfxsi.KeyEvent]): Unit = {
+ onKeyTyped() = v
+ }
+
+ /**
+ * Defines a function to be called when a mouse button has been clicked (pressed and released) on this `Scene`.
+ */
+ def onMouseClicked = delegate.onMouseClickedProperty
+
+ def onMouseClicked_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
+ onMouseClicked() = v
+ }
+
+ /**
+ * Defines a function to be called when a mouse button is pressed on this `Scene` and then dragged.
+ */
+ def onMouseDragged = delegate.onMouseDraggedProperty
+
+ def onMouseDragged_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
+ onMouseDragged() = v
+ }
+
+ /**
+ * Defines a function to be called when a full press-drag-release gesture enters this `Scene`.
+ */
+ def onMouseDragEntered = delegate.onMouseDragEnteredProperty
+
+ def onMouseDragEntered_=(
+ v: jfxe.EventHandler[_ >: jfxsi.MouseDragEvent]
+ ): Unit = {
+ onMouseDragEntered() = v
+ }
+
+ /**
+ * Defines a function to be called when a full press-drag-release gesture exits this `Scene`.
+ */
+ def onMouseDragExited = delegate.onMouseDragExitedProperty
+
+ def onMouseDragExited_=(
+ v: jfxe.EventHandler[_ >: jfxsi.MouseDragEvent]
+ ): Unit = {
+ onMouseDragExited() = v
+ }
+
+ /**
+ * Defines a function to be called when a full press-drag-release gesture progresses within this `Scene`.
+ */
+ def onMouseDragOver = delegate.onMouseDragOverProperty
+
+ def onMouseDragOver_=(
+ v: jfxe.EventHandler[_ >: jfxsi.MouseDragEvent]
+ ): Unit = {
+ onMouseDragOver() = v
+ }
+
+ /**
+ * Defines a function to be called when a full press-drag-release gesture ends within this `Scene`.
+ */
+ def onMouseDragReleased = delegate.onMouseDragReleasedProperty
+
+ def onMouseDragReleased_=(
+ v: jfxe.EventHandler[_ >: jfxsi.MouseDragEvent]
+ ): Unit = {
+ onMouseDragReleased() = v
+ }
+
+ /**
+ * Defines a function to be called when the mouse enters this `Scene`.
+ */
+ def onMouseEntered = delegate.onMouseEnteredProperty
+
+ def onMouseEntered_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
+ onMouseEntered() = v
+ }
+
+ /**
+ * Defines a function to be called when the mouse exits this `Scene`.
+ */
+ def onMouseExited = delegate.onMouseExitedProperty
+
+ def onMouseExited_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
+ onMouseExited() = v
+ }
+
+ /**
+ * Defines a function to be called when mouse cursor moves within this `Scene` but no buttons have been pushed.
+ */
+ def onMouseMoved = delegate.onMouseMovedProperty
+
+ def onMouseMoved_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
+ onMouseMoved() = v
+ }
+
+ /**
+ * Defines a function to be called when a mouse button has been pressed on this `Scene`.
+ */
+ def onMousePressed = delegate.onMousePressedProperty
+
+ def onMousePressed_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
+ onMousePressed() = v
+ }
+
+ /**
+ * Defines a function to be called when a mouse button has been released on this `Scene`.
+ */
+ def onMouseReleased = delegate.onMouseReleasedProperty
+
+ def onMouseReleased_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
+ onMouseReleased() = v
+ }
+
+ /**
+ * Defines a function to be called when user performs a scrolling action.
+ */
+ def onScroll = delegate.onScrollProperty
+
+ def onScroll_=(v: jfxe.EventHandler[_ >: jfxsi.ScrollEvent]): Unit = {
+ onScroll() = v
+ }
+
+ /**
+ * The URL of the user-agent stylesheet that will be used by this Scene in place of the the platform-default
+ * user-agent stylesheet. If the URL does not resolve to a valid location, the platform-default user-agent
+ * stylesheet will be used.
+ *
+ * For additional information about using CSS with the scene graph, see the
+ * [[http://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html CSS Reference Guide]].
+ *
+ * @return The URL of the user-agent stylesheet that will be used by this SubScene, or null if has not been set.
+ */
+ def userAgentStylesheet: ObjectProperty[String] =
+ delegate.userAgentStylesheetProperty
+
+ /**
+ * Set the URL of the user-agent stylesheet that will be used by this Scene in place of the the platform-default
+ * user-agent stylesheet. If the URL does not resolve to a valid location, the platform-default user-agent
+ * stylesheet will be used.
+ *
+ * For additional information about using CSS with the scene graph, see the
+ * [[http://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html CSS Reference Guide]].
+ *
+ * @param url The URL is a hierarchical URI of the form `[scheme:][//authority][path]`.
+ * If the URL does not have a `[scheme:]` component, the URL is considered to be the `[path]`
+ * component only. Any leading '/' character of the `[path]` is ignored and the `[path]` is
+ * treated as a path relative to the root of the application's classpath.
+ */
+ def userAgentStylesheet_=(url: String): Unit = {
+ ObjectProperty.fillProperty[String](userAgentStylesheet, url)
+ }
+
+ /**
+ * The `Window` for this Scene
+ */
+ def window: ReadOnlyObjectProperty[javafx.stage.Window] =
+ delegate.windowProperty
+
+ /**
+ * The horizontal location of this `Scene` on the `Window`.
+ */
+ def x: ReadOnlyDoubleProperty = delegate.xProperty
+
+ /**
+ * The vertical location of this `Scene` on the `Window`.
+ */
+ def y: ReadOnlyDoubleProperty = delegate.yProperty
+
+ /**
+ * Retrieves the depth buffer attribute for this scene.
+ */
+ def depthBuffer = delegate.isDepthBuffer
+
+ /**
+ * Gets an observable list of string URLs linking to the stylesheets to use with this Parent's contents.
+ */
+ def stylesheets: jfxc.ObservableList[String] = delegate.getStylesheets
+
+ /**
+ * Sets the list of stylesheets URLs, replacing the prior content. If you want append to current content, use `add` or
+ * similar.
+ *
+ * @param c list of stylesheets URLs to replace prior content.
+ */
+ def stylesheets_=(c: Iterable[String]): Unit = {
+ fillCollection(stylesheets, c)
+ }
+
+ /**
+ * Looks for any node within the scene graph based on the specified CSS selector.
+ *
+ * @param selector The css selector to look up
+ * @return A [[scala.Some]] containing the Node in the scene which matches the CSS selector, or [[scala.None]]
+ * if none is found.
+ */
+ def lookup(selector: String): Option[Node] = Option(delegate.lookup(selector))
+
+ /**
+ * Registers the specified mnemonic.
+ *
+ * @param m The Mnemonic
+ */
+ def addMnemonic(m: Mnemonic): Unit = {
+ delegate.addMnemonic(m)
+ }
+
+ /**
+ * Unregisters the specified mnemonic.
+ *
+ * @param m The Mnemonic to be removed.
+ */
+ def removeMnemonic(m: Mnemonic): Unit = {
+ delegate.removeMnemonic(m)
+ }
+
+ /**
+ * Gets the list of mnemonics for this `Scene`.
+ */
+ def getMnemonics
+ : jfxc.ObservableMap[jfxsi.KeyCombination, jfxc.ObservableList[
+ jfxsi.Mnemonic
+ ]] = delegate.getMnemonics
+
+ /**
+ * Gets the list of accelerators for this Scene.
+ */
+ def accelerators: jfxc.ObservableMap[jfxsi.KeyCombination, Runnable] =
+ delegate.getAccelerators
+
+ /**
+ * Confirms a potential drag and drop gesture that is recognized over this `Scene`.
+ *
+ * @param transferModes The supported `TransferMode`(s) of this `Node`
+ * @return A `Dragboard` to place this `Scene`'s data on
+ */
+ def startDragAndDrop(transferModes: TransferMode*): Dragboard =
+ delegate.startDragAndDrop(transferModes.map(_.delegate): _*)
+
+ /**
+ * Starts a full press-drag-release gesture with this scene as gesture source.
+ */
+ def startFullDrag(): Unit = {
+ delegate.startFullDrag()
+ }
+
+ /**
+ * The scene's current focus owner node. This node's "focused" variable might be false if this scene has no window,
+ * or if the window is inactive (window.focused == false).
+ *
+ * @since 2.2
+ */
+ def focusOwner: ReadOnlyObjectProperty[jfxs.Node] =
+ delegate.focusOwnerProperty()
+
+ /**
+ * Defines a function to be called when user performs a rotation action.
+ *
+ * @since 2.2
+ */
+ def onRotate = delegate.onRotateProperty
+
+ def onRotate_=(v: jfxe.EventHandler[_ >: jfxsi.RotateEvent]): Unit = {
+ onRotate() = v
+ }
+
+ /**
+ * Defines a function to be called when a rotation gesture ends.
+ *
+ * @since 2.2
+ */
+ def onRotationFinished = delegate.onRotationFinishedProperty()
+
+ def onRotationFinished_=(
+ v: jfxe.EventHandler[_ >: jfxsi.RotateEvent]
+ ): Unit = {
+ onRotationFinished() = v
+ }
+
+ /**
+ * Defines a function to be called when a rotation gesture starts.
+ *
+ * @since 2.2
+ */
+ def onRotationStarted = delegate.onRotationFinishedProperty()
+
+ def onRotationStarted_=(
+ v: jfxe.EventHandler[_ >: jfxsi.RotateEvent]
+ ): Unit = {
+ onRotationStarted() = v
+ }
+
+ /**
+ * Defines a function to be called when a Scroll gesture ends.
+ *
+ * @since 2.2
+ */
+ def onScrollFinished = delegate.onScrollFinishedProperty()
+
+ def onScrollFinished_=(v: jfxe.EventHandler[_ >: jfxsi.ScrollEvent]): Unit = {
+ onScrollFinished() = v
+ }
+
+ /**
+ * Defines a function to be called when a Scroll gesture starts.
+ *
+ * @since 2.2
+ */
+ def onScrollStarted = delegate.onScrollStartedProperty()
+
+ def onScrollStarted_=(v: jfxe.EventHandler[_ >: jfxsi.ScrollEvent]): Unit = {
+ onScrollStarted() = v
+ }
+
+ /**
+ * Defines a function to be called when a Swipe Down gesture starts.
+ *
+ * @since 2.2
+ */
+ def onSwipeDown = delegate.onSwipeDownProperty()
+
+ def onSwipeDown_=(v: jfxe.EventHandler[_ >: jfxsi.SwipeEvent]): Unit = {
+ onSwipeDown() = v
+ }
+
+ /**
+ * Defines a function to be called when a Swipe Down gesture starts.
+ *
+ * @since 2.2
+ */
+ def onSwipeLeft = delegate.onSwipeLeftProperty()
+
+ def onSwipeLeft_=(v: jfxe.EventHandler[_ >: jfxsi.SwipeEvent]): Unit = {
+ onSwipeLeft() = v
+ }
+
+ /**
+ * Defines a function to be called when a Swipe Up gesture starts.
+ *
+ * @since 2.2
+ */
+ def onSwipeUp = delegate.onSwipeUpProperty()
+
+ def onSwipeUp_=(v: jfxe.EventHandler[_ >: jfxsi.SwipeEvent]): Unit = {
+ onSwipeUp() = v
+ }
+
+ /**
+ * Defines a function to be called when a Swipe Right gesture starts.
+ *
+ * @since 2.2
+ */
+ def onSwipeRight = delegate.onSwipeRightProperty()
+
+ def onSwipeRight_=(v: jfxe.EventHandler[_ >: jfxsi.SwipeEvent]): Unit = {
+ onSwipeRight() = v
+ }
+
+ /**
+ * Defines a function to be called when user performs a Touch action.
+ *
+ * @since 2.2
+ */
+ def onZoom = delegate.onZoomProperty()
+
+ def onZoom_=(v: jfxe.EventHandler[_ >: jfxsi.ZoomEvent]): Unit = {
+ onZoom() = v
+ }
+
+ /**
+ * Defines a function to be called when a Zoom gesture ends.
+ *
+ * @since 2.2
+ */
+ def onZoomFinished = delegate.onZoomFinishedProperty()
+
+ def onZoomFinished_=(v: jfxe.EventHandler[_ >: jfxsi.ZoomEvent]): Unit = {
+ onZoomFinished() = v
+ }
+
+ /**
+ * Defines a function to be called when a Zoom gesture starts.
+ *
+ * @since 2.2
+ */
+ def onZoomStarted = delegate.onZoomStartedProperty()
+
+ def onZoomStarted_=(v: jfxe.EventHandler[_ >: jfxsi.ZoomEvent]): Unit = {
+ onZoomStarted() = v
+ }
+
+ /**
+ * Defines a function to be called when user performs a Touch Moved action.
+ *
+ * @since 2.2
+ */
+ def onTouchMoved = delegate.onTouchMovedProperty()
+
+ def onTouchMoved_=(v: jfxe.EventHandler[_ >: jfxsi.TouchEvent]): Unit = {
+ onTouchMoved() = v
+ }
+
+ /**
+ * Defines a function to be called when user performs a Touch Pressed action.
+ *
+ * @since 2.2
+ */
+ def onTouchPressed = delegate.onTouchPressedProperty()
+
+ def onTouchPressed_=(v: jfxe.EventHandler[_ >: jfxsi.TouchEvent]): Unit = {
+ onTouchPressed() = v
+ }
+
+ /**
+ * Defines a function to be called when user performs a Touch Released action.
+ *
+ * @since 2.2
+ */
+ def onTouchReleased = delegate.onTouchReleasedProperty()
+
+ def onTouchReleased_=(v: jfxe.EventHandler[_ >: jfxsi.TouchEvent]): Unit = {
+ onTouchReleased() = v
+ }
+
+ /**
+ * Defines a function to be called when user performs a Touch Stationary action.
+ *
+ * @since 2.2
+ */
+ def onTouchStationary = delegate.onTouchStationaryProperty()
+
+ def onTouchStationary_=(v: jfxe.EventHandler[_ >: jfxsi.TouchEvent]): Unit = {
+ onTouchStationary() = v
+ }
+
+ /**
+ * Takes a snapshot of this scene and returns the rendered image when it is ready.
+ *
+ * @param image The writable image that will be used to hold the rendered scene.
+ * @return the rendered image
+ *
+ * @since 2.2
+ */
+ def snapshot(image: WritableImage): WritableImage = delegate.snapshot(image)
+
+ /**
+ * Takes a snapshot of this scene at the next frame and calls the specified callback method when the image is ready.
+ *
+ * @param callback A function to be called when the image is ready.
+ * @param image The writable image that will be used to hold the rendered scene.
+ *
+ * @since 2.2
+ */
+ def snapshot(callback: SnapshotResult => Unit, image: WritableImage): Unit = {
+ val javaCallback = new jfxu.Callback[jfxs.SnapshotResult, java.lang.Void] {
+ def call(result: jfxs.SnapshotResult): java.lang.Void = {
+ callback(new SnapshotResult(result))
+ null
+ }
+ }
+ delegate.snapshot(javaCallback, image)
+ }
+
+}
diff --git a/src/main/scala/wow/doge/mygame/utils/GenericConsoleStream.scala b/src/main/scala/wow/doge/mygame/utils/GenericConsoleStream.scala
new file mode 100644
index 0000000..3b1ac28
--- /dev/null
+++ b/src/main/scala/wow/doge/mygame/utils/GenericConsoleStream.scala
@@ -0,0 +1,104 @@
+package wow.doge.mygame.utils
+
+import java.io.ByteArrayOutputStream
+import java.io.OutputStream
+import java.io.PrintStream
+
+import cats.effect.Resource
+import monix.bio.Task
+import scalafx.scene.control.TextArea
+import scalafx.application.Platform
+
+trait ConsoleStreamable[T] {
+ def println(inst: T, text: String): Unit
+ def print(inst: T, text: String): Unit
+}
+
+class GenericConsoleStream[T](
+ outputStream: OutputStream,
+ val config: GenericConsoleStream.Config =
+ GenericConsoleStream.Config.default,
+ private var streamable: Option[T] = None
+)(implicit
+ cs: ConsoleStreamable[T]
+) extends PrintStream(outputStream, true) {
+ private lazy val defaultOut = System.out
+
+ def printToStreamable(stble: Option[T], text: String) =
+ stble.foreach(s => cs.println(s, text))
+
+ override def println(text: String): Unit =
+ if (config.exclusive) {
+ printToStreamable(streamable, text)
+ } else {
+ defaultOut.println(text)
+ printToStreamable(streamable, text)
+ }
+
+ override def print(text: String): Unit =
+ streamable.foreach(s =>
+ if (config.exclusive) {
+ printToStreamable(streamable, text)
+ } else {
+ defaultOut.println(text)
+ printToStreamable(streamable, text)
+ }
+ )
+
+ def :=(s: T) = {
+ streamable match {
+ case Some(value) =>
+ case None => streamable = Some(s)
+ }
+ }
+}
+
+object GenericConsoleStream {
+
+ /**
+ * for future use
+ */
+ case class Config(exclusive: Boolean = false)
+ object Config {
+ lazy val default = Config()
+ }
+
+ implicit val implJFXConsoleStreamForTextArea =
+ new ConsoleStreamable[scalafx.scene.control.TextArea] {
+
+ override def println(
+ ta: scalafx.scene.control.TextArea,
+ text: String
+ ): Unit =
+ ta.appendText(text + "\n")
+
+ override def print(
+ ta: scalafx.scene.control.TextArea,
+ text: String
+ ): Unit =
+ ta.appendText(text)
+
+ }
+
+ // def textAreaStreamResource(ta: TextArea) =
+ // Resource.make(
+ // Task(
+ // new GenericConsoleStream(
+ // outputStream = new ByteArrayOutputStream(),
+ // streamable = ta
+ // )
+ // )
+ // )(s => Task(s.close()))
+
+ def textAreaStream(
+ // ta: TextArea
+ ) =
+ // Task(
+ new GenericConsoleStream[TextArea](
+ outputStream = new ByteArrayOutputStream()
+ // streamable = ta
+ )
+ // )
+ // (s => Task(s.close()))
+
+}
diff --git a/src/main/scala/wow/doge/mygame/utils/JFXConsoleStream.scala b/src/main/scala/wow/doge/mygame/utils/JFXConsoleStream.scala
deleted file mode 100644
index e2c5546..0000000
--- a/src/main/scala/wow/doge/mygame/utils/JFXConsoleStream.scala
+++ /dev/null
@@ -1,71 +0,0 @@
-package wow.doge.mygame.utils
-
-import java.io.ByteArrayOutputStream
-import java.io.OutputStream
-import java.io.PrintStream
-
-import cats.effect.Resource
-import monix.bio.Task
-import scalafx.scene.control.TextArea
-
-trait JFXConsoleStreamable[T] {
- def println(inst: T, text: String): Unit
- def print(inst: T, text: String): Unit
-}
-
-class JFXConsoleStream[T](
- outputStream: OutputStream,
- val config: JFXConsoleStream.Config = JFXConsoleStream.Config.default,
- control: T
-)(implicit
- jcs: JFXConsoleStreamable[T]
-) extends PrintStream(outputStream, true) {
- private lazy val defaultOut = System.out
- override def println(text: String): Unit =
- if (config.exclusive) {
- jcs.println(control, text + "\n")
- } else {
- defaultOut.println(text)
- jcs.println(control, text + "\n")
- }
- override def print(text: String): Unit = jcs.println(control, text)
-}
-
-object JFXConsoleStream {
-
- /**
- * for future use
- */
- case class Config(exclusive: Boolean = false)
- object Config {
- lazy val default = Config()
- }
-
- implicit val implJFXConsoleStreamForTextArea =
- new JFXConsoleStreamable[scalafx.scene.control.TextArea] {
-
- override def println(
- ta: scalafx.scene.control.TextArea,
- text: String
- ): Unit =
- ta.appendText(text + "\n")
-
- override def print(
- ta: scalafx.scene.control.TextArea,
- text: String
- ): Unit =
- ta.appendText(text)
-
- }
-
- def textAreaStream(ta: TextArea) =
- Resource.make(
- Task(
- new JFXConsoleStream(
- outputStream = new ByteArrayOutputStream(),
- control = ta
- )
- )
- )(s => Task(s.close()))
-
-}
diff --git a/src/main/scala/wow/doge/mygame/utils/ResizeHelper.java b/src/main/scala/wow/doge/mygame/utils/ResizeHelper.java
new file mode 100644
index 0000000..5bb2086
--- /dev/null
+++ b/src/main/scala/wow/doge/mygame/utils/ResizeHelper.java
@@ -0,0 +1,130 @@
+package wow.doge.mygame.utils;
+
+import javafx.event.EventHandler;
+import javafx.event.EventType;
+import javafx.geometry.Insets;
+import javafx.scene.Cursor;
+import javafx.scene.Scene;
+import javafx.scene.input.MouseEvent;
+import javafx.stage.Stage;
+
+//created by Alexander Berg
+public class ResizeHelper {
+
+ public static ResizeListener addResizeListener(Stage stage) {
+ ResizeListener resizeListener = new ResizeListener(stage);
+ Scene scene = stage.getScene();
+ scene.addEventHandler(MouseEvent.MOUSE_MOVED, resizeListener);
+ scene.addEventHandler(MouseEvent.MOUSE_PRESSED, resizeListener);
+ scene.addEventHandler(MouseEvent.MOUSE_DRAGGED, resizeListener);
+ scene.addEventHandler(MouseEvent.MOUSE_EXITED, resizeListener);
+ scene.addEventHandler(MouseEvent.MOUSE_EXITED_TARGET, resizeListener);
+
+ return resizeListener;
+ }
+
+ public static class ResizeListener implements EventHandler {
+ private Stage stage;
+ private Scene scene;
+ private Cursor cursorEvent = Cursor.DEFAULT;
+ private int border = 4;
+ private double startX = 0;
+ private double startY = 0;
+ private double sceneOffsetX = 0;
+ private double sceneOffsetY = 0;
+ private double padTop = 0;
+ private double padRight = 0;
+ private double padBottom = 0;
+ private double padLeft = 0;
+
+ public ResizeListener(Stage stage) {
+ this.stage = stage;
+ this.scene = stage.getScene();
+ }
+
+ public void setPadding(Insets padding) {
+ padTop = padding.getTop();
+ padRight = padding.getRight();
+ padBottom = padding.getBottom();
+ padLeft = padding.getLeft();
+ }
+
+ @Override
+ public void handle(MouseEvent mouseEvent) {
+ EventType extends MouseEvent> mouseEventType = mouseEvent.getEventType();
+
+ double mouseEventX = mouseEvent.getSceneX(), mouseEventY = mouseEvent.getSceneY(),
+ viewWidth = stage.getWidth() - padLeft - padRight,
+ viewHeight = stage.getHeight() - padTop - padBottom;
+
+ if (MouseEvent.MOUSE_MOVED.equals(mouseEventType)) {
+ if (mouseEventX < border + padLeft && mouseEventY < border + padTop) {
+ cursorEvent = Cursor.NW_RESIZE;
+ } else if (mouseEventX < border + padLeft && mouseEventY > viewHeight - border + padTop) {
+ cursorEvent = Cursor.SW_RESIZE;
+ } else if (mouseEventX > viewWidth - border + padLeft && mouseEventY < border + padTop) {
+ cursorEvent = Cursor.NE_RESIZE;
+ } else if (mouseEventX > viewWidth - border + padLeft && mouseEventY > viewHeight - border + padTop) {
+ cursorEvent = Cursor.SE_RESIZE;
+ } else if (mouseEventX < border + padLeft) {
+ cursorEvent = Cursor.W_RESIZE;
+ } else if (mouseEventX > viewWidth - border + padLeft) {
+ cursorEvent = Cursor.E_RESIZE;
+ } else if (mouseEventY < border + padTop) {
+ cursorEvent = Cursor.N_RESIZE;
+ } else if (mouseEventY > viewHeight - border + padTop) {
+ cursorEvent = Cursor.S_RESIZE;
+ } else {
+ cursorEvent = Cursor.DEFAULT;
+ }
+
+ scene.setCursor(cursorEvent);
+ } else if (MouseEvent.MOUSE_EXITED.equals(mouseEventType)
+ || MouseEvent.MOUSE_EXITED_TARGET.equals(mouseEventType)) {
+ scene.setCursor(Cursor.DEFAULT);
+ } else if (MouseEvent.MOUSE_PRESSED.equals(mouseEventType)) {
+ startX = viewWidth - mouseEventX;
+ startY = viewHeight - mouseEventY;
+ sceneOffsetX = mouseEvent.getSceneX();
+ sceneOffsetY = mouseEvent.getSceneY();
+ } else if (MouseEvent.MOUSE_DRAGGED.equals(mouseEventType) && !Cursor.DEFAULT.equals(cursorEvent)) {
+ if (!Cursor.W_RESIZE.equals(cursorEvent) && !Cursor.E_RESIZE.equals(cursorEvent)) {
+ double minHeight = stage.getMinHeight() > (border * 2) ? stage.getMinHeight() : (border * 2);
+
+ if (Cursor.NW_RESIZE.equals(cursorEvent) || Cursor.N_RESIZE.equals(cursorEvent)
+ || Cursor.NE_RESIZE.equals(cursorEvent)) {
+ if (stage.getHeight() > minHeight || mouseEventY < 0) {
+ double height = stage.getY() - mouseEvent.getScreenY() + stage.getHeight() + sceneOffsetY;
+ double y = mouseEvent.getScreenY() - sceneOffsetY;
+
+ stage.setHeight(height);
+ stage.setY(y);
+ }
+ } else {
+ if (stage.getHeight() > minHeight || mouseEventY + startY - stage.getHeight() > 0) {
+ stage.setHeight(mouseEventY + startY + padBottom + padTop);
+ }
+ }
+ }
+
+ if (!Cursor.N_RESIZE.equals(cursorEvent) && !Cursor.S_RESIZE.equals(cursorEvent)) {
+ double minWidth = stage.getMinWidth() > (border * 2) ? stage.getMinWidth() : (border * 2);
+ if (Cursor.NW_RESIZE.equals(cursorEvent) || Cursor.W_RESIZE.equals(cursorEvent)
+ || Cursor.SW_RESIZE.equals(cursorEvent)) {
+ if (stage.getWidth() > minWidth || mouseEventX < 0) {
+ double width = stage.getX() - mouseEvent.getScreenX() + stage.getWidth() + sceneOffsetX;
+ double x = mouseEvent.getScreenX() - sceneOffsetX;
+
+ stage.setWidth(width);
+ stage.setX(x);
+ }
+ } else {
+ if (stage.getWidth() > minWidth || mouseEventX + startX - stage.getWidth() > 0) {
+ stage.setWidth(mouseEventX + startX + padLeft + padRight);
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/scala/wow/doge/mygame/utils/TreeTest.scala b/src/main/scala/wow/doge/mygame/utils/TreeTest.scala
new file mode 100644
index 0000000..2f112ee
--- /dev/null
+++ b/src/main/scala/wow/doge/mygame/utils/TreeTest.scala
@@ -0,0 +1,24 @@
+package wow.doge.mygame.utils
+
+import monix.execution.atomic.AtomicAny
+
+/**
+ * Useless
+ */
+sealed abstract class Tree[+T]
+case class Node[T](data: T, children: AtomicAny[LazyList[Tree[T]]])
+ extends Tree[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)
+
+class TreeManager[T] {
+// val root: AtomicAny[Tree[T]] = AtomicAny(Leaf)
+
+ def add(data: T, node: Node[T]) = {}
+}