forked from nova/jmonkey-test
first commit
This commit is contained in:
commit
1f55e08fa5
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
package ammonite
|
||||||
|
package $file.src.main.resources
|
||||||
|
import _root_.ammonite.interp.api.InterpBridge.{
|
||||||
|
value => interp
|
||||||
|
}
|
||||||
|
import _root_.ammonite.interp.api.InterpBridge.value.{
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
import _root_.ammonite.interp.api.IvyConstructor.{
|
||||||
|
ArtifactIdExt,
|
||||||
|
GroupIdExt
|
||||||
|
}
|
||||||
|
import _root_.ammonite.runtime.tools.{
|
||||||
|
browse,
|
||||||
|
grep,
|
||||||
|
time,
|
||||||
|
tail
|
||||||
|
}
|
||||||
|
import _root_.ammonite.repl.tools.{
|
||||||
|
desugar,
|
||||||
|
source
|
||||||
|
}
|
||||||
|
import _root_.ammonite.main.Router.{
|
||||||
|
doc,
|
||||||
|
main
|
||||||
|
}
|
||||||
|
import _root_.ammonite.repl.tools.Util.{
|
||||||
|
pathScoptRead
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object dep{
|
||||||
|
/*<script>*/class Test(x: Int)
|
||||||
|
/*</script>*/ /*<generated>*/
|
||||||
|
def $main() = { scala.Iterator[String]() }
|
||||||
|
override def toString = "dep"
|
||||||
|
/*</generated>*/
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
package ammonite
|
||||||
|
package $file.src.main.resources
|
||||||
|
import _root_.ammonite.interp.api.InterpBridge.{
|
||||||
|
value => interp
|
||||||
|
}
|
||||||
|
import _root_.ammonite.interp.api.InterpBridge.value.{
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
import _root_.ammonite.interp.api.IvyConstructor.{
|
||||||
|
ArtifactIdExt,
|
||||||
|
GroupIdExt
|
||||||
|
}
|
||||||
|
import _root_.ammonite.runtime.tools.{
|
||||||
|
browse,
|
||||||
|
grep,
|
||||||
|
time,
|
||||||
|
tail
|
||||||
|
}
|
||||||
|
import _root_.ammonite.repl.tools.{
|
||||||
|
desugar,
|
||||||
|
source
|
||||||
|
}
|
||||||
|
import _root_.ammonite.main.Router.{
|
||||||
|
doc,
|
||||||
|
main
|
||||||
|
}
|
||||||
|
import _root_.ammonite.repl.tools.Util.{
|
||||||
|
pathScoptRead
|
||||||
|
}
|
||||||
|
import ammonite.$file.src.main.resources.{
|
||||||
|
dep
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object hello{
|
||||||
|
/*<script>*/import $file.$
|
||||||
|
import dep.Test
|
||||||
|
|
||||||
|
/*<amm>*/val res_2 = /*</amm>*/new Test(1)
|
||||||
|
/*</script>*/ /*<generated>*/
|
||||||
|
def $main() = { scala.Iterator[String]() }
|
||||||
|
override def toString = "hello"
|
||||||
|
/*</generated>*/
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
|
||||||
|
package ammonite
|
||||||
|
package $file.src.main.resources
|
||||||
|
import _root_.ammonite.interp.api.InterpBridge.{
|
||||||
|
value => interp
|
||||||
|
}
|
||||||
|
import _root_.ammonite.interp.api.InterpBridge.value.{
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
import _root_.ammonite.interp.api.IvyConstructor.{
|
||||||
|
ArtifactIdExt,
|
||||||
|
GroupIdExt
|
||||||
|
}
|
||||||
|
import _root_.ammonite.runtime.tools.{
|
||||||
|
browse,
|
||||||
|
grep,
|
||||||
|
time,
|
||||||
|
tail
|
||||||
|
}
|
||||||
|
import _root_.ammonite.repl.tools.{
|
||||||
|
desugar,
|
||||||
|
source
|
||||||
|
}
|
||||||
|
import _root_.ammonite.main.Router.{
|
||||||
|
doc,
|
||||||
|
main
|
||||||
|
}
|
||||||
|
import _root_.ammonite.repl.tools.Util.{
|
||||||
|
pathScoptRead
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object hello2{
|
||||||
|
/*<script>*/import $repo.$
|
||||||
|
// import $repo.`https://bintray.com/jmonkeyengine/com.jme3`
|
||||||
|
// import $file.dep
|
||||||
|
import $ivy.$
|
||||||
|
// import $ivy.`wow.doge:game:1.0-SNAPSHOT`
|
||||||
|
import $ivy.$
|
||||||
|
// import wow.doge.game.types.GameScript
|
||||||
|
import com.jme3.scene.control.Control
|
||||||
|
|
||||||
|
// println("hello from script")
|
||||||
|
|
||||||
|
// class Scr extends GameScript {
|
||||||
|
// def start(): Unit = println("hello from start")
|
||||||
|
|
||||||
|
// def stop(): Unit = println("hello from stop")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // class SomeClass extends Control {}
|
||||||
|
|
||||||
|
// @main
|
||||||
|
// def main(): GameScript = new Scr()
|
||||||
|
import com.simsilica.es.base.DefaultEntityData
|
||||||
|
import com.simsilica.es.EntityData
|
||||||
|
import com.jme3.app.Application
|
||||||
|
import wow.doge.mygame.game.Implicits._
|
||||||
|
import wow.doge.mygame.components.TestComponent
|
||||||
|
import com.jme3.scene.shape.Box
|
||||||
|
import com.jme3.scene.Geometry
|
||||||
|
import com.jme3.material.Material
|
||||||
|
import com.jme3.math.ColorRGBA
|
||||||
|
import com.jme3.asset.AssetManager
|
||||||
|
import com.jme3.math.Vector3f
|
||||||
|
import wow.doge.mygame.state._
|
||||||
|
class TestAppState(
|
||||||
|
// private var _entity: Option[EntityData] = Some(new DefaultEntityData())
|
||||||
|
) extends MyBaseState {
|
||||||
|
protected lazy val b = new Box(1, 1, 1)
|
||||||
|
protected lazy val geom = new Geometry("Box", b)
|
||||||
|
protected lazy val mat = Material(
|
||||||
|
assetManager = assetManager,
|
||||||
|
path = "Common/MatDefs/Misc/Unshaded.j3md"
|
||||||
|
)
|
||||||
|
|
||||||
|
// def entity = _entity
|
||||||
|
// override def initialize(app: Application): Unit = {
|
||||||
|
// super.initialize(app)
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
override def init() = {
|
||||||
|
entityData
|
||||||
|
.createEntity()
|
||||||
|
.withComponents(TestComponent())
|
||||||
|
// entityData.setComponents(x, TestComponent())
|
||||||
|
val es = entityData.getEntities(classOf[TestComponent])
|
||||||
|
println(es)
|
||||||
|
geom.setMaterial(mat)
|
||||||
|
rootNode.attachChild(geom)
|
||||||
|
|
||||||
|
// geom.foreach(e => {
|
||||||
|
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
override def update(tpf: Float) = {
|
||||||
|
geom.rotate(0, 0.5f * tpf, 0)
|
||||||
|
geom.move(new Vector3f(0, 1 * tpf, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
override def cleanup(app: Application): Unit = {
|
||||||
|
// _entity.map(_.close())
|
||||||
|
// _entity = None
|
||||||
|
}
|
||||||
|
|
||||||
|
override def onEnable(): Unit = {}
|
||||||
|
|
||||||
|
override def onDisable(): Unit = {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object Material {
|
||||||
|
def apply(
|
||||||
|
color: String = "Color",
|
||||||
|
colorType: com.jme3.math.ColorRGBA = ColorRGBA.Blue,
|
||||||
|
assetManager: AssetManager,
|
||||||
|
path: String
|
||||||
|
): Material = {
|
||||||
|
val mat =
|
||||||
|
new Material(assetManager, path)
|
||||||
|
mat.setColor(color, colorType)
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@main
|
||||||
|
def main(): MyBaseState = new TestAppState()
|
||||||
|
/*</script>*/ /*<generated>*/
|
||||||
|
def $main() = { scala.Iterator[String]() }
|
||||||
|
override def toString = "hello2"
|
||||||
|
/*</generated>*/
|
||||||
|
}
|
25
.gitignore
vendored
Normal file
25
.gitignore
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# sbt specific
|
||||||
|
.cache/
|
||||||
|
.history/
|
||||||
|
.lib/
|
||||||
|
dist/*
|
||||||
|
target/
|
||||||
|
lib_managed/
|
||||||
|
src_managed/
|
||||||
|
project/boot/
|
||||||
|
project/plugins/project/
|
||||||
|
metals.sbt
|
||||||
|
.metals
|
||||||
|
.bloop
|
||||||
|
|
||||||
|
# Scala-IDE specific
|
||||||
|
.scala_dependencies
|
||||||
|
.worksheet
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
.vscode
|
||||||
|
assets/
|
||||||
|
*.j3o
|
1
.scalafmt.conf
Normal file
1
.scalafmt.conf
Normal file
@ -0,0 +1 @@
|
|||||||
|
version = "2.6.4"
|
3
assets.jmp
Normal file
3
assets.jmp
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#assets properties
|
||||||
|
#Fri Oct 23 22:34:43 IST 2020
|
||||||
|
assets.folder.name=src/main/resources/assets
|
192
build.sbt
Normal file
192
build.sbt
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
// The simplest possible sbt build file is just one line:
|
||||||
|
|
||||||
|
scalaVersion := "2.13.3"
|
||||||
|
// That is, to create a valid sbt build, all you've got to do is define the
|
||||||
|
// version of Scala you'd like your project to use.
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// Lines like the above defining `scalaVersion` are called "settings". Settings
|
||||||
|
// are key/value pairs. In the case of `scalaVersion`, the key is "scalaVersion"
|
||||||
|
// and the value is "2.13.1"
|
||||||
|
|
||||||
|
// It's possible to define many kinds of settings, such as:
|
||||||
|
|
||||||
|
// Note, it's not required for you to define these three settings. These are
|
||||||
|
// mostly only necessary if you intend to publish your library's binaries on a
|
||||||
|
// place like Sonatype or Bintray.
|
||||||
|
|
||||||
|
// Want to use a published library in your project?
|
||||||
|
// You can define other libraries as dependencies in your build like this:
|
||||||
|
|
||||||
|
resolvers += "Jcenter" at "https://jcenter.bintray.com/"
|
||||||
|
resolvers += "JME Bintray" at "https://bintray.com/jmonkeyengine/com.jme3"
|
||||||
|
|
||||||
|
resolvers += Resolver.mavenLocal
|
||||||
|
resolvers += Resolver.sonatypeRepo("snapshots")
|
||||||
|
|
||||||
|
lazy val jmeVersion = "3.3.2-stable"
|
||||||
|
|
||||||
|
lazy val osName = System.getProperty("os.name") match {
|
||||||
|
case n if n.startsWith("Linux") => "linux"
|
||||||
|
case n if n.startsWith("Mac") => "mac"
|
||||||
|
case n if n.startsWith("Windows") => "win"
|
||||||
|
case _ => throw new Exception("Unknown platform!")
|
||||||
|
}
|
||||||
|
lazy val javaFXModules =
|
||||||
|
Seq("base", "controls", "fxml", "graphics", "media", "swing", "web")
|
||||||
|
|
||||||
|
lazy val root = (project in file(".")).settings(
|
||||||
|
inThisBuild(
|
||||||
|
List(
|
||||||
|
scalaVersion := scalaVersion.value, // 2.11.12, or 2.13.3
|
||||||
|
semanticdbEnabled := true, // enable SemanticDB
|
||||||
|
semanticdbVersion := "4.3.24" // use Scalafix compatible version
|
||||||
|
)
|
||||||
|
),
|
||||||
|
name := "mygame",
|
||||||
|
organization := "wow.doge",
|
||||||
|
version := "1.0-SNAPSHOT",
|
||||||
|
libraryDependencies ++= Seq(
|
||||||
|
"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
|
||||||
|
"org.jmonkeyengine" % "jme3-desktop" % jmeVersion,
|
||||||
|
// https://mvnrepository.com/artifact/org.jmonkeyengine/jme3-lwjgl3
|
||||||
|
"org.jmonkeyengine" % "jme3-lwjgl3" % jmeVersion,
|
||||||
|
"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",
|
||||||
|
// "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.circe" %% "circe-core" % "0.13.0",
|
||||||
|
"io.circe" %% "circe-generic" % "0.13.0",
|
||||||
|
"com.softwaremill.sttp.client" %% "core" % "2.2.5",
|
||||||
|
"com.softwaremill.sttp.client" %% "monix" % "2.2.5",
|
||||||
|
"com.softwaremill.sttp.client" %% "circe" % "2.2.5",
|
||||||
|
"com.softwaremill.sttp.client" %% "async-http-client-backend-monix" % "2.2.5",
|
||||||
|
"com.github.valskalla" %% "odin-monix" % "0.8.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.github.valskalla" %% "odin-slf4j" % "0.8.1",
|
||||||
|
"com.softwaremill.quicklens" %% "quicklens" % "1.6.1"
|
||||||
|
),
|
||||||
|
// Determine OS version of JavaFX binaries
|
||||||
|
|
||||||
|
// Add JavaFX dependencies
|
||||||
|
libraryDependencies ++= javaFXModules.map(m =>
|
||||||
|
"org.openjfx" % s"javafx-$m" % "14.0.1" classifier osName
|
||||||
|
),
|
||||||
|
scalacOptions ++= Seq(
|
||||||
|
"-encoding",
|
||||||
|
"UTF-8",
|
||||||
|
"-deprecation",
|
||||||
|
"-feature",
|
||||||
|
"-unchecked",
|
||||||
|
"-Xlint",
|
||||||
|
"-Ywarn-numeric-widen",
|
||||||
|
"-Ymacro-annotations",
|
||||||
|
// "utf-8", // Specify character encoding used by source files.
|
||||||
|
"-explaintypes" // Explain type errors in more detail.
|
||||||
|
),
|
||||||
|
javacOptions ++= Seq("-source", "11", "-target", "11"),
|
||||||
|
javaOptions ++= Seq("-Xmx2G", "-Xms2G"),
|
||||||
|
fork := true,
|
||||||
|
assemblyMergeStrategy in assembly := {
|
||||||
|
case PathList("javax", "servlet", xs @ _*) => MergeStrategy.first
|
||||||
|
case PathList(ps @ _*) if ps.last endsWith ".html" => MergeStrategy.first
|
||||||
|
case "application.conf" => MergeStrategy.concat
|
||||||
|
case "unwanted.txt" => MergeStrategy.discard
|
||||||
|
case x if Assembly.isConfigFile(x) =>
|
||||||
|
MergeStrategy.concat
|
||||||
|
case PathList("META-INF", xs @ _*) =>
|
||||||
|
(xs map { _.toLowerCase }) match {
|
||||||
|
case ("manifest.mf" :: Nil) | ("index.list" :: Nil) |
|
||||||
|
("dependencies" :: Nil) =>
|
||||||
|
MergeStrategy.discard
|
||||||
|
case ps @ (x :: xs)
|
||||||
|
if ps.last.endsWith(".sf") || ps.last.endsWith(".dsa") =>
|
||||||
|
MergeStrategy.discard
|
||||||
|
case "plexus" :: xs =>
|
||||||
|
MergeStrategy.discard
|
||||||
|
case "services" :: xs =>
|
||||||
|
MergeStrategy.filterDistinctLines
|
||||||
|
case ("spring.schemas" :: Nil) | ("spring.handlers" :: Nil) =>
|
||||||
|
MergeStrategy.filterDistinctLines
|
||||||
|
case _ => MergeStrategy.first // Changed deduplicate to first
|
||||||
|
}
|
||||||
|
case PathList(_*) => MergeStrategy.first
|
||||||
|
// case x =>
|
||||||
|
// val oldStrategy = (assemblyMergeStrategy in assembly).value
|
||||||
|
// oldStrategy(x)
|
||||||
|
}
|
||||||
|
// scalaVersion := "2.13.2", // 2.11.12, or 2.13.3
|
||||||
|
// semanticdbEnabled := true, // enable SemanticDB
|
||||||
|
// semanticdbVersion := scalafixSemanticdb.revision // use Scalafix compatible version
|
||||||
|
// semanticdbVersion := "4.3.24",
|
||||||
|
)
|
||||||
|
|
||||||
|
// Here, `libraryDependencies` is a set of dependencies, and by using `+=`,
|
||||||
|
// we're adding the scala-parser-combinators dependency to the set of dependencies
|
||||||
|
// that sbt will go and fetch when it starts up.
|
||||||
|
// Now, in any Scala file, you can import classes, objects, etc., from
|
||||||
|
// scala-parser-combinators with a regular import.
|
||||||
|
|
||||||
|
// TIP: To find the "dependency" that you need to add to the
|
||||||
|
// `libraryDependencies` set, which in the above example looks like this:
|
||||||
|
|
||||||
|
// "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2"
|
||||||
|
|
||||||
|
// You can use Scaladex, an index of all known published Scala libraries. There,
|
||||||
|
// after you find the library you want, you can just copy/paste the dependency
|
||||||
|
// information that you need into your build file. For example, on the
|
||||||
|
// scala/scala-parser-combinators Scaladex page,
|
||||||
|
// https://index.scala-lang.org/scala/scala-parser-combinators, you can copy/paste
|
||||||
|
// the sbt dependency from the sbt box on the right-hand side of the screen.
|
||||||
|
|
||||||
|
// IMPORTANT NOTE: while build files look _kind of_ like regular Scala, it's
|
||||||
|
// important to note that syntax in *.sbt files doesn't always behave like
|
||||||
|
// regular Scala. For example, notice in this build file that it's not required
|
||||||
|
// to put our settings into an enclosing object or class. Always remember that
|
||||||
|
// sbt is a bit different, semantically, than vanilla Scala.
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// Most moderately interesting Scala projects don't make use of the very simple
|
||||||
|
// build file style (called "bare style") used in this build.sbt file. Most
|
||||||
|
// intermediate Scala projects make use of so-called "multi-project" builds. A
|
||||||
|
// multi-project build makes it possible to have different folders which sbt can
|
||||||
|
// be configured differently for. That is, you may wish to have different
|
||||||
|
// dependencies or different testing frameworks defined for different parts of
|
||||||
|
// your codebase. Multi-project builds make this possible.
|
||||||
|
|
||||||
|
// Here's a quick glimpse of what a multi-project build looks like for this
|
||||||
|
// build, with only one "subproject" defined, called `root`:
|
||||||
|
|
||||||
|
// lazy val root = (project in file(".")).
|
||||||
|
// settings(
|
||||||
|
// inThisBuild(List(
|
||||||
|
// organization := "ch.epfl.scala",
|
||||||
|
// scalaVersion := "2.13.1"
|
||||||
|
// )),
|
||||||
|
// name := "hello-world"
|
||||||
|
// )
|
||||||
|
|
||||||
|
// To learn more about multi-project builds, head over to the official sbt
|
||||||
|
// documentation at http://www.scala-sbt.org/documentation.html
|
BIN
libbulletjme.so
Normal file
BIN
libbulletjme.so
Normal file
Binary file not shown.
1
project/build.properties
Normal file
1
project/build.properties
Normal file
@ -0,0 +1 @@
|
|||||||
|
sbt.version=1.3.13
|
2
project/plugins.sbt
Normal file
2
project/plugins.sbt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.15.0")
|
||||||
|
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.23")
|
@ -0,0 +1 @@
|
|||||||
|
org.jetbrains.kotlin.mainKts.jsr223.KotlinJsr223MainKtsScriptEngineFactory
|
7
src/main/resources/application.conf
Normal file
7
src/main/resources/application.conf
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
jme-dispatcher {
|
||||||
|
type = "Dispatcher"
|
||||||
|
name = "JME-Thread"
|
||||||
|
executor = "wow.doge.mygame.executors.JMEThreadExecutorServiceConfigurator"
|
||||||
|
throughput = 1
|
||||||
|
}
|
||||||
|
akka.jvm-exit-on-fatal-error = on
|
2
src/main/resources/dep.sc
Normal file
2
src/main/resources/dep.sc
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// println("hello from dep")
|
||||||
|
class Test(x: Int)
|
36
src/main/resources/hello.main.kts
Normal file
36
src/main/resources/hello.main.kts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// @file:Import("src/main/resources/hello2.main.kts")
|
||||||
|
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.0-M1")
|
||||||
|
@file:DependsOn("/home/rohan/.m2/repository/wow/doge/game/1.0-SNAPSHOT/game-1.0-SNAPSHOT.jar")
|
||||||
|
@file:DependsOn("/home/rohan/.ivy2/local/wow.doge/mygame_2.13/1.0-SNAPSHOT/jars/mygame_2.13.jar")
|
||||||
|
|
||||||
|
import wow.doge.game.types.GameScript
|
||||||
|
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
import wow.doge.mygame.components.Test
|
||||||
|
|
||||||
|
|
||||||
|
//println(x * 2)
|
||||||
|
|
||||||
|
println("hello from main script")
|
||||||
|
|
||||||
|
class GameScriptImpl : GameScript {
|
||||||
|
override fun start() = runBlocking {
|
||||||
|
for(x in 0 until 5) {
|
||||||
|
launch {
|
||||||
|
val del = Random.nextLong(20, 100)
|
||||||
|
|
||||||
|
delay(del)
|
||||||
|
println("hello from start $x, delay is $del")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun stop() {println("hello from stop")}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameScriptImpl()
|
||||||
|
|
||||||
|
class MyTest : Test()
|
35
src/main/resources/hello.sc
Normal file
35
src/main/resources/hello.sc
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// #!/usr/bin/env amm
|
||||||
|
|
||||||
|
// import coursierapi.MavenRepository
|
||||||
|
|
||||||
|
// interp.repositories.update(
|
||||||
|
// interp.repositories() ::: List(
|
||||||
|
// MavenRepository.of("file://home/rohan/.m2/repository")
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
|
||||||
|
// @
|
||||||
|
// import $repo.`https://jcenter.bintray.com`
|
||||||
|
// // import $repo.`https://bintray.com/jmonkeyengine/com.jme3`
|
||||||
|
// import $file.dep
|
||||||
|
// import $ivy.`org.jmonkeyengine:jme3-core:3.2.4-stable`
|
||||||
|
// import $ivy.`wow.doge:game:1.0-SNAPSHOT`
|
||||||
|
// import wow.doge.game.types.GameScript
|
||||||
|
// import com.jme3.scene.control.Control
|
||||||
|
|
||||||
|
// println("hello from script")
|
||||||
|
|
||||||
|
// class Scr extends GameScript {
|
||||||
|
// def start(): Unit = println("hello from start")
|
||||||
|
|
||||||
|
// def stop(): Unit = println("hello from stop")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // class SomeClass extends Control {}
|
||||||
|
|
||||||
|
// @main
|
||||||
|
// def main(): GameScript = new Scr()
|
||||||
|
import $file.dep
|
||||||
|
import dep.Test
|
||||||
|
|
||||||
|
new Test(1)
|
5
src/main/resources/hello2.main.kts
Normal file
5
src/main/resources/hello2.main.kts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
println("hello from dep")
|
||||||
|
|
||||||
|
class Test(val x: Int)
|
||||||
|
|
||||||
|
var x = 2
|
107
src/main/resources/hello2.sc
Normal file
107
src/main/resources/hello2.sc
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#!/usr/bin/env amm
|
||||||
|
|
||||||
|
// import coursierapi.MavenRepository
|
||||||
|
|
||||||
|
// interp.repositories.update(
|
||||||
|
// interp.repositories() ::: List(
|
||||||
|
// MavenRepository.of("file://home/rohan/.m2/repository")
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
|
||||||
|
// @
|
||||||
|
import $repo.`https://jcenter.bintray.com`
|
||||||
|
// import $repo.`https://bintray.com/jmonkeyengine/com.jme3`
|
||||||
|
// import $file.dep
|
||||||
|
import $ivy.`org.jmonkeyengine:jme3-core:3.2.4-stable`
|
||||||
|
// import $ivy.`wow.doge:game:1.0-SNAPSHOT`
|
||||||
|
import $ivy.`wow.doge::mygame:1.0-SNAPSHOT`
|
||||||
|
// import wow.doge.game.types.GameScript
|
||||||
|
import com.jme3.scene.control.Control
|
||||||
|
|
||||||
|
// println("hello from script")
|
||||||
|
|
||||||
|
// class Scr extends GameScript {
|
||||||
|
// def start(): Unit = println("hello from start")
|
||||||
|
|
||||||
|
// def stop(): Unit = println("hello from stop")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // class SomeClass extends Control {}
|
||||||
|
|
||||||
|
// @main
|
||||||
|
// def main(): GameScript = new Scr()
|
||||||
|
import com.simsilica.es.base.DefaultEntityData
|
||||||
|
import com.simsilica.es.EntityData
|
||||||
|
import com.jme3.app.Application
|
||||||
|
import wow.doge.mygame.game.Implicits._
|
||||||
|
import wow.doge.mygame.components.TestComponent
|
||||||
|
import com.jme3.scene.shape.Box
|
||||||
|
import com.jme3.scene.Geometry
|
||||||
|
import com.jme3.material.Material
|
||||||
|
import com.jme3.math.ColorRGBA
|
||||||
|
import com.jme3.asset.AssetManager
|
||||||
|
import com.jme3.math.Vector3f
|
||||||
|
import wow.doge.mygame.state._
|
||||||
|
class TestAppState(
|
||||||
|
// private var _entity: Option[EntityData] = Some(new DefaultEntityData())
|
||||||
|
) extends MyBaseState {
|
||||||
|
protected lazy val b = new Box(1, 1, 1)
|
||||||
|
protected lazy val geom = new Geometry("Box", b)
|
||||||
|
protected lazy val mat = Material(
|
||||||
|
assetManager = assetManager,
|
||||||
|
path = "Common/MatDefs/Misc/Unshaded.j3md"
|
||||||
|
)
|
||||||
|
|
||||||
|
// def entity = _entity
|
||||||
|
// override def initialize(app: Application): Unit = {
|
||||||
|
// super.initialize(app)
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
override def init() = {
|
||||||
|
entityData
|
||||||
|
.createEntity()
|
||||||
|
.withComponents(TestComponent())
|
||||||
|
// entityData.setComponents(x, TestComponent())
|
||||||
|
val es = entityData.getEntities(classOf[TestComponent])
|
||||||
|
println(es)
|
||||||
|
geom.setMaterial(mat)
|
||||||
|
rootNode.attachChild(geom)
|
||||||
|
|
||||||
|
// geom.foreach(e => {
|
||||||
|
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
override def update(tpf: Float) = {
|
||||||
|
geom.rotate(0, 0.5f * tpf, 0)
|
||||||
|
geom.move(new Vector3f(0, 1 * tpf, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
override def cleanup(app: Application): Unit = {
|
||||||
|
// _entity.map(_.close())
|
||||||
|
// _entity = None
|
||||||
|
}
|
||||||
|
|
||||||
|
override def onEnable(): Unit = {}
|
||||||
|
|
||||||
|
override def onDisable(): Unit = {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object Material {
|
||||||
|
def apply(
|
||||||
|
color: String = "Color",
|
||||||
|
colorType: com.jme3.math.ColorRGBA = ColorRGBA.Blue,
|
||||||
|
assetManager: AssetManager,
|
||||||
|
path: String
|
||||||
|
): Material = {
|
||||||
|
val mat =
|
||||||
|
new Material(assetManager, path)
|
||||||
|
mat.setColor(color, colorType)
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@main
|
||||||
|
def main(): MyBaseState = new TestAppState()
|
19
src/main/resources/weapon.json
Normal file
19
src/main/resources/weapon.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"record": "Weapon",
|
||||||
|
"values": {
|
||||||
|
"baseId": "4F00000062",
|
||||||
|
"weaponType": "sword",
|
||||||
|
"name": "Exquisite Steel Sword",
|
||||||
|
"attack": "40",
|
||||||
|
"weight": "20"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val entity = ed.createEntity()
|
||||||
|
entity.setComponents(
|
||||||
|
Record("Weapon"),
|
||||||
|
WeaponType("Sword"),
|
||||||
|
Name("Exquisite Steel Sword"),
|
||||||
|
Attack(40),
|
||||||
|
Weight(20)
|
||||||
|
)
|
62
src/main/scala/com/jme3/animation/package.scala
Normal file
62
src/main/scala/com/jme3/animation/package.scala
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package com.jme3
|
||||||
|
|
||||||
|
import com.jme3.input.Action
|
||||||
|
|
||||||
|
package object animation {
|
||||||
|
|
||||||
|
implicit class AnimChannelWrap(val uval: AnimChannel) extends AnyVal {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current animation that is played by this AnimChannel.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* This resets the time to zero, and optionally blends the animation
|
||||||
|
* over <code>blendTime</code> 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(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 =
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
16
src/main/scala/com/jme3/app/package.scala
Normal file
16
src/main/scala/com/jme3/app/package.scala
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package com.jme3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Brandon Barker on 6/19/17.
|
||||||
|
*/
|
||||||
|
package object app {
|
||||||
|
|
||||||
|
implicit class SimpleApplicationWrap(val uval: SimpleApplication) extends AnyVal {
|
||||||
|
|
||||||
|
//FIXME: proof of concept, remove later
|
||||||
|
def testWrap: String = uval.hashCode().toString
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
6
src/main/scala/com/jme3/input/Action.scala
Normal file
6
src/main/scala/com/jme3/input/Action.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package com.jme3.input
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Brandon Barker on 6/19/17.
|
||||||
|
*/
|
||||||
|
final case class Action(name: String) extends AnyVal
|
37
src/main/scala/com/jme3/input/controls/package.scala
Normal file
37
src/main/scala/com/jme3/input/controls/package.scala
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package com.jme3.input
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Brandon Barker on 6/19/17.
|
||||||
|
*/
|
||||||
|
package object controls {
|
||||||
|
|
||||||
|
implicit class ActionListenerWrap(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.
|
||||||
|
*/
|
||||||
|
def onAction(action: Action, keyPressed: Boolean, tpf: Float): Unit =
|
||||||
|
uval.onAction(action.name, keyPressed, tpf)
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit class AnalogListenerWrap(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.
|
||||||
|
*/
|
||||||
|
def onAnalog(action: Action, value: Float, tpf: Float): Unit =
|
||||||
|
uval.onAnalog(action.name, value, tpf)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
18
src/main/scala/com/jme3/input/package.scala
Normal file
18
src/main/scala/com/jme3/input/package.scala
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package com.jme3
|
||||||
|
|
||||||
|
import com.jme3.input.controls.{InputListener, Trigger}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Brandon Barker on 6/21/17.
|
||||||
|
*/
|
||||||
|
package object input {
|
||||||
|
|
||||||
|
implicit class InputManagerWrap(val uval: InputManager) extends AnyVal {
|
||||||
|
def addMapping(action: Action, triggers: Trigger*): Unit =
|
||||||
|
uval.addMapping(action.name, triggers: _*)
|
||||||
|
def addListener(listener: InputListener, actions: Action*): Unit =
|
||||||
|
uval.addListener(listener, actions.map(act => act.name): _*)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
11
src/main/scala/com/jme3/material/package.scala
Normal file
11
src/main/scala/com/jme3/material/package.scala
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package com.jme3
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager
|
||||||
|
|
||||||
|
package object material {
|
||||||
|
|
||||||
|
object Material {
|
||||||
|
def apply(contentMan: AssetManager, defName: String): Material =
|
||||||
|
new Material(contentMan, defName)
|
||||||
|
}
|
||||||
|
}
|
19
src/main/scala/com/jme3/scene/debug/package.scala
Normal file
19
src/main/scala/com/jme3/scene/debug/package.scala
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package com.jme3.scene
|
||||||
|
|
||||||
|
import com.jme3.animation.Skeleton
|
||||||
|
|
||||||
|
package object debug {
|
||||||
|
|
||||||
|
object SkeletonDebugger {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a debugger with no length data. The wires will be a connection between the bones' heads only.
|
||||||
|
* The points will show the bones' heads only and no dotted line of inter bones connection will be visible.
|
||||||
|
* @param name
|
||||||
|
* the name of the debugger's node
|
||||||
|
* @param skeleton
|
||||||
|
* the skeleton that will be shown
|
||||||
|
*/
|
||||||
|
def apply(name: String, skeleton: Skeleton) = new SkeletonDebugger(name, skeleton)
|
||||||
|
}
|
||||||
|
}
|
56
src/main/scala/com/jme3/scene/package.scala
Normal file
56
src/main/scala/com/jme3/scene/package.scala
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package com.jme3
|
||||||
|
|
||||||
|
import com.jme3.scene.control.Control
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Brandon Barker on 6/19/17.
|
||||||
|
*/
|
||||||
|
package object scene {
|
||||||
|
|
||||||
|
object Geometry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a geometry node with mesh data.
|
||||||
|
* The material of the geometry is null, it cannot
|
||||||
|
* be rendered until it is set.
|
||||||
|
*
|
||||||
|
* @param name The name of this geometry
|
||||||
|
* @param mesh The mesh data for this geometry
|
||||||
|
*/
|
||||||
|
def apply(name: String, mesh: Mesh): Geometry = new Geometry(name, mesh)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object Node {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor instantiates a new <code>Node</code> with a default empty
|
||||||
|
* list for containing children.
|
||||||
|
*
|
||||||
|
* @param name the name of the scene element. This is required for
|
||||||
|
* identification and comparison purposes.
|
||||||
|
*/
|
||||||
|
def apply(name: String): Node = new Node(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit class NodeWrap(val uval: Node) extends AnyVal {
|
||||||
|
|
||||||
|
def getControlMaybe[T <: Control](controlType: Class[T]): Option[T] =
|
||||||
|
Option(uval.getControl(controlType))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit class SpatialWrap(val uval: Spatial) extends AnyVal {
|
||||||
|
|
||||||
|
def toNode: Either[ClassCastException, Node] =
|
||||||
|
uval match {
|
||||||
|
case ul: Node => Right(ul)
|
||||||
|
case ul =>
|
||||||
|
Left(
|
||||||
|
new ClassCastException(s"Couldn't convert ${ul.getName} to Node")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
20
src/main/scala/com/jme3/scene/shape/package.scala
Normal file
20
src/main/scala/com/jme3/scene/shape/package.scala
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package com.jme3.scene
|
||||||
|
|
||||||
|
package object shape {
|
||||||
|
|
||||||
|
object Box {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new box.
|
||||||
|
* <p>
|
||||||
|
* The box has a center of 0,0,0 and extends in the out from the center by
|
||||||
|
* the given amount in <em>each</em> direction. So, for example, a box
|
||||||
|
* with extent of 0.5 would be the unit cube.
|
||||||
|
*
|
||||||
|
* @param xs the size of the box along the x axis, in both directions.
|
||||||
|
* @param ys the size of the box along the y axis, in both directions.
|
||||||
|
* @param zs the size of the box along the z axis, in both directions.
|
||||||
|
*/
|
||||||
|
def apply(xs: Float, ys: Float, zs: Float): Box = new Box(xs, ys, zs)
|
||||||
|
}
|
||||||
|
}
|
14
src/main/scala/com/jme3/syntax/package.scala
Normal file
14
src/main/scala/com/jme3/syntax/package.scala
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package com.jme3
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Brandon Barker on 6/21/17.
|
||||||
|
*/
|
||||||
|
package object syntax {
|
||||||
|
|
||||||
|
@specialized def discard[A](evaluateForSideEffectOnly: A): Unit = {
|
||||||
|
val _: A = evaluateForSideEffectOnly
|
||||||
|
() //Return unit to prevent warning due to discarding value
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
5
src/main/scala/message.txt
Normal file
5
src/main/scala/message.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Hey guys, few days ago I discovered I could load objects created in scripts at runtime, and cast them to an interface to call their methods provided
|
||||||
|
1. both host program and script have access to the same interface via a common library
|
||||||
|
2. script object implements that interface
|
||||||
|
|
||||||
|
I was thinking, maybe I could implement appstates in scripts to implement game mechanics and attach them to the state manager at runtime, and similarly for components of an ECS. What do you guys think?
|
127
src/main/scala/wow/doge/mygame/Main.scala
Normal file
127
src/main/scala/wow/doge/mygame/Main.scala
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
package wow.doge.mygame
|
||||||
|
|
||||||
|
import game.GameApp
|
||||||
|
import com.jme3.app.StatsAppState
|
||||||
|
|
||||||
|
import akka.actor.typed.ActorSystem
|
||||||
|
import akka.actor.typed.SpawnProtocol
|
||||||
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
import akka.actor.typed.Behavior
|
||||||
|
import akka.util.Timeout
|
||||||
|
import com.jme3.system.AppSettings
|
||||||
|
import wow.doge.mygame.game.GameAppActor
|
||||||
|
import wow.doge.mygame.scriptsystem.ScriptCachingActor
|
||||||
|
object Main extends App {
|
||||||
|
import java.util.logging.{Logger, Level}
|
||||||
|
Logger.getLogger("").setLevel(Level.SEVERE)
|
||||||
|
|
||||||
|
// runner.runCode("""|println("starting scala script engine")""".stripMargin)
|
||||||
|
val gameApp = new GameApp(
|
||||||
|
// new EntityDataState(),
|
||||||
|
// new TestAppState(),
|
||||||
|
// new PlayerMovementState(),
|
||||||
|
// new FlyCamAppState(),
|
||||||
|
new StatsAppState()
|
||||||
|
)
|
||||||
|
val settings = new AppSettings(true)
|
||||||
|
// settings.setVSync(true)
|
||||||
|
settings.setFrameRate(144)
|
||||||
|
gameApp.setSettings(settings)
|
||||||
|
val actorSystem = ActorSystem(RootActor(gameApp), "rootActor")
|
||||||
|
// actorSystem.eventStream
|
||||||
|
// gameApp.start()
|
||||||
|
println("here 1")
|
||||||
|
// actorSystem.terminate()
|
||||||
|
// JMEExecutorService.shutdown()
|
||||||
|
// println("here 2")
|
||||||
|
//FIXME remove this
|
||||||
|
// System.exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
object RootActor {
|
||||||
|
def apply(app: GameApp): Behavior[SpawnProtocol.Command] =
|
||||||
|
Behaviors.setup { ctx =>
|
||||||
|
ctx.log.debug("Starting root actor")
|
||||||
|
val testActor = ctx.spawn(TestActor(), "testActor")
|
||||||
|
val _ = ctx.spawn(GameAppActor(app), "gameAppActor")
|
||||||
|
|
||||||
|
testActor ! TestActor.Test
|
||||||
|
SpawnProtocol()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object TestActor {
|
||||||
|
sealed trait Command
|
||||||
|
case object Test extends Command
|
||||||
|
private case object Done extends Command
|
||||||
|
// sealed trait Result
|
||||||
|
// case object Done extends Result
|
||||||
|
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
implicit val timeout = Timeout(15.seconds)
|
||||||
|
// implicit val scheduler =
|
||||||
|
|
||||||
|
def apply(): Behavior[Command] =
|
||||||
|
Behaviors.setup { ctx =>
|
||||||
|
ctx.spawn(ScriptCachingActor(), "scriptCacher")
|
||||||
|
Behaviors.receiveMessage { msg =>
|
||||||
|
msg match {
|
||||||
|
case Test =>
|
||||||
|
// ctx.ask(
|
||||||
|
// router,
|
||||||
|
// ScriptActor.Compile(
|
||||||
|
// // os.pwd / "some.sc",
|
||||||
|
// os.pwd / "src" / "main" / "resources" / "hello2.main.kts",
|
||||||
|
// _
|
||||||
|
// )
|
||||||
|
// ) {
|
||||||
|
// case Success(value) =>
|
||||||
|
// ctx.log.debug("Received Value")
|
||||||
|
// ctx.log.debug(value.toString())
|
||||||
|
// Done
|
||||||
|
// case Failure(exception) =>
|
||||||
|
// ctx.log.debug(s"Received Error ${exception.getMessage()}")
|
||||||
|
// Done
|
||||||
|
// }
|
||||||
|
// val x = scriptStorer
|
||||||
|
// .askT(
|
||||||
|
// ScriptStoringActor
|
||||||
|
// .Get(os.pwd / "src" / "main" / "resources" / "hello2.sc", _)
|
||||||
|
// )(timeout, ctx.system.scheduler)
|
||||||
|
|
||||||
|
// ctx.ask(
|
||||||
|
// scriptStorer,
|
||||||
|
// ScriptStoringActor
|
||||||
|
// .Get(os.pwd / "src" / "main" / "resources" / "hello2.sc", _)
|
||||||
|
// ) {
|
||||||
|
// case Success(value) => {
|
||||||
|
// ctx.log.debug(value.toString())
|
||||||
|
// ctx.ask(
|
||||||
|
// scriptStorer,
|
||||||
|
// ScriptStoringActor
|
||||||
|
// .Get(os.pwd / "src" / "main" / "resources" / "hello2.sc", _)
|
||||||
|
// ) {
|
||||||
|
// case Success(value) => {
|
||||||
|
// ctx.log.debug(value.toString())
|
||||||
|
// Done
|
||||||
|
// }
|
||||||
|
// case Failure(exception) =>
|
||||||
|
// ctx.log.debug(exception.getMessage())
|
||||||
|
// Done
|
||||||
|
// }
|
||||||
|
// Done
|
||||||
|
// }
|
||||||
|
// case Failure(exception) =>
|
||||||
|
// ctx.log.debug(exception.getMessage())
|
||||||
|
// Done
|
||||||
|
// }
|
||||||
|
|
||||||
|
Behaviors.same
|
||||||
|
case Done => Behaviors.same
|
||||||
|
}
|
||||||
|
|
||||||
|
// SpawnProtocol()
|
||||||
|
// Behaviors.same
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
src/main/scala/wow/doge/mygame/components/Position.scala
Normal file
6
src/main/scala/wow/doge/mygame/components/Position.scala
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package wow.doge.mygame.components
|
||||||
|
|
||||||
|
import com.simsilica.es.EntityComponent;
|
||||||
|
import wow.doge.mygame.math.ImVector3f
|
||||||
|
|
||||||
|
final case class Position(location: ImVector3f) extends EntityComponent
|
28
src/main/scala/wow/doge/mygame/components/Tag.scala
Normal file
28
src/main/scala/wow/doge/mygame/components/Tag.scala
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package wow.doge.mygame.components
|
||||||
|
|
||||||
|
import com.simsilica.es.EntityComponent
|
||||||
|
|
||||||
|
final case class Tag(name: String) extends EntityComponent
|
||||||
|
|
||||||
|
object Tag {
|
||||||
|
val SpaceShip = "SpaceShip"
|
||||||
|
val BasicInvader = "BasicInvader"
|
||||||
|
}
|
||||||
|
// public class Model implements EntityComponent {
|
||||||
|
// private final String name;
|
||||||
|
// public final static String SpaceShip = "SpaceShip";
|
||||||
|
// public final static String BasicInvader = "BasicInvader";
|
||||||
|
|
||||||
|
// public Model(String name) {
|
||||||
|
// this.name = name;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public String getName() {
|
||||||
|
// return name;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public String toString() {
|
||||||
|
// return "Model[" + name + "]";
|
||||||
|
// }
|
||||||
|
// }
|
11
src/main/scala/wow/doge/mygame/components/Test.java
Normal file
11
src/main/scala/wow/doge/mygame/components/Test.java
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package wow.doge.mygame.components;
|
||||||
|
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import wow.doge.mygame.math.ImVector3f;
|
||||||
|
|
||||||
|
//test java final case class instantiation
|
||||||
|
public class Test {
|
||||||
|
public void test() {
|
||||||
|
var pos = Position.apply(ImVector3f.apply(1, 1, 1));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package wow.doge.mygame.components
|
||||||
|
|
||||||
|
import com.simsilica.es.EntityComponent
|
||||||
|
|
||||||
|
final case class TestComponent() extends EntityComponent
|
139
src/main/scala/wow/doge/mygame/events/EventBus.scala
Normal file
139
src/main/scala/wow/doge/mygame/events/EventBus.scala
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
package wow.doge.mygame.events
|
||||||
|
|
||||||
|
// import akka.event.ActorEventBus
|
||||||
|
// import akka.event.ManagedActorClassification
|
||||||
|
// import akka.event.ActorClassifier
|
||||||
|
import akka.actor.typed.ActorRef
|
||||||
|
// import akka.actor.ActorSystem
|
||||||
|
// import akka.event.EventBus
|
||||||
|
// import akka.util.Subclassification
|
||||||
|
// import java.util.concurrent.atomic.AtomicReference
|
||||||
|
import akka.actor.typed.Behavior
|
||||||
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
import scala.reflect.ClassTag
|
||||||
|
import akka.event.EventStream
|
||||||
|
|
||||||
|
// private[events] final case class ClassificationMessage(ref: ActorRef, id: Int)
|
||||||
|
|
||||||
|
// class ActorBusImpl(val system: ActorSystem, val busSize: Int)
|
||||||
|
// extends ActorEventBus
|
||||||
|
// with ActorClassifier
|
||||||
|
// with ManagedActorClassification {
|
||||||
|
// type Event = ClassificationMessage
|
||||||
|
|
||||||
|
// // is used for extracting the classifier from the incoming events
|
||||||
|
// override protected def classify(event: Event): ActorRef = event.ref
|
||||||
|
|
||||||
|
// // determines the initial size of the index data structure
|
||||||
|
// // used internally (i.e. the expected number of different classifiers)
|
||||||
|
// override protected def mapSize: Int = busSize
|
||||||
|
// }
|
||||||
|
|
||||||
|
// class StartsWithSubclassification extends Subclassification[String] {
|
||||||
|
// override def isEqual(x: String, y: String): Boolean =
|
||||||
|
// x == y
|
||||||
|
|
||||||
|
// override def isSubclass(x: String, y: String): Boolean =
|
||||||
|
// x.startsWith(y)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// import akka.event.SubchannelClassification
|
||||||
|
|
||||||
|
// final case class MsgEnvelope(topic: String, payload: Any)
|
||||||
|
// import akka.actor.typed.scaladsl.adapter._
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Publishes the payload of the MsgEnvelope when the topic of the
|
||||||
|
// * MsgEnvelope starts with the String specified when subscribing.
|
||||||
|
// */
|
||||||
|
// class SubchannelBusImpl extends EventBus with SubchannelClassification {
|
||||||
|
// type Event = Any
|
||||||
|
// type Classifier = Class[_]
|
||||||
|
// type Subscriber = ActorRef
|
||||||
|
|
||||||
|
// // Subclassification is an object providing `isEqual` and `isSubclass`
|
||||||
|
// // to be consumed by the other methods of this classifier
|
||||||
|
// // override protected val subclassification: Subclassification[Classifier] =
|
||||||
|
// // new StartsWithSubclassification
|
||||||
|
|
||||||
|
// private val initiallySubscribedOrUnsubscriber =
|
||||||
|
// new AtomicReference[Either[Set[ActorRef], ActorRef]](Left(Set.empty))
|
||||||
|
|
||||||
|
// override protected implicit val subclassification
|
||||||
|
// : Subclassification[Classifier] = new Subclassification[Class[_]] {
|
||||||
|
// def isEqual(x: Class[_], y: Class[_]) = x == y
|
||||||
|
// def isSubclass(x: Class[_], y: Class[_]) = y.isAssignableFrom(x)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // is used for extracting the classifier from the incoming events
|
||||||
|
// override protected def classify(event: Event): Classifier = event.getClass()
|
||||||
|
|
||||||
|
// // will be invoked for each event for all subscribers which registered
|
||||||
|
// // themselves for the event’s classifier
|
||||||
|
// override protected def publish(event: Event, subscriber: Subscriber): Unit = {
|
||||||
|
// // subscriber ! event.payload
|
||||||
|
// subscriber ! event
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
object EventBus {
|
||||||
|
sealed trait Command[A]
|
||||||
|
final case class Publish[A, E <: A](event: E, publisher: ActorRef[_])
|
||||||
|
extends Command[A]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe a typed actor to listen for types or subtypes of E
|
||||||
|
* by sending this command to the [[akka.actor.typed.ActorSystem.eventStream]].
|
||||||
|
*
|
||||||
|
* ==Simple example==
|
||||||
|
* {{{
|
||||||
|
* sealed trait A
|
||||||
|
* case object A1 extends A
|
||||||
|
* //listen for all As
|
||||||
|
* def subscribe(actorSystem: ActorSystem[_], actorRef: ActorRef[A]) =
|
||||||
|
* actorSystem.eventStream ! EventStream.Subscribe(actorRef)
|
||||||
|
* //listen for A1s only
|
||||||
|
* def subscribe(actorSystem: ActorSystem[_], actorRef: ActorRef[A]) =
|
||||||
|
* actorSystem.eventStream ! EventStream.Subscribe[A1](actorRef)
|
||||||
|
* }}}
|
||||||
|
*/
|
||||||
|
final case class Subscribe[A, E <: A](subscriber: ActorRef[E])(implicit
|
||||||
|
classTag: ClassTag[E]
|
||||||
|
) extends Command[A] {
|
||||||
|
|
||||||
|
def topic: Class[_] = classTag.runtimeClass
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe an actor ref from the event stream
|
||||||
|
* by sending this command to the [[akka.actor.typed.ActorSystem.eventStream]].
|
||||||
|
*/
|
||||||
|
final case class Unsubscribe[A, E <: A](subscriber: ActorRef[E])
|
||||||
|
extends Command[A]
|
||||||
|
|
||||||
|
def apply[A](): Behavior[EventBus.Command[A]] =
|
||||||
|
Behaviors.setup { ctx =>
|
||||||
|
val eventStream = new EventStream(ctx.system.classicSystem)
|
||||||
|
new EventBus().eventStreamBehavior(eventStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class EventBus[B] {
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
|
||||||
|
private def eventStreamBehavior(
|
||||||
|
eventStream: akka.event.EventStream
|
||||||
|
): Behavior[EventBus.Command[B]] =
|
||||||
|
Behaviors.receiveMessage {
|
||||||
|
case EventBus.Publish(event, publisher) =>
|
||||||
|
eventStream.publish(event)
|
||||||
|
Behaviors.same
|
||||||
|
case s @ EventBus.Subscribe(subscriber) =>
|
||||||
|
eventStream.subscribe(subscriber.toClassic, s.topic)
|
||||||
|
Behaviors.same
|
||||||
|
case EventBus.Unsubscribe(subscriber) =>
|
||||||
|
eventStream.unsubscribe(subscriber.toClassic)
|
||||||
|
Behaviors.same
|
||||||
|
}
|
||||||
|
}
|
17
src/main/scala/wow/doge/mygame/events/Events.scala
Normal file
17
src/main/scala/wow/doge/mygame/events/Events.scala
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package wow.doge.mygame.events
|
||||||
|
|
||||||
|
// object Test {
|
||||||
|
|
||||||
|
// Events.BulletFired
|
||||||
|
// }
|
||||||
|
|
||||||
|
object Events {
|
||||||
|
sealed trait Event
|
||||||
|
case object BulletFired extends Event
|
||||||
|
// type BulletFired = BulletFired.type
|
||||||
|
case class EventWithData(data: Int) extends Event
|
||||||
|
|
||||||
|
sealed trait Tick extends Event
|
||||||
|
case object RenderTick extends Tick
|
||||||
|
case object PhysicsTick extends Tick
|
||||||
|
}
|
3
src/main/scala/wow/doge/mygame/events/EventsModule.scala
Normal file
3
src/main/scala/wow/doge/mygame/events/EventsModule.scala
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package wow.doge.mygame.events
|
||||||
|
|
||||||
|
trait EventsModule {}
|
@ -0,0 +1,5 @@
|
|||||||
|
package wow.doge.mygame.executors
|
||||||
|
|
||||||
|
trait ExecutorsModule {
|
||||||
|
lazy val schedulers = new Schedulers()
|
||||||
|
}
|
103
src/main/scala/wow/doge/mygame/executors/GUIExecutor.scala
Normal file
103
src/main/scala/wow/doge/mygame/executors/GUIExecutor.scala
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package wow.doge.mygame.executors
|
||||||
|
|
||||||
|
import akka.dispatch.{
|
||||||
|
DispatcherPrerequisites,
|
||||||
|
ExecutorServiceFactory,
|
||||||
|
ExecutorServiceConfigurator
|
||||||
|
}
|
||||||
|
import com.typesafe.config.Config
|
||||||
|
import java.util.concurrent.{
|
||||||
|
ExecutorService,
|
||||||
|
AbstractExecutorService,
|
||||||
|
ThreadFactory,
|
||||||
|
TimeUnit
|
||||||
|
}
|
||||||
|
import java.util.Collections
|
||||||
|
import javax.swing.SwingUtilities
|
||||||
|
import javafx.application.Platform
|
||||||
|
import monix.execution.Scheduler
|
||||||
|
import scala.concurrent.ExecutionContext
|
||||||
|
import java.util.concurrent.Executor
|
||||||
|
import wow.doge.mygame.Main
|
||||||
|
|
||||||
|
// First we wrap invokeLater/runLater as an ExecutorService
|
||||||
|
trait GUIExecutorService extends AbstractExecutorService {
|
||||||
|
def execute(command: Runnable): Unit
|
||||||
|
|
||||||
|
def shutdown(): Unit = ()
|
||||||
|
|
||||||
|
def shutdownNow() = Collections.emptyList[Runnable]
|
||||||
|
|
||||||
|
def isShutdown = false
|
||||||
|
|
||||||
|
def isTerminated = false
|
||||||
|
|
||||||
|
def awaitTermination(l: Long, timeUnit: TimeUnit) = true
|
||||||
|
}
|
||||||
|
|
||||||
|
object JavaFXExecutorService extends GUIExecutorService {
|
||||||
|
override def execute(command: Runnable) = Platform.runLater(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
object SwingExecutorService extends GUIExecutorService {
|
||||||
|
override def execute(command: Runnable) = SwingUtilities.invokeLater(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
object JMEExecutorService extends GUIExecutorService {
|
||||||
|
override def execute(command: Runnable) = Main.gameApp.enqueue(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
class JavaFXEventThreadExecutorServiceConfigurator(
|
||||||
|
config: Config,
|
||||||
|
prerequisites: DispatcherPrerequisites
|
||||||
|
) extends ExecutorServiceConfigurator(config, prerequisites) {
|
||||||
|
private val f = new ExecutorServiceFactory {
|
||||||
|
def createExecutorService: ExecutorService = JavaFXExecutorService
|
||||||
|
}
|
||||||
|
|
||||||
|
def createExecutorServiceFactory(
|
||||||
|
id: String,
|
||||||
|
threadFactory: ThreadFactory
|
||||||
|
): ExecutorServiceFactory = f
|
||||||
|
}
|
||||||
|
|
||||||
|
class JMEThreadExecutorServiceConfigurator(
|
||||||
|
config: Config,
|
||||||
|
prerequisites: DispatcherPrerequisites
|
||||||
|
) extends ExecutorServiceConfigurator(config, prerequisites) {
|
||||||
|
private val f = new ExecutorServiceFactory {
|
||||||
|
def createExecutorService: ExecutorService = JMEExecutorService
|
||||||
|
}
|
||||||
|
|
||||||
|
def createExecutorServiceFactory(
|
||||||
|
id: String,
|
||||||
|
threadFactory: ThreadFactory
|
||||||
|
): ExecutorServiceFactory = f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then we create an ExecutorServiceConfigurator so that Akka can use our SwingExecutorService for the dispatchers
|
||||||
|
class SwingEventThreadExecutorServiceConfigurator(
|
||||||
|
config: Config,
|
||||||
|
prerequisites: DispatcherPrerequisites
|
||||||
|
) extends ExecutorServiceConfigurator(config, prerequisites) {
|
||||||
|
private val f = new ExecutorServiceFactory {
|
||||||
|
def createExecutorService: ExecutorService = SwingExecutorService
|
||||||
|
}
|
||||||
|
|
||||||
|
def createExecutorServiceFactory(
|
||||||
|
id: String,
|
||||||
|
threadFactory: ThreadFactory
|
||||||
|
): ExecutorServiceFactory = f
|
||||||
|
}
|
||||||
|
|
||||||
|
object JFXExecutionContexts {
|
||||||
|
val javaFxExecutionContext: ExecutionContext =
|
||||||
|
ExecutionContext.fromExecutor(new Executor {
|
||||||
|
def execute(command: Runnable): Unit = {
|
||||||
|
Platform.runLater(command)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
val fxScheduler =
|
||||||
|
Scheduler(javaFxExecutionContext)
|
||||||
|
|
||||||
|
}
|
10
src/main/scala/wow/doge/mygame/executors/Schedulers.scala
Normal file
10
src/main/scala/wow/doge/mygame/executors/Schedulers.scala
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package wow.doge.mygame.executors
|
||||||
|
|
||||||
|
import monix.execution.Scheduler
|
||||||
|
|
||||||
|
final case class Schedulers(
|
||||||
|
blockingIO: Scheduler = Scheduler.io(),
|
||||||
|
cpu: Scheduler = Scheduler.global,
|
||||||
|
fx: Scheduler = JFXExecutionContexts.fxScheduler,
|
||||||
|
jme: Option[Scheduler] = None
|
||||||
|
)
|
109
src/main/scala/wow/doge/mygame/game/GameApp.scala
Normal file
109
src/main/scala/wow/doge/mygame/game/GameApp.scala
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package wow.doge.mygame.game
|
||||||
|
|
||||||
|
import com.jme3.app.SimpleApplication
|
||||||
|
|
||||||
|
import com.jme3.app.state.AppState
|
||||||
|
import akka.actor.typed.ActorRef
|
||||||
|
import akka.actor.typed.Behavior
|
||||||
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
|
||||||
|
object Greeter {
|
||||||
|
final case class Greet(whom: String, replyTo: ActorRef[Greeted])
|
||||||
|
final case class Greeted(whom: String, from: ActorRef[Greet])
|
||||||
|
|
||||||
|
def apply(): Behavior[Greet] =
|
||||||
|
Behaviors.receive { (context, message) =>
|
||||||
|
// context.log.info("Hello {}!", message.whom)
|
||||||
|
//#greeter-send-messages
|
||||||
|
message.replyTo ! Greeted(message.whom, context.self)
|
||||||
|
//#greeter-send-messages
|
||||||
|
Behaviors.same
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameApp(
|
||||||
|
// actorSystem: ActorSystem[SpawnProtocol.Command],
|
||||||
|
appStates: AppState*
|
||||||
|
) extends SimpleApplication(appStates: _*) {
|
||||||
|
// implicit val timeout = Timeout(10.seconds)
|
||||||
|
// implicit val scheduler = actorSystem.scheduler
|
||||||
|
|
||||||
|
override def simpleInitApp(): Unit = {
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
|
||||||
|
// geom.updateModelBound()
|
||||||
|
// geom.updateGeometricState()
|
||||||
|
}
|
||||||
|
|
||||||
|
// override def stop(): Unit = {
|
||||||
|
// actorSystem.terminate()
|
||||||
|
// super.stop()
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object GameApp {
|
||||||
|
// def myExec(app: SimpleApplication, command: Runnable) = {
|
||||||
|
// app.enqueue(command)
|
||||||
|
// }
|
||||||
|
// val javaFxExecutionContext: ExecutionContext =
|
||||||
|
// ExecutionContext.fromExecutor(new Executor {
|
||||||
|
// def execute(command: Runnable): Unit = {
|
||||||
|
// Platform.runLater(command)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// def jmeEC(app: SimpleApplication): ExecutionContext =
|
||||||
|
// ExecutionContext.fromExecutor(new Executor {
|
||||||
|
// override def execute(command: Runnable): Unit = app.enqueue(command)
|
||||||
|
// })
|
||||||
|
|
||||||
|
// def jmeScheduler(app: SimpleApplication) = Sch
|
||||||
|
}
|
67
src/main/scala/wow/doge/mygame/game/GameAppActor.scala
Normal file
67
src/main/scala/wow/doge/mygame/game/GameAppActor.scala
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package wow.doge.mygame.game
|
||||||
|
|
||||||
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
import wow.doge.mygame.state.MovementActor
|
||||||
|
import wow.doge.mygame.state.PlayerMovementState2
|
||||||
|
import wow.doge.mygame.state.MovementActorTimer
|
||||||
|
import com.jme3.scene.shape.Box
|
||||||
|
import com.jme3.scene.Geometry
|
||||||
|
import wow.doge.mygame.implicits._
|
||||||
|
import wow.doge.mygame.events.EventBus
|
||||||
|
import wow.doge.mygame.events.Events
|
||||||
|
import wow.doge.mygame.state.ImMovementActor
|
||||||
|
|
||||||
|
object GameAppActor {
|
||||||
|
|
||||||
|
sealed trait Command
|
||||||
|
def apply(app: GameApp) =
|
||||||
|
Behaviors.setup[Command] { ctx =>
|
||||||
|
lazy val b = new Box(1, 1, 1)
|
||||||
|
lazy val geom = new Geometry("Box", b)
|
||||||
|
val movementActor =
|
||||||
|
ctx.spawn(
|
||||||
|
MovementActor(MovementActor.Props(app, geom)),
|
||||||
|
"movementActor"
|
||||||
|
// DispatcherSelector.fromConfig("jme-dispatcher")
|
||||||
|
)
|
||||||
|
|
||||||
|
val movementActorTimer = ctx.spawn(
|
||||||
|
MovementActorTimer(movementActor),
|
||||||
|
"movementActorTimer"
|
||||||
|
)
|
||||||
|
val imMovementActor = ctx.spawn(
|
||||||
|
ImMovementActor(ImMovementActor.Props(app, geom)),
|
||||||
|
"imMovementActor"
|
||||||
|
)
|
||||||
|
|
||||||
|
val subscribingActor = ctx.spawn(SubscribingActor(), "subscriber-1")
|
||||||
|
|
||||||
|
val eventBus =
|
||||||
|
ctx.spawn(Behaviors.logMessages(EventBus[Events.Tick]()), "eventBus1")
|
||||||
|
|
||||||
|
eventBus ! EventBus.Subscribe(subscribingActor)
|
||||||
|
|
||||||
|
eventBus ! EventBus.Publish(Events.PhysicsTick, ctx.self)
|
||||||
|
|
||||||
|
app
|
||||||
|
.getStateManager()
|
||||||
|
.attach(
|
||||||
|
new PlayerMovementState2(
|
||||||
|
movementActor,
|
||||||
|
movementActorTimer,
|
||||||
|
imMovementActor,
|
||||||
|
geom
|
||||||
|
)
|
||||||
|
)
|
||||||
|
app.start()
|
||||||
|
Behaviors.stopped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object SubscribingActor {
|
||||||
|
def apply() =
|
||||||
|
Behaviors.receive[Events.PhysicsTick.type] { (ctx, msg) =>
|
||||||
|
ctx.log.debug(s"received event $msg")
|
||||||
|
Behaviors.same
|
||||||
|
}
|
||||||
|
}
|
55
src/main/scala/wow/doge/mygame/implicits/EntityQuery.scala
Normal file
55
src/main/scala/wow/doge/mygame/implicits/EntityQuery.scala
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package wow.doge.mygame.implicits
|
||||||
|
|
||||||
|
import com.simsilica.es.ComponentFilter
|
||||||
|
import com.simsilica.es.EntityComponent
|
||||||
|
import com.simsilica.es.EntityData
|
||||||
|
import com.simsilica.es.EntitySet
|
||||||
|
import com.simsilica.es.Filters
|
||||||
|
import scala.reflect.ClassTag
|
||||||
|
import scala.util.Try
|
||||||
|
|
||||||
|
class EntityQuery(ed: EntityData) {
|
||||||
|
private var cfilter: Option[ComponentFilter[_ <: EntityComponent]] = None
|
||||||
|
private val buf = collection.mutable.ListBuffer.empty[Class[_]]
|
||||||
|
|
||||||
|
def filter[T <: EntityComponent](field: String, value: Object)(implicit
|
||||||
|
ev: ClassTag[T]
|
||||||
|
): EntityQuery = {
|
||||||
|
val c = ev.runtimeClass.asInstanceOf[Class[T]]
|
||||||
|
cfilter = Try(Filters.fieldEquals(c, field, value)).toOption
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
def filterOr[T <: EntityComponent](operands: ComponentFilter[_ <: T]*)(
|
||||||
|
implicit ev: ClassTag[T]
|
||||||
|
): EntityQuery = {
|
||||||
|
val c = ev.runtimeClass.asInstanceOf[Class[T]]
|
||||||
|
cfilter = Try(Filters.or(c, operands: _*)).toOption
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
def filterAnd[T <: EntityComponent](operands: ComponentFilter[_ <: T]*)(
|
||||||
|
implicit ev: ClassTag[T]
|
||||||
|
): EntityQuery = {
|
||||||
|
val c = ev.runtimeClass.asInstanceOf[Class[T]]
|
||||||
|
cfilter = Try(Filters.and(c, operands: _*)).toOption
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
def component[T <: EntityComponent]()(implicit
|
||||||
|
ev: ClassTag[T]
|
||||||
|
): EntityQuery = {
|
||||||
|
val c = ev.runtimeClass
|
||||||
|
buf += c
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
def components[T <: EntityComponent](lst: Class[T]*): EntitySet = {
|
||||||
|
ed.getEntities(lst: _*)
|
||||||
|
}
|
||||||
|
|
||||||
|
def result: EntitySet =
|
||||||
|
cfilter.fold(ed.getEntities(buf.toList: _*)) { filters =>
|
||||||
|
ed.getEntities(filters, buf.toList: _*)
|
||||||
|
}
|
||||||
|
}
|
175
src/main/scala/wow/doge/mygame/implicits/package.scala
Normal file
175
src/main/scala/wow/doge/mygame/implicits/package.scala
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
package wow.doge.mygame
|
||||||
|
|
||||||
|
import com.jme3.app.SimpleApplication
|
||||||
|
import com.jme3.app.state.AppStateManager
|
||||||
|
import scala.reflect.ClassTag
|
||||||
|
import com.jme3.app.state.AppState
|
||||||
|
import com.jme3.scene.Node
|
||||||
|
import com.jme3.scene.Spatial
|
||||||
|
import com.simsilica.es.EntityData
|
||||||
|
import com.simsilica.es.EntityComponent
|
||||||
|
import com.simsilica.es.EntityId
|
||||||
|
import akka.actor.typed.ActorRef
|
||||||
|
import akka.util.Timeout
|
||||||
|
import akka.actor.typed.Scheduler
|
||||||
|
import monix.eval.Task
|
||||||
|
import com.jme3.input.InputManager
|
||||||
|
import com.jme3.input.controls.Trigger
|
||||||
|
import com.jme3.input.controls.InputListener
|
||||||
|
import com.jme3.math.Vector3f
|
||||||
|
import wow.doge.mygame.math.ImVector3f
|
||||||
|
import com.jme3.scene.Geometry
|
||||||
|
import wow.doge.mygame.state.CardinalDirection
|
||||||
|
import wow.doge.mygame.state.CanMove
|
||||||
|
import com.jme3.renderer.Camera
|
||||||
|
|
||||||
|
package object implicits {
|
||||||
|
implicit class StateManagerExt(val sm: AppStateManager) extends AnyVal {
|
||||||
|
def state[S <: AppState]()(implicit c: ClassTag[S]): S =
|
||||||
|
sm.getState(c.runtimeClass.asInstanceOf[Class[S]])
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit class SimpleApplicationExt(val sa: SimpleApplication)
|
||||||
|
extends AnyVal {
|
||||||
|
def stateManager() = sa.getStateManager()
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit class NodeExt(val n: Node) extends AnyVal {
|
||||||
|
def child(s: Spatial): Node = {
|
||||||
|
n.attachChild(s)
|
||||||
|
n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit class EntityDataExt(val ed: EntityData) extends AnyVal {
|
||||||
|
|
||||||
|
def query = new EntityQuery(ed)
|
||||||
|
|
||||||
|
// def entities[T <: EntityComponent](entities: Seq[T])
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit class EntityExt(val e: EntityId) extends AnyVal {
|
||||||
|
def withComponents(classes: EntityComponent*)(implicit
|
||||||
|
ed: EntityData
|
||||||
|
): EntityId = {
|
||||||
|
ed.setComponents(e, classes: _*)
|
||||||
|
e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit class ActorRefExt[Req](val a: ActorRef[Req]) extends AnyVal {
|
||||||
|
import akka.actor.typed.scaladsl.AskPattern._
|
||||||
|
def askT[Res](
|
||||||
|
replyTo: ActorRef[Res] => Req
|
||||||
|
)(implicit timeout: Timeout, scheduler: Scheduler): Task[Res] = {
|
||||||
|
Task.deferFuture(a.ask(replyTo)(timeout, scheduler))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// def ?[Res](replyTo: ActorRef[Res] => Req)(implicit timeout: Timeout, scheduler: Scheduler): Future[Res] = {
|
||||||
|
// ask(replyTo)(timeout, scheduler)
|
||||||
|
// }
|
||||||
|
|
||||||
|
implicit class InputManagerExt(val inputManager: InputManager)
|
||||||
|
extends AnyVal {
|
||||||
|
def withMapping(mapping: String, triggers: Trigger*): InputManager = {
|
||||||
|
inputManager.addMapping(mapping, triggers: _*)
|
||||||
|
inputManager
|
||||||
|
}
|
||||||
|
|
||||||
|
def withListener(listener: InputListener, mappings: String*) = {
|
||||||
|
inputManager.addListener(listener, mappings: _*)
|
||||||
|
inputManager
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit class Vector3fExt(val v: Vector3f) extends AnyVal {
|
||||||
|
def +=(that: Vector3f) = v.addLocal(that)
|
||||||
|
def *=(that: Vector3f) = v.multLocal(that)
|
||||||
|
def -=(that: Vector3f) = v.subtractLocal(that)
|
||||||
|
def /=(that: Vector3f) = v.divideLocal(that)
|
||||||
|
def unary_- = v.negateLocal()
|
||||||
|
def immutable = ImVector3f(v.x, v.y, v.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit class ImVector3fExt(val v: ImVector3f) extends AnyVal {
|
||||||
|
def +(that: ImVector3f) = v.copy(v.x + that.x, v.y + that.y, v.z + that.z)
|
||||||
|
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.x * f)
|
||||||
|
v * ImVector3f(f, f, f)
|
||||||
|
def -(that: ImVector3f) = v.copy(v.x - that.x, v.y - that.y, v.z - that.z)
|
||||||
|
def /(that: ImVector3f) = v.copy(v.x / that.x, v.y / that.y, v.z / that.z)
|
||||||
|
def unary_- = v.copy(-v.x, -v.y, -v.z)
|
||||||
|
// def unary_-(that: ImVector3f) = this.copy(this.x, this.y, this.z)
|
||||||
|
def mutable = new Vector3f(v.x, v.y, v.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
// implicit val implVector3fForVector3 = new Vector3[Vector3f] {
|
||||||
|
// override def +(implicit v: Vector3f, that: com.jme3.math.Vector3f): Unit =
|
||||||
|
// v += that
|
||||||
|
|
||||||
|
// override def *(implicit v: Vector3f, that: Vector3f): Unit = v *= that
|
||||||
|
|
||||||
|
// override def -(implicit v: Vector3f, that: Vector3f): Unit = v -= that
|
||||||
|
|
||||||
|
// override def /(implicit v: Vector3f, that: Vector3f): Unit = v /= that
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// implicit val implImVector3fForVector3 = new Vector3[ImVector3f] {
|
||||||
|
// override def +(implicit v: ImVector3f, that: ImVector3f): Unit =
|
||||||
|
// v + that
|
||||||
|
|
||||||
|
// override def *(implicit v: ImVector3f, that: ImVector3f): Unit = v * that
|
||||||
|
|
||||||
|
// override def -(implicit v: ImVector3f, that: ImVector3f): Unit = v - that
|
||||||
|
|
||||||
|
// override def /(implicit v: ImVector3f, that: ImVector3f): Unit = v / that
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// def test[T](v: T)(implicit ev: Vector3[T]) = {
|
||||||
|
// import ev._
|
||||||
|
// ev.+
|
||||||
|
// }
|
||||||
|
|
||||||
|
implicit val implCanMoveForGeom = new CanMove[Geometry] {
|
||||||
|
override def getDirection(
|
||||||
|
cam: Camera,
|
||||||
|
cardinalDir: CardinalDirection
|
||||||
|
): ImVector3f = {
|
||||||
|
val camDir =
|
||||||
|
cam.getDirection().immutable * 0.6f
|
||||||
|
val camLeft = cam.getLeft().immutable * 0.4f
|
||||||
|
|
||||||
|
val zero = ImVector3f.ZERO
|
||||||
|
val dir = cardinalDir
|
||||||
|
val walkDir = {
|
||||||
|
val mutWalkDir = new Vector3f()
|
||||||
|
if (dir.left) {
|
||||||
|
// ctx.log.trace("left")
|
||||||
|
mutWalkDir += (zero + camLeft).mutable
|
||||||
|
}
|
||||||
|
if (dir.right) {
|
||||||
|
// ctx.log.trace("right")
|
||||||
|
mutWalkDir += (zero + -camLeft).mutable
|
||||||
|
}
|
||||||
|
if (dir.up) {
|
||||||
|
// ctx.log.trace("up")
|
||||||
|
mutWalkDir += (zero + camDir).mutable
|
||||||
|
}
|
||||||
|
if (dir.down) {
|
||||||
|
// ctx.log.trace("down")
|
||||||
|
mutWalkDir += (zero + -camDir).mutable
|
||||||
|
}
|
||||||
|
mutWalkDir.immutable
|
||||||
|
}
|
||||||
|
walkDir
|
||||||
|
}
|
||||||
|
override def move(geom: Geometry, direction: ImVector3f): Unit = {
|
||||||
|
val v = geom.getLocalTranslation()
|
||||||
|
geom.setLocalTranslation(v += direction.mutable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
src/main/scala/wow/doge/mygame/math/ImVector3f.scala
Normal file
11
src/main/scala/wow/doge/mygame/math/ImVector3f.scala
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package wow.doge.mygame.math
|
||||||
|
|
||||||
|
case class ImVector3f(x: Float = 0f, y: Float = 0f, z: Float = 0f)
|
||||||
|
|
||||||
|
object ImVector3f {
|
||||||
|
val ZERO = ImVector3f(0, 0, 0)
|
||||||
|
val UNIT_X = ImVector3f(1, 0, 0)
|
||||||
|
val UNIT_Y = ImVector3f(0, 1, 0)
|
||||||
|
val UNIT_Z = ImVector3f(0, 0, 1)
|
||||||
|
|
||||||
|
}
|
157
src/main/scala/wow/doge/mygame/scriptsystem/ScriptActor.scala
Normal file
157
src/main/scala/wow/doge/mygame/scriptsystem/ScriptActor.scala
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
package wow.doge.mygame.state
|
||||||
|
|
||||||
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
import ammonite.Main
|
||||||
|
import akka.actor.typed.ActorRef
|
||||||
|
import com.jme3.app.state.AppState
|
||||||
|
import ammonite.runtime.Storage.Folder
|
||||||
|
import ammonite.main.Defaults
|
||||||
|
import akka.actor.typed.Behavior
|
||||||
|
import akka.actor.typed.scaladsl.ActorContext
|
||||||
|
import ammonite.util.Res.Success
|
||||||
|
import javax.script.ScriptEngine
|
||||||
|
import javax.script.ScriptEngineManager
|
||||||
|
import scala.util.Try
|
||||||
|
import cats.implicits._
|
||||||
|
|
||||||
|
object ScriptActor {
|
||||||
|
sealed trait Result
|
||||||
|
final case class AppStateResult(state: AppState) extends Result
|
||||||
|
final case class Error(reason: String) extends Result
|
||||||
|
|
||||||
|
sealed trait Command
|
||||||
|
final case class Compile(path: os.Path, sender: ActorRef[Result])
|
||||||
|
extends Command
|
||||||
|
|
||||||
|
final case class CompileAny(
|
||||||
|
path: os.Path,
|
||||||
|
result: ActorRef[Either[Error, Any]]
|
||||||
|
) extends Command
|
||||||
|
|
||||||
|
def defaultScalaRunner() =
|
||||||
|
ammonite
|
||||||
|
.Main(
|
||||||
|
storageBackend = new Folder(
|
||||||
|
// os.pwd / "target"
|
||||||
|
Defaults.ammoniteHome,
|
||||||
|
isRepl = false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def defaultKotlinRunner(): ScriptEngine = {
|
||||||
|
val manager = new ScriptEngineManager()
|
||||||
|
val engine = manager.getEngineByExtension("main.kts")
|
||||||
|
engine
|
||||||
|
}
|
||||||
|
|
||||||
|
def apply(
|
||||||
|
scalaRunner: Main = defaultScalaRunner(),
|
||||||
|
kotlinRunner: ScriptEngine = defaultKotlinRunner()
|
||||||
|
// parent: ActorRef[ScriptStoringActor.Command]
|
||||||
|
): Behavior[ScriptActor.Command] =
|
||||||
|
Behaviors.setup(ctx =>
|
||||||
|
new ScriptActor(scalaRunner, kotlinRunner, ctx).receiveMessage
|
||||||
|
)
|
||||||
|
|
||||||
|
sealed trait ScriptType
|
||||||
|
case object ScalaType extends ScriptType
|
||||||
|
case object KotlinType extends ScriptType
|
||||||
|
case object GroovyType extends ScriptType
|
||||||
|
|
||||||
|
def determineScriptType(path: os.Path): Either[Error, ScriptType] =
|
||||||
|
path.toString match {
|
||||||
|
case s if s.endsWith(".sc") => Right(ScalaType)
|
||||||
|
case s if s.endsWith(".main.kts") => Right(KotlinType)
|
||||||
|
case s if s.endsWith(".groovy") => Right(GroovyType)
|
||||||
|
case _ => Left(Error("Unknown script type"))
|
||||||
|
}
|
||||||
|
|
||||||
|
def runScala(path: os.Path, scalaRunner: ammonite.Main): Either[Error, Any] =
|
||||||
|
scalaRunner
|
||||||
|
.runScript(
|
||||||
|
path,
|
||||||
|
Seq.empty
|
||||||
|
)
|
||||||
|
._1 match {
|
||||||
|
case ammonite.util.Res.Exception(t, msg) => Left(Error(msg))
|
||||||
|
|
||||||
|
case Success(obj) => Right(obj)
|
||||||
|
|
||||||
|
case _ => Left(Error("Failed to run script"))
|
||||||
|
}
|
||||||
|
|
||||||
|
def runKotlin(path: os.Path, kotlinRunner: ScriptEngine): Either[Error, Any] =
|
||||||
|
Try(kotlinRunner.eval(os.read(path))).toEither.leftMap(t =>
|
||||||
|
Error(t.getMessage())
|
||||||
|
)
|
||||||
|
|
||||||
|
def runGroovy(path: os.Path): Either[Error, Any] =
|
||||||
|
Left(Error("Not implemented yet"))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScriptActor(
|
||||||
|
val scalaRunner: Main,
|
||||||
|
val kotlinRunner: ScriptEngine,
|
||||||
|
// parent: ActorRef[ScriptStoringActor.Command],
|
||||||
|
context: ActorContext[ScriptActor.Command]
|
||||||
|
) {
|
||||||
|
import ScriptActor._
|
||||||
|
|
||||||
|
def receiveMessage: Behavior[Command] =
|
||||||
|
Behaviors.receiveMessage { msg =>
|
||||||
|
msg match {
|
||||||
|
case Compile(path, sender) =>
|
||||||
|
context.log.debug(s"Received $path")
|
||||||
|
val res = getScript(path)
|
||||||
|
sender ! res
|
||||||
|
Behaviors.same
|
||||||
|
// case CompileScripts(sender, paths) =>
|
||||||
|
case CompileAny(path, requester) =>
|
||||||
|
context.log.debug(s"Received $path")
|
||||||
|
val res = getScript2(path)
|
||||||
|
context.log.debug(s"result = $res")
|
||||||
|
requester ! res
|
||||||
|
// parent ! ScriptStoringActor.Put(path, res)
|
||||||
|
Behaviors.same
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def getScript(path: os.Path) = {
|
||||||
|
val res = determineScriptType(path) match {
|
||||||
|
case Right(ScalaType) => runScala(path, scalaRunner)
|
||||||
|
case Right(KotlinType) => runKotlin(path, kotlinRunner)
|
||||||
|
case Right(GroovyType) => runGroovy(path)
|
||||||
|
case l @ Left(err) => l
|
||||||
|
}
|
||||||
|
|
||||||
|
res match {
|
||||||
|
case Left(err) => err
|
||||||
|
case Right(obj) =>
|
||||||
|
obj match {
|
||||||
|
case s: MyBaseState => AppStateResult(s)
|
||||||
|
case _ => Error("Class in script does not match known types")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def getScript2(path: os.Path): Either[Error, Any] = {
|
||||||
|
val res = determineScriptType(path) match {
|
||||||
|
case Right(ScalaType) => runScala(path, scalaRunner)
|
||||||
|
case Right(KotlinType) => runKotlin(path, kotlinRunner)
|
||||||
|
case Right(GroovyType) => runGroovy(path)
|
||||||
|
case l @ Left(err) => l
|
||||||
|
}
|
||||||
|
|
||||||
|
// res match {
|
||||||
|
// case Left(err) => err
|
||||||
|
// case Right(obj) =>
|
||||||
|
// obj match {
|
||||||
|
// case s: MyBaseState => AppStateResult(s)
|
||||||
|
// case _ => Error("Class in script does not match known types")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,166 @@
|
|||||||
|
package wow.doge.mygame.scriptsystem
|
||||||
|
|
||||||
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
import akka.actor.typed.scaladsl.PoolRouter
|
||||||
|
import akka.actor.typed.scaladsl.Routers
|
||||||
|
import wow.doge.mygame.state.ScriptActor
|
||||||
|
import akka.actor.typed.ActorRef
|
||||||
|
import akka.actor.typed.scaladsl.ActorContext
|
||||||
|
import akka.actor.typed.Behavior
|
||||||
|
import akka.util.Timeout
|
||||||
|
import scala.util.Success
|
||||||
|
import scala.util.Failure
|
||||||
|
import akka.actor.typed.SupervisorStrategy
|
||||||
|
|
||||||
|
object ScriptCachingActor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* aka script representation
|
||||||
|
*/
|
||||||
|
type ScriptRepr = Any
|
||||||
|
type ScriptsMap = Map[os.Path, ScriptRepr]
|
||||||
|
type ScriptResult = Either[ScriptActor.Error, ScriptRepr]
|
||||||
|
|
||||||
|
sealed trait Command
|
||||||
|
final case class Get(
|
||||||
|
scriptPath: os.Path,
|
||||||
|
requester: ActorRef[ScriptResult]
|
||||||
|
) extends Command
|
||||||
|
final case class GetMap(requester: ActorRef[ScriptsMap]) extends Command
|
||||||
|
final case class Put(scriptPath: os.Path, script: ScriptRepr) extends Command
|
||||||
|
private final case object NoOp extends Command
|
||||||
|
|
||||||
|
private final case class DelegateToChild(
|
||||||
|
scriptActor: ActorRef[ScriptActor.Command],
|
||||||
|
scriptPath: os.Path,
|
||||||
|
requester: ActorRef[ScriptResult]
|
||||||
|
) extends Command
|
||||||
|
|
||||||
|
final case class Props(
|
||||||
|
ctx: ActorContext[Command],
|
||||||
|
scriptActor: ActorRef[ScriptActor.Command]
|
||||||
|
)
|
||||||
|
final case class State(scriptsMap: ScriptsMap)
|
||||||
|
def apply(state: State = State(Map.empty)): Behavior[Command] =
|
||||||
|
Behaviors.logMessages {
|
||||||
|
Behaviors.setup { ctx =>
|
||||||
|
val pool = ScriptActorPool(4)
|
||||||
|
val scriptsRouter = ctx.spawn(pool, "script-actors-pool")
|
||||||
|
new ScriptCachingActor(Props(ctx, scriptsRouter)).receiveMessage(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def getOrCompileScript(
|
||||||
|
ctx: ActorContext[Command],
|
||||||
|
scriptPath: os.Path,
|
||||||
|
scriptsMap: ScriptsMap,
|
||||||
|
scriptActor: ActorRef[ScriptActor.Command],
|
||||||
|
requester: ActorRef[ScriptResult]
|
||||||
|
) = {
|
||||||
|
scriptsMap
|
||||||
|
.get(scriptPath)
|
||||||
|
.fold {
|
||||||
|
ctx.log.debug("Delegating to child")
|
||||||
|
ctx.self ! DelegateToChild(
|
||||||
|
scriptActor,
|
||||||
|
scriptPath,
|
||||||
|
requester
|
||||||
|
)
|
||||||
|
} { s =>
|
||||||
|
ctx.log.debug("Getting script from cache")
|
||||||
|
requester ! Right(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def askChildForScriptCompilation(
|
||||||
|
ctx: ActorContext[Command],
|
||||||
|
scriptActor: ActorRef[ScriptActor.Command],
|
||||||
|
scriptPath: os.Path,
|
||||||
|
requester: ActorRef[ScriptResult]
|
||||||
|
)(implicit timeout: Timeout) = {
|
||||||
|
ctx.ask(scriptActor, ScriptActor.CompileAny(scriptPath, _)) {
|
||||||
|
case Success(value) =>
|
||||||
|
requester ! value
|
||||||
|
value.fold(
|
||||||
|
err => {
|
||||||
|
ctx.log.error(err.reason)
|
||||||
|
NoOp
|
||||||
|
},
|
||||||
|
res => {
|
||||||
|
Put(scriptPath, res)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
case Failure(exception) => {
|
||||||
|
ctx.log.error(exception.getMessage())
|
||||||
|
NoOp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScriptCachingActor(props: ScriptCachingActor.Props) {
|
||||||
|
import com.softwaremill.quicklens._
|
||||||
|
import ScriptCachingActor._
|
||||||
|
def receiveMessage(state: State): Behavior[Command] =
|
||||||
|
Behaviors.receiveMessage { msg =>
|
||||||
|
msg match {
|
||||||
|
case Get(scriptPath, requester) =>
|
||||||
|
getOrCompileScript(
|
||||||
|
props.ctx,
|
||||||
|
scriptPath,
|
||||||
|
state.scriptsMap,
|
||||||
|
props.scriptActor,
|
||||||
|
requester
|
||||||
|
)
|
||||||
|
Behaviors.same
|
||||||
|
|
||||||
|
case DelegateToChild(scriptActor, scriptPath, requester) =>
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
implicit val timeout = Timeout(15.seconds)
|
||||||
|
// child ! ScriptActor.CompileAny(scriptPath, requester)
|
||||||
|
askChildForScriptCompilation(
|
||||||
|
props.ctx,
|
||||||
|
scriptActor,
|
||||||
|
scriptPath,
|
||||||
|
requester
|
||||||
|
)
|
||||||
|
Behaviors.same
|
||||||
|
|
||||||
|
case GetMap(requester) =>
|
||||||
|
requester ! state.scriptsMap
|
||||||
|
Behaviors.same
|
||||||
|
|
||||||
|
case Put(scriptPath, script) =>
|
||||||
|
props.ctx.log.debug(s"Putting $script at path $scriptPath")
|
||||||
|
val newState =
|
||||||
|
state.modify(_.scriptsMap).using(_ + (scriptPath -> script))
|
||||||
|
props.ctx.log.debug(newState.toString())
|
||||||
|
receiveMessage(state = newState)
|
||||||
|
|
||||||
|
case NoOp => Behaviors.same
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ScriptActorPool {
|
||||||
|
def apply(
|
||||||
|
poolSize: Int
|
||||||
|
): PoolRouter[ScriptActor.Command] =
|
||||||
|
Routers.pool(poolSize = poolSize)(
|
||||||
|
// make sure the workers are restarted if they fail
|
||||||
|
Behaviors
|
||||||
|
.supervise(ScriptActor())
|
||||||
|
.onFailure[Exception](SupervisorStrategy.restart)
|
||||||
|
)
|
||||||
|
|
||||||
|
// def apply(
|
||||||
|
// poolSize: Int,
|
||||||
|
// parent: ActorRef[ScriptStoringActor.Command]
|
||||||
|
// ): PoolRouter[ScriptActor.Command] =
|
||||||
|
// Routers.pool(poolSize = poolSize)(
|
||||||
|
// // make sure the workers are restarted if they fail
|
||||||
|
// Behaviors
|
||||||
|
// .supervise(ScriptActor(parent = parent))
|
||||||
|
// .onFailure[Exception](SupervisorStrategy.restart)
|
||||||
|
// )
|
||||||
|
}
|
38
src/main/scala/wow/doge/mygame/state/EntityDataState.java
Normal file
38
src/main/scala/wow/doge/mygame/state/EntityDataState.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package wow.doge.mygame.state;
|
||||||
|
|
||||||
|
import com.jme3.app.state.AbstractAppState;
|
||||||
|
import com.simsilica.es.EntityData;
|
||||||
|
import com.simsilica.es.base.DefaultEntityData;
|
||||||
|
import com.jme3.app.state.BaseAppState;
|
||||||
|
import com.jme3.app.Application;
|
||||||
|
|
||||||
|
public class EntityDataState extends BaseAppState {
|
||||||
|
private EntityData entityData;
|
||||||
|
|
||||||
|
public EntityDataState() {
|
||||||
|
this(new DefaultEntityData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityDataState(EntityData ed) {
|
||||||
|
this.entityData = ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityData getEntityData() {
|
||||||
|
return entityData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onEnable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDisable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
public void cleanup(Application application) {
|
||||||
|
entityData.close();
|
||||||
|
entityData = null; // cannot be reused
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize(Application application) {
|
||||||
|
}
|
||||||
|
}
|
86
src/main/scala/wow/doge/mygame/state/MovementActor.scala
Normal file
86
src/main/scala/wow/doge/mygame/state/MovementActor.scala
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package wow.doge.mygame.state
|
||||||
|
|
||||||
|
import akka.actor.typed.scaladsl.ActorContext
|
||||||
|
import akka.actor.typed.Behavior
|
||||||
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
import com.softwaremill.quicklens._
|
||||||
|
import wow.doge.mygame.implicits._
|
||||||
|
import com.jme3.renderer.Camera
|
||||||
|
import wow.doge.mygame.math.ImVector3f
|
||||||
|
|
||||||
|
trait CanMove[T] {
|
||||||
|
def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f
|
||||||
|
def move(inst: T, direction: ImVector3f): Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
object ImMovementActor {
|
||||||
|
sealed trait Command
|
||||||
|
// final case class Tick(tpf: Float) extends Command
|
||||||
|
final case class Tick(tpf: Float) extends Command
|
||||||
|
|
||||||
|
sealed trait Movement extends Command
|
||||||
|
final case class MovedLeft(pressed: Boolean) extends Movement
|
||||||
|
final case class MovedUp(pressed: Boolean) extends Movement
|
||||||
|
final case class MovedRight(pressed: Boolean) extends Movement
|
||||||
|
final case class MovedDown(pressed: Boolean) extends Movement
|
||||||
|
|
||||||
|
final case class Props[T: CanMove](
|
||||||
|
app: com.jme3.app.Application,
|
||||||
|
movable: T
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal state of the actor
|
||||||
|
*
|
||||||
|
* @param cardinalDir Immutable, can be shared as is
|
||||||
|
* @param walkDirection Immutable
|
||||||
|
*/
|
||||||
|
final case class State(
|
||||||
|
cardinalDir: CardinalDirection = CardinalDirection()
|
||||||
|
)
|
||||||
|
|
||||||
|
def apply[T: CanMove](props: Props[T]): Behavior[Command] =
|
||||||
|
Behaviors.setup(ctx => new ImMovementActor(ctx, props).receive(State()))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ImMovementActor[T](
|
||||||
|
ctx: ActorContext[ImMovementActor.Command],
|
||||||
|
props: ImMovementActor.Props[T]
|
||||||
|
) {
|
||||||
|
import ImMovementActor._
|
||||||
|
|
||||||
|
def receive(
|
||||||
|
state: ImMovementActor.State
|
||||||
|
)(implicit cm: CanMove[T]): Behavior[Command] =
|
||||||
|
Behaviors.receiveMessage { msg =>
|
||||||
|
msg match {
|
||||||
|
case m: Movement =>
|
||||||
|
m match {
|
||||||
|
case MovedLeft(pressed) =>
|
||||||
|
receive(state = state.modify(_.cardinalDir.left).setTo(pressed))
|
||||||
|
case MovedUp(pressed) =>
|
||||||
|
receive(state = state.modify(_.cardinalDir.up).setTo(pressed))
|
||||||
|
case MovedRight(pressed) =>
|
||||||
|
receive(state = state.modify(_.cardinalDir.right).setTo(pressed))
|
||||||
|
case MovedDown(pressed) =>
|
||||||
|
receive(state = state.modify(_.cardinalDir.down).setTo(pressed))
|
||||||
|
}
|
||||||
|
|
||||||
|
case Tick(tpf) =>
|
||||||
|
val walkDir =
|
||||||
|
cm.getDirection(props.app.getCamera(), state.cardinalDir)
|
||||||
|
if (walkDir != ImVector3f.ZERO) {
|
||||||
|
val tmp = walkDir * 2f
|
||||||
|
props.app.enqueue(new Runnable {
|
||||||
|
override def run(): Unit = {
|
||||||
|
cm.move(props.movable, tmp)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Behaviors.same
|
||||||
|
// receive(state = state.modify(_.walkDirection).setTo(walkDir))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
src/main/scala/wow/doge/mygame/state/MyBaseState.scala
Normal file
63
src/main/scala/wow/doge/mygame/state/MyBaseState.scala
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package wow.doge.mygame.state
|
||||||
|
|
||||||
|
import com.jme3.app.Application
|
||||||
|
import com.jme3.app.SimpleApplication
|
||||||
|
import com.jme3.app.state.AppState
|
||||||
|
import com.jme3.scene.Node
|
||||||
|
import com.jme3.app.state.BaseAppState
|
||||||
|
import com.simsilica.es.EntityData
|
||||||
|
import com.simsilica.es.base.DefaultEntityData
|
||||||
|
|
||||||
|
trait MyBaseState extends BaseAppState {
|
||||||
|
|
||||||
|
var simpleApp: SimpleApplication = null
|
||||||
|
implicit val entityData: EntityData = new DefaultEntityData()
|
||||||
|
def stateManager = simpleApp.getStateManager
|
||||||
|
def guiNode = simpleApp.getGuiNode
|
||||||
|
def rootNode = simpleApp.getRootNode
|
||||||
|
def assetManager = simpleApp.getAssetManager
|
||||||
|
def inputManager = simpleApp.getInputManager
|
||||||
|
def cam = simpleApp.getCamera
|
||||||
|
|
||||||
|
override protected final def initialize(app: Application): Unit = {
|
||||||
|
simpleApp = app.asInstanceOf[SimpleApplication]
|
||||||
|
init()
|
||||||
|
// stateManager.getState(classOf[FlyCamAppState]).getCamera().setMoveSpeed(100)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected def init(): Unit
|
||||||
|
|
||||||
|
override protected def cleanup(app: Application): Unit = {
|
||||||
|
entityData.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected def getOrCreateNode(parent: Node, id: String) =
|
||||||
|
Option(parent.getChild(id)).fold {
|
||||||
|
val node = new Node(id)
|
||||||
|
parent.attachChild(node)
|
||||||
|
node
|
||||||
|
}(node => node.asInstanceOf[Node])
|
||||||
|
|
||||||
|
protected def enableStates(classes: Class[_ <: AppState]*) =
|
||||||
|
setEnabledToStates(true, classes: _*)
|
||||||
|
protected def disableStates(classes: Class[_ <: AppState]*) =
|
||||||
|
setEnabledToStates(false, classes: _*)
|
||||||
|
|
||||||
|
protected def setEnabledToStates(
|
||||||
|
enabled: Boolean,
|
||||||
|
classes: Class[_ <: AppState]*
|
||||||
|
) = {
|
||||||
|
for (clazz <- classes) {
|
||||||
|
val st = stateManager.getState(clazz)
|
||||||
|
if (st != null) st.setEnabled(enabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected def removeStates(classes: Class[_ <: AppState]*) = {
|
||||||
|
for (clazz <- classes) {
|
||||||
|
val st = stateManager.getState(clazz)
|
||||||
|
if (st != null) stateManager.detach(st)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
286
src/main/scala/wow/doge/mygame/state/PlayerMovementState2.scala
Normal file
286
src/main/scala/wow/doge/mygame/state/PlayerMovementState2.scala
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
package wow.doge.mygame.state
|
||||||
|
|
||||||
|
|
||||||
|
import scala.concurrent.duration.DurationInt
|
||||||
|
|
||||||
|
import com.jme3.input.InputManager
|
||||||
|
import com.jme3.input.KeyInput
|
||||||
|
import com.jme3.input.controls.ActionListener
|
||||||
|
import com.jme3.input.controls.KeyTrigger
|
||||||
|
import com.jme3.math.Vector3f
|
||||||
|
|
||||||
|
import akka.actor.typed.scaladsl.ActorContext
|
||||||
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
import akka.actor.typed.Behavior
|
||||||
|
import akka.actor.typed.ActorRef
|
||||||
|
import com.jme3.scene.Geometry
|
||||||
|
import akka.actor.typed.scaladsl.TimerScheduler
|
||||||
|
|
||||||
|
import wow.doge.mygame.implicits._
|
||||||
|
|
||||||
|
class PlayerMovementState2(
|
||||||
|
movementActor: ActorRef[MovementActor.Command],
|
||||||
|
movementActorTimer: ActorRef[MovementActorTimer.Command],
|
||||||
|
imMovementActor: ActorRef[ImMovementActor.Command],
|
||||||
|
geom: Geometry
|
||||||
|
) extends MyBaseState
|
||||||
|
with ActionListener {
|
||||||
|
|
||||||
|
protected lazy val mat = MyMaterial(
|
||||||
|
assetManager = assetManager,
|
||||||
|
path = "Common/MatDefs/Misc/Unshaded.j3md"
|
||||||
|
)
|
||||||
|
|
||||||
|
override protected[state] def onEnable(): Unit = {}
|
||||||
|
|
||||||
|
override protected[state] def onDisable(): Unit = {}
|
||||||
|
|
||||||
|
override protected def init(): Unit = {
|
||||||
|
|
||||||
|
setupKeys(inputManager)
|
||||||
|
geom.setMaterial(mat)
|
||||||
|
rootNode.attachChild(geom)
|
||||||
|
// movementActorTimer ! MovementActorTimer.Start(geom, cam)
|
||||||
|
// movementActorTimer ! MovementActorTimer.Start
|
||||||
|
}
|
||||||
|
|
||||||
|
// def system =
|
||||||
|
// simpleApp.getStateManager.getState(classOf[ActorSystemState]).system
|
||||||
|
// def player = system.actorSelection("/user/player") //.resolveOne(1.second)
|
||||||
|
|
||||||
|
var lastDir: Vector3f = Vector3f.UNIT_X
|
||||||
|
|
||||||
|
override def update(tpf: Float) = {
|
||||||
|
// val direction = new Vector3f()
|
||||||
|
// direction.multLocal(10 * tpf)
|
||||||
|
// if (direction.length() > 0f) {
|
||||||
|
// // player ! PlayerMove(direction)
|
||||||
|
// lastDir = direction.normalize
|
||||||
|
// }
|
||||||
|
// if (shoot) {
|
||||||
|
// shoot = false
|
||||||
|
// // player ! Shoot(lastDir)
|
||||||
|
// }
|
||||||
|
// movementActor ! MovementActor.Tick(tpf, geom, cam)
|
||||||
|
imMovementActor ! ImMovementActor.Tick(tpf)
|
||||||
|
// movementActorTimer ! MovementActorTimer.Update(tpf)
|
||||||
|
}
|
||||||
|
|
||||||
|
def setupKeys(inputManager: InputManager) = {
|
||||||
|
|
||||||
|
inputManager
|
||||||
|
.withMapping(
|
||||||
|
"Left",
|
||||||
|
// new KeyTrigger(KeyInput.KEY_A),
|
||||||
|
new KeyTrigger(KeyInput.KEY_LEFT)
|
||||||
|
)
|
||||||
|
.withMapping(
|
||||||
|
"Right",
|
||||||
|
// new KeyTrigger(KeyInput.KEY_D),
|
||||||
|
new KeyTrigger(KeyInput.KEY_RIGHT)
|
||||||
|
)
|
||||||
|
inputManager.addMapping(
|
||||||
|
"Up",
|
||||||
|
// new KeyTrigger(KeyInput.KEY_W),
|
||||||
|
new KeyTrigger(KeyInput.KEY_UP)
|
||||||
|
)
|
||||||
|
inputManager.addMapping(
|
||||||
|
"Down",
|
||||||
|
// new KeyTrigger(KeyInput.KEY_S),
|
||||||
|
new KeyTrigger(KeyInput.KEY_DOWN)
|
||||||
|
)
|
||||||
|
inputManager.addMapping(
|
||||||
|
"Space",
|
||||||
|
new KeyTrigger(KeyInput.KEY_SPACE),
|
||||||
|
new KeyTrigger(KeyInput.KEY_H)
|
||||||
|
)
|
||||||
|
inputManager.addMapping(
|
||||||
|
"Reset",
|
||||||
|
new KeyTrigger(KeyInput.KEY_R),
|
||||||
|
new KeyTrigger(KeyInput.KEY_RETURN)
|
||||||
|
)
|
||||||
|
inputManager
|
||||||
|
.withListener(this, "Left")
|
||||||
|
.withListener(this, "Right")
|
||||||
|
inputManager.addListener(this, "Up")
|
||||||
|
inputManager.addListener(this, "Down")
|
||||||
|
inputManager.addListener(this, "Space")
|
||||||
|
inputManager.addListener(this, "Reset")
|
||||||
|
}
|
||||||
|
|
||||||
|
def onAction(binding: String, value: Boolean, tpf: Float) =
|
||||||
|
binding match {
|
||||||
|
case "Left" => imMovementActor ! ImMovementActor.MovedLeft(value)
|
||||||
|
case "Right" => imMovementActor ! ImMovementActor.MovedRight(value)
|
||||||
|
case "Up" => imMovementActor ! ImMovementActor.MovedUp(value)
|
||||||
|
case "Down" => imMovementActor ! ImMovementActor.MovedDown(value)
|
||||||
|
case "Space" =>
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
final case class CardinalDirection(
|
||||||
|
left: Boolean = false,
|
||||||
|
right: Boolean = false,
|
||||||
|
up: Boolean = false,
|
||||||
|
down: Boolean = false
|
||||||
|
)
|
||||||
|
|
||||||
|
object MovementActor {
|
||||||
|
sealed trait Command
|
||||||
|
// final case class Tick(tpf: Float, geom: Geometry, cam: Camera) extends Command
|
||||||
|
// final case class Tick(tpf: Float) extends Command
|
||||||
|
final case object Tick extends Command
|
||||||
|
|
||||||
|
sealed trait Movement extends Command
|
||||||
|
final case class MovedLeft(pressed: Boolean) extends Movement
|
||||||
|
final case class MovedUp(pressed: Boolean) extends Movement
|
||||||
|
final case class MovedRight(pressed: Boolean) extends Movement
|
||||||
|
final case class MovedDown(pressed: Boolean) extends Movement
|
||||||
|
|
||||||
|
final case class Props(app: com.jme3.app.Application, geom: Geometry)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal state of the actor
|
||||||
|
*
|
||||||
|
* @param cardinalDir Immutable, can be shared as is
|
||||||
|
* @param walkDirection scratch space to avoid allocations on every tick. Do not share outside the actor
|
||||||
|
*/
|
||||||
|
final case class State(
|
||||||
|
cardinalDir: CardinalDirection = CardinalDirection(),
|
||||||
|
walkDirection: Vector3f = Vector3f.UNIT_X
|
||||||
|
)
|
||||||
|
|
||||||
|
def apply(props: Props): Behavior[Command] =
|
||||||
|
Behaviors.setup(ctx => new MovementActor(ctx, props).receive(State()))
|
||||||
|
|
||||||
|
}
|
||||||
|
class MovementActor(
|
||||||
|
ctx: ActorContext[MovementActor.Command],
|
||||||
|
props: MovementActor.Props
|
||||||
|
) {
|
||||||
|
import MovementActor._
|
||||||
|
import com.softwaremill.quicklens._
|
||||||
|
def receive(state: MovementActor.State): Behavior[Command] =
|
||||||
|
Behaviors.receiveMessage { msg =>
|
||||||
|
msg match {
|
||||||
|
case m: Movement =>
|
||||||
|
m match {
|
||||||
|
case MovedLeft(pressed) =>
|
||||||
|
receive(state = state.modify(_.cardinalDir.left).setTo(pressed))
|
||||||
|
case MovedUp(pressed) =>
|
||||||
|
receive(state = state.modify(_.cardinalDir.up).setTo(pressed))
|
||||||
|
case MovedRight(pressed) =>
|
||||||
|
receive(state = state.modify(_.cardinalDir.right).setTo(pressed))
|
||||||
|
case MovedDown(pressed) =>
|
||||||
|
receive(state = state.modify(_.cardinalDir.down).setTo(pressed))
|
||||||
|
}
|
||||||
|
|
||||||
|
case Tick =>
|
||||||
|
val camDir =
|
||||||
|
props.app.getCamera.getDirection().clone().multLocal(0.6f)
|
||||||
|
val camLeft = props.app.getCamera.getLeft().clone().multLocal(0.4f)
|
||||||
|
val walkDir = state.walkDirection.set(0, 0, 0)
|
||||||
|
// val walkDir = new Vector3f
|
||||||
|
val dir = state.cardinalDir
|
||||||
|
if (dir.up) {
|
||||||
|
ctx.log.debug("up")
|
||||||
|
// ctx.log.debug(Thread.currentThread().getName())
|
||||||
|
// walkDir.addLocal(0, 0, -1)
|
||||||
|
walkDir += camDir
|
||||||
|
}
|
||||||
|
if (dir.left) {
|
||||||
|
ctx.log.debug("left")
|
||||||
|
// walkDir.addLocal(-1, 0, 0)
|
||||||
|
walkDir.addLocal(camLeft)
|
||||||
|
}
|
||||||
|
if (dir.right) {
|
||||||
|
ctx.log.debug("right")
|
||||||
|
// walkDir.addLocal(1, 0, 0)
|
||||||
|
walkDir.addLocal(camLeft.negateLocal())
|
||||||
|
}
|
||||||
|
if (dir.down) {
|
||||||
|
ctx.log.debug("down")
|
||||||
|
walkDir.addLocal(camDir.negateLocal())
|
||||||
|
// walkDir.addLocal(0, 0, 1)
|
||||||
|
}
|
||||||
|
// (dir.up, dir.down, dir.left, dir.right) match {
|
||||||
|
// case (true, false, true, false) =>
|
||||||
|
// case _ =>
|
||||||
|
// }
|
||||||
|
|
||||||
|
walkDir.multLocal(2f)
|
||||||
|
|
||||||
|
// walkDir.multLocal(100f)
|
||||||
|
// .multLocal(tpf)
|
||||||
|
|
||||||
|
// val v = props.geom.getLocalTranslation()
|
||||||
|
// props.geom.setLocalTranslation(
|
||||||
|
// (v += walkDir)
|
||||||
|
// )
|
||||||
|
props.app.enqueue(new Runnable {
|
||||||
|
override def run(): Unit = {
|
||||||
|
// geom.setLocalTranslation(walkDir)
|
||||||
|
|
||||||
|
val v = props.geom.getLocalTranslation()
|
||||||
|
props.geom.setLocalTranslation(
|
||||||
|
(v += walkDir)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Behaviors.same
|
||||||
|
// receive(state = state.modify(_.walkDirection).setTo(walkDir))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object MovementActorTimer {
|
||||||
|
sealed trait Command
|
||||||
|
final case object Start extends Command
|
||||||
|
final case object Update extends Command
|
||||||
|
private case object Send extends Command
|
||||||
|
case object TimerKey
|
||||||
|
|
||||||
|
final case class Props(
|
||||||
|
timers: TimerScheduler[MovementActorTimer.Command],
|
||||||
|
target: ActorRef[MovementActor.Command]
|
||||||
|
)
|
||||||
|
final case class State()
|
||||||
|
def apply(target: ActorRef[MovementActor.Command]) =
|
||||||
|
Behaviors.withTimers[Command] { timers =>
|
||||||
|
new MovementActorTimer(Props(timers, target)).idle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class MovementActorTimer(
|
||||||
|
props: MovementActorTimer.Props
|
||||||
|
) {
|
||||||
|
import MovementActorTimer._
|
||||||
|
// import com.softwaremill.quicklens._
|
||||||
|
|
||||||
|
def idle(): Behavior[Command] =
|
||||||
|
Behaviors.receiveMessage { msg =>
|
||||||
|
msg match {
|
||||||
|
case Start =>
|
||||||
|
props.timers.startTimerWithFixedDelay(
|
||||||
|
Send,
|
||||||
|
10.millis
|
||||||
|
)
|
||||||
|
active()
|
||||||
|
case _ => Behaviors.unhandled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def active(): Behavior[Command] =
|
||||||
|
Behaviors.receiveMessage { msg =>
|
||||||
|
msg match {
|
||||||
|
case Update => active()
|
||||||
|
case Send =>
|
||||||
|
props.target ! MovementActor.Tick
|
||||||
|
Behaviors.same
|
||||||
|
case _ => Behaviors.unhandled
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
206
src/main/scala/wow/doge/mygame/state/ScriptingEngineState.scala
Normal file
206
src/main/scala/wow/doge/mygame/state/ScriptingEngineState.scala
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
package wow.doge.mygame.state
|
||||||
|
|
||||||
|
import ammonite.runtime.Storage.Folder
|
||||||
|
import ammonite.main.Defaults
|
||||||
|
import ammonite.Main
|
||||||
|
import javax.script.ScriptEngine
|
||||||
|
import com.jme3.app.Application
|
||||||
|
import com.jme3.app.state.AppState
|
||||||
|
import akka.actor.typed.scaladsl.AbstractBehavior
|
||||||
|
import akka.actor.typed.scaladsl.ActorContext
|
||||||
|
import akka.actor.typed.Behavior
|
||||||
|
import akka.actor.typed.ActorRef
|
||||||
|
import ammonite.util.Res.Success
|
||||||
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
import akka.actor.typed.SpawnProtocol
|
||||||
|
|
||||||
|
class ScriptingEngineState(
|
||||||
|
sse: ScalaScriptingEngine,
|
||||||
|
kse: KotlinScriptingEngine
|
||||||
|
) extends MyBaseState {
|
||||||
|
|
||||||
|
// implicit val actorSystem =
|
||||||
|
// ActorSystem.create(MyActorSystem(), "rootActor")
|
||||||
|
// implicit val timeout: Timeout = Timeout(3.seconds)
|
||||||
|
// val scalaScriptActor: Future[ActorRef[ScalaScriptBehavior.Command]] =
|
||||||
|
// actorSystem.ask(
|
||||||
|
// SpawnProtocol.Spawn(
|
||||||
|
// ScalaScriptBehavior(sse.runner),
|
||||||
|
// name = "ScalaScriptCompilerActor",
|
||||||
|
// Props.empty,
|
||||||
|
// _
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
|
||||||
|
override protected def cleanup(app: Application): Unit = {
|
||||||
|
// actorSystem.terminate()
|
||||||
|
}
|
||||||
|
|
||||||
|
// override protected def initialize(app: Application): Unit = {
|
||||||
|
// super.initialize(app)
|
||||||
|
|
||||||
|
// }
|
||||||
|
override def init() = {
|
||||||
|
// Future {
|
||||||
|
// while (true) {
|
||||||
|
// // super.update(tpf)
|
||||||
|
// val (res, k) = sse.runner.runScript(
|
||||||
|
// // os.Path(getClass().getResource("/hello.sc").getPath),
|
||||||
|
// os.pwd / "src" / "main" / "resources" / "hello.sc",
|
||||||
|
// Seq.empty
|
||||||
|
// // Seq(("start", None))
|
||||||
|
// // Scripts.groupArgs(List(""))
|
||||||
|
// )
|
||||||
|
// val ms = res.map(_.asInstanceOf[GameScript])
|
||||||
|
// ms.map(_.start())
|
||||||
|
|
||||||
|
// val res2 = kse.engine.eval(
|
||||||
|
// os.read(os.pwd / "src" / "main" / "resources" / "hello.main.kts")
|
||||||
|
// )
|
||||||
|
// // val res2 = engine.eval(getClass().getResource("/hello.main.kts").getPath)
|
||||||
|
// // val invoker = engine.asInstanceOf[Invocable]
|
||||||
|
// // val scr = invoker.getInterface(res2, classOf[GameScript])
|
||||||
|
// val scr = res2.asInstanceOf[GameScript]
|
||||||
|
// scr.start()
|
||||||
|
// Thread.sleep(2000)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Future {
|
||||||
|
// sse.runner
|
||||||
|
// .runScript(
|
||||||
|
// os.pwd / "src" / "main" / "resources" / "hello2.sc",
|
||||||
|
// Seq.empty
|
||||||
|
// )
|
||||||
|
// ._1
|
||||||
|
// .map(_.asInstanceOf[MyBaseState])
|
||||||
|
// .map(s => stateManager.attach(s))
|
||||||
|
|
||||||
|
// ()
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// val res = scalaScriptActor
|
||||||
|
// .map(
|
||||||
|
// _.ask(ref =>
|
||||||
|
// ScalaScriptBehavior.Compile(
|
||||||
|
// ref,
|
||||||
|
// os.pwd / "src" / "main" / "resources" / "hello2.sc"
|
||||||
|
// // os.Path(getClass().getResource("/hello2.sc").getPath)
|
||||||
|
// )
|
||||||
|
// )(Timeout(10.seconds), actorSystem.scheduler)
|
||||||
|
// )
|
||||||
|
// .flatten
|
||||||
|
|
||||||
|
// res.foreach(_ match {
|
||||||
|
// case AppStateResult(state) => {
|
||||||
|
// stateManager.attach(state)
|
||||||
|
// }
|
||||||
|
// case wow.doge.mygame.state.ScalaScriptBehavior.Error(reason) =>
|
||||||
|
// println("error")
|
||||||
|
// })
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override def update(tpf: Float): Unit = {}
|
||||||
|
|
||||||
|
override protected def onEnable(): Unit = {}
|
||||||
|
|
||||||
|
override protected def onDisable(): Unit = {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object MyActorSystem {
|
||||||
|
def apply(): Behavior[SpawnProtocol.Command] =
|
||||||
|
Behaviors.setup { context =>
|
||||||
|
// Start initial tasks
|
||||||
|
// context.spawn(...)
|
||||||
|
|
||||||
|
SpawnProtocol()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class ScalaScriptingEngine(
|
||||||
|
val runner: Main = ammonite
|
||||||
|
.Main(
|
||||||
|
// predefCode = """
|
||||||
|
// import coursierapi.MavenRepository
|
||||||
|
|
||||||
|
// interp.repositories.update(
|
||||||
|
// interp.repositories() ::: List(
|
||||||
|
// MavenRepository.of("file://home/rohan/.m2/repository")
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
|
||||||
|
// @
|
||||||
|
|
||||||
|
// """,
|
||||||
|
defaultPredef = false,
|
||||||
|
storageBackend = new Folder(Defaults.ammoniteHome, isRepl = false)
|
||||||
|
)
|
||||||
|
) {}
|
||||||
|
|
||||||
|
class KotlinScriptingEngine(val engine: ScriptEngine) {
|
||||||
|
// val manager = new ScriptEngineManager()
|
||||||
|
// val engine = manager.getEngineByExtension("main.kts")
|
||||||
|
}
|
||||||
|
|
||||||
|
object ScalaScriptBehavior {
|
||||||
|
sealed trait Result
|
||||||
|
final case class AppStateResult(state: AppState) extends Result
|
||||||
|
final case class Error(reason: String) extends Result
|
||||||
|
|
||||||
|
sealed trait Command
|
||||||
|
final case class Compile(sender: ActorRef[Result], path: os.Path)
|
||||||
|
extends Command
|
||||||
|
// final case class CompileScripts(sender: ActorRef[Result], paths: os.Path*)
|
||||||
|
// extends Command
|
||||||
|
def apply(
|
||||||
|
runner: Main = ammonite
|
||||||
|
.Main(
|
||||||
|
storageBackend = new Folder(
|
||||||
|
// os.pwd / "target"
|
||||||
|
Defaults.ammoniteHome,
|
||||||
|
isRepl = false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) =
|
||||||
|
Behaviors.setup(ctx => new ScalaScriptActor(runner, ctx))
|
||||||
|
private class ScalaScriptActor(
|
||||||
|
val runner: Main,
|
||||||
|
context: ActorContext[Command]
|
||||||
|
) extends AbstractBehavior[Command](context) {
|
||||||
|
|
||||||
|
override def onMessage(msg: Command): Behavior[Command] = {
|
||||||
|
msg match {
|
||||||
|
case Compile(sender, path) =>
|
||||||
|
context.log.debug(s"Received $path")
|
||||||
|
val res = getScript(path)
|
||||||
|
println(res)
|
||||||
|
sender ! res
|
||||||
|
Behaviors.same
|
||||||
|
// case CompileScripts(sender, paths) =>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def getScript(path: os.Path): Result = {
|
||||||
|
runner
|
||||||
|
.runScript(
|
||||||
|
path,
|
||||||
|
Seq.empty
|
||||||
|
)
|
||||||
|
._1 match {
|
||||||
|
case ammonite.util.Res.Exception(t, msg) => Error(msg)
|
||||||
|
|
||||||
|
case Success(obj) =>
|
||||||
|
obj match {
|
||||||
|
case s: MyBaseState => AppStateResult(s)
|
||||||
|
case _ => Error("Unknown script type")
|
||||||
|
// AppStateResult(s.asInstanceOf[AppState])
|
||||||
|
}
|
||||||
|
|
||||||
|
case _ => Error("Failed to run script")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
71
src/main/scala/wow/doge/mygame/state/TestAppState.scala
Normal file
71
src/main/scala/wow/doge/mygame/state/TestAppState.scala
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package wow.doge.mygame.state
|
||||||
|
|
||||||
|
import com.jme3.app.Application
|
||||||
|
import wow.doge.mygame.implicits._
|
||||||
|
import wow.doge.mygame.components.TestComponent
|
||||||
|
import com.jme3.scene.shape.Box
|
||||||
|
import com.jme3.scene.Geometry
|
||||||
|
import com.jme3.material.Material
|
||||||
|
import com.jme3.math.ColorRGBA
|
||||||
|
import com.jme3.asset.AssetManager
|
||||||
|
import com.jme3.math.Vector3f
|
||||||
|
class TestAppState(
|
||||||
|
// private var _entity: Option[EntityData] = Some(new DefaultEntityData())
|
||||||
|
) extends MyBaseState {
|
||||||
|
var geom: Option[Geometry] = None
|
||||||
|
|
||||||
|
// def entity = _entity
|
||||||
|
// override def initialize(app: Application): Unit = {
|
||||||
|
// super.initialize(app)
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
override def init() = {
|
||||||
|
entityData
|
||||||
|
.createEntity()
|
||||||
|
.withComponents(TestComponent())
|
||||||
|
// entityData.setComponents(x, TestComponent())
|
||||||
|
val es = entityData.getEntities(classOf[TestComponent])
|
||||||
|
println(es)
|
||||||
|
val b = new Box(1, 1, 1)
|
||||||
|
geom = Some(new Geometry("Box", b))
|
||||||
|
|
||||||
|
val mat = MyMaterial(
|
||||||
|
assetManager = assetManager,
|
||||||
|
path = "Common/MatDefs/Misc/Unshaded.j3md"
|
||||||
|
)
|
||||||
|
geom.foreach(e => {
|
||||||
|
e.setMaterial(mat)
|
||||||
|
rootNode.attachChild(e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override def update(tpf: Float) = {
|
||||||
|
geom.foreach(_.rotate(0, 0.5f * tpf, 0))
|
||||||
|
geom.foreach(_.move(new Vector3f(0, 1 * tpf, 0)))
|
||||||
|
}
|
||||||
|
|
||||||
|
override def cleanup(app: Application): Unit = {
|
||||||
|
// _entity.map(_.close())
|
||||||
|
// _entity = None
|
||||||
|
}
|
||||||
|
|
||||||
|
override def onEnable(): Unit = {}
|
||||||
|
|
||||||
|
override def onDisable(): Unit = {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object MyMaterial {
|
||||||
|
def apply(
|
||||||
|
color: String = "Color",
|
||||||
|
colorType: com.jme3.math.ColorRGBA = ColorRGBA.Blue,
|
||||||
|
assetManager: AssetManager,
|
||||||
|
path: String
|
||||||
|
): Material = {
|
||||||
|
val mat =
|
||||||
|
new Material(assetManager, path)
|
||||||
|
mat.setColor(color, colorType)
|
||||||
|
mat
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user