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)
|
||||
|
||||
}
|