forked from nova/jmonkey-test
Rohan Sircar
3 years ago
commit
1f55e08fa5
53 changed files with 2862 additions and 0 deletions
-
39.ammonite/scala-2.12.12/amm-2.2.0-4-4bd225e/src/main/resources/dep/src/ammonite/$file/src/main/resources/dep.scala
-
45.ammonite/scala-2.12.12/amm-2.2.0-4-4bd225e/src/main/resources/hello/src/ammonite/$file/src/main/resources/hello.scala
-
134.ammonite/scala-2.12.12/amm-2.2.0-4-4bd225e/src/main/resources/hello2/src/ammonite/$file/src/main/resources/hello2.scala
-
25.gitignore
-
1.scalafmt.conf
-
3assets.jmp
-
192build.sbt
-
BINlibbulletjme.so
-
1project/build.properties
-
2project/plugins.sbt
-
1src/main/resources/META-INF/services/javax.script.ScriptEngineFactory
-
7src/main/resources/application.conf
-
2src/main/resources/dep.sc
-
36src/main/resources/hello.main.kts
-
35src/main/resources/hello.sc
-
5src/main/resources/hello2.main.kts
-
107src/main/resources/hello2.sc
-
19src/main/resources/weapon.json
-
62src/main/scala/com/jme3/animation/package.scala
-
16src/main/scala/com/jme3/app/package.scala
-
6src/main/scala/com/jme3/input/Action.scala
-
37src/main/scala/com/jme3/input/controls/package.scala
-
18src/main/scala/com/jme3/input/package.scala
-
11src/main/scala/com/jme3/material/package.scala
-
19src/main/scala/com/jme3/scene/debug/package.scala
-
56src/main/scala/com/jme3/scene/package.scala
-
20src/main/scala/com/jme3/scene/shape/package.scala
-
14src/main/scala/com/jme3/syntax/package.scala
-
5src/main/scala/message.txt
-
127src/main/scala/wow/doge/mygame/Main.scala
-
6src/main/scala/wow/doge/mygame/components/Position.scala
-
28src/main/scala/wow/doge/mygame/components/Tag.scala
-
11src/main/scala/wow/doge/mygame/components/Test.java
-
5src/main/scala/wow/doge/mygame/components/TestComponent.scala
-
139src/main/scala/wow/doge/mygame/events/EventBus.scala
-
17src/main/scala/wow/doge/mygame/events/Events.scala
-
3src/main/scala/wow/doge/mygame/events/EventsModule.scala
-
5src/main/scala/wow/doge/mygame/executors/ExecutorsModule.scala
-
103src/main/scala/wow/doge/mygame/executors/GUIExecutor.scala
-
10src/main/scala/wow/doge/mygame/executors/Schedulers.scala
-
109src/main/scala/wow/doge/mygame/game/GameApp.scala
-
67src/main/scala/wow/doge/mygame/game/GameAppActor.scala
-
55src/main/scala/wow/doge/mygame/implicits/EntityQuery.scala
-
175src/main/scala/wow/doge/mygame/implicits/package.scala
-
11src/main/scala/wow/doge/mygame/math/ImVector3f.scala
-
157src/main/scala/wow/doge/mygame/scriptsystem/ScriptActor.scala
-
166src/main/scala/wow/doge/mygame/scriptsystem/ScriptCachingActor.scala
-
38src/main/scala/wow/doge/mygame/state/EntityDataState.java
-
86src/main/scala/wow/doge/mygame/state/MovementActor.scala
-
63src/main/scala/wow/doge/mygame/state/MyBaseState.scala
-
286src/main/scala/wow/doge/mygame/state/PlayerMovementState2.scala
-
206src/main/scala/wow/doge/mygame/state/ScriptingEngineState.scala
-
71src/main/scala/wow/doge/mygame/state/TestAppState.scala
@ -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>*/ |
|||
} |
@ -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 |
@ -0,0 +1 @@ |
|||
version = "2.6.4" |
@ -0,0 +1,3 @@ |
|||
#assets properties |
|||
#Fri Oct 23 22:34:43 IST 2020 |
|||
assets.folder.name=src/main/resources/assets |
@ -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 |
@ -0,0 +1 @@ |
|||
sbt.version=1.3.13 |
@ -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 |
@ -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 |
@ -0,0 +1,2 @@ |
|||
// println("hello from dep") |
|||
class Test(x: Int) |
@ -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() |
@ -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) |
@ -0,0 +1,5 @@ |
|||
println("hello from dep") |
|||
|
|||
class Test(val x: Int) |
|||
|
|||
var x = 2 |
@ -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() |
@ -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) |
|||
) |
@ -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) |
|||
} |
|||
|
|||
|
|||
} |
@ -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 |
|||
|
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,6 @@ |
|||
package com.jme3.input |
|||
|
|||
/** |
|||
* Created by Brandon Barker on 6/19/17. |
|||
*/ |
|||
final case class Action(name: String) extends AnyVal |
@ -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) |
|||
} |
|||
|
|||
} |
@ -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): _*) |
|||
|
|||
} |
|||
|
|||
} |
@ -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) |
|||
} |
|||
} |
@ -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) |
|||
} |
|||
} |
@ -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") |
|||
) |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
@ -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) |
|||
} |
|||
} |
@ -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 |
|||
} |
|||
|
|||
} |
@ -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? |
@ -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 |
|||
} |
|||
} |
|||
} |
@ -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 |
@ -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 + "]"; |
|||
// } |
|||
// } |
@ -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 |
@ -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 |
|||
} |
|||
} |
@ -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 |
|||
} |
@ -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() |
|||
} |
@ -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) |
|||
|
|||
} |
@ -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 |
|||
) |
@ -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 |
|||
} |
@ -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 |
|||
} |
|||
} |
@ -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: _*) |
|||
} |
|||
} |
@ -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) |
|||
} |
|||
} |
|||
} |
@ -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) |
|||
|
|||
} |
@ -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) |
|||
// ) |
|||
} |
@ -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) { |
|||
} |
|||
} |
@ -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)) |
|||
|
|||
} |
|||
} |
|||
} |
@ -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) |
|||
} |
|||
} |
|||
|
|||
} |
@ -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 |
|||
|
|||
} |
|||
} |
|||
} |
@ -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") |
|||
} |
|||
|
|||
} |
|||
|
|||
} |
|||
} |
@ -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 |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue