first commit

This commit is contained in:
Rohan Sircar 2020-11-07 20:59:57 +05:30
commit 1f55e08fa5
53 changed files with 2862 additions and 0 deletions

View File

@ -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>*/
}

View File

@ -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>*/
}

View File

@ -0,0 +1,134 @@
package ammonite
package $file.src.main.resources
import _root_.ammonite.interp.api.InterpBridge.{
value => interp
}
import _root_.ammonite.interp.api.InterpBridge.value.{
exit
}
import _root_.ammonite.interp.api.IvyConstructor.{
ArtifactIdExt,
GroupIdExt
}
import _root_.ammonite.runtime.tools.{
browse,
grep,
time,
tail
}
import _root_.ammonite.repl.tools.{
desugar,
source
}
import _root_.ammonite.main.Router.{
doc,
main
}
import _root_.ammonite.repl.tools.Util.{
pathScoptRead
}
object hello2{
/*<script>*/import $repo.$
// import $repo.`https://bintray.com/jmonkeyengine/com.jme3`
// import $file.dep
import $ivy.$
// import $ivy.`wow.doge:game:1.0-SNAPSHOT`
import $ivy.$
// import wow.doge.game.types.GameScript
import com.jme3.scene.control.Control
// println("hello from script")
// class Scr extends GameScript {
// def start(): Unit = println("hello from start")
// def stop(): Unit = println("hello from stop")
// }
// // class SomeClass extends Control {}
// @main
// def main(): GameScript = new Scr()
import com.simsilica.es.base.DefaultEntityData
import com.simsilica.es.EntityData
import com.jme3.app.Application
import wow.doge.mygame.game.Implicits._
import wow.doge.mygame.components.TestComponent
import com.jme3.scene.shape.Box
import com.jme3.scene.Geometry
import com.jme3.material.Material
import com.jme3.math.ColorRGBA
import com.jme3.asset.AssetManager
import com.jme3.math.Vector3f
import wow.doge.mygame.state._
class TestAppState(
// private var _entity: Option[EntityData] = Some(new DefaultEntityData())
) extends MyBaseState {
protected lazy val b = new Box(1, 1, 1)
protected lazy val geom = new Geometry("Box", b)
protected lazy val mat = Material(
assetManager = assetManager,
path = "Common/MatDefs/Misc/Unshaded.j3md"
)
// def entity = _entity
// override def initialize(app: Application): Unit = {
// super.initialize(app)
// }
override def init() = {
entityData
.createEntity()
.withComponents(TestComponent())
// entityData.setComponents(x, TestComponent())
val es = entityData.getEntities(classOf[TestComponent])
println(es)
geom.setMaterial(mat)
rootNode.attachChild(geom)
// geom.foreach(e => {
// })
}
override def update(tpf: Float) = {
geom.rotate(0, 0.5f * tpf, 0)
geom.move(new Vector3f(0, 1 * tpf, 0))
}
override def cleanup(app: Application): Unit = {
// _entity.map(_.close())
// _entity = None
}
override def onEnable(): Unit = {}
override def onDisable(): Unit = {}
}
object Material {
def apply(
color: String = "Color",
colorType: com.jme3.math.ColorRGBA = ColorRGBA.Blue,
assetManager: AssetManager,
path: String
): Material = {
val mat =
new Material(assetManager, path)
mat.setColor(color, colorType)
mat
}
}
@main
def main(): MyBaseState = new TestAppState()
/*</script>*/ /*<generated>*/
def $main() = { scala.Iterator[String]() }
override def toString = "hello2"
/*</generated>*/
}

25
.gitignore vendored Normal file
View File

@ -0,0 +1,25 @@
*.class
*.log
# sbt specific
.cache/
.history/
.lib/
dist/*
target/
lib_managed/
src_managed/
project/boot/
project/plugins/project/
metals.sbt
.metals
.bloop
# Scala-IDE specific
.scala_dependencies
.worksheet
.idea/
.vscode
assets/
*.j3o

1
.scalafmt.conf Normal file
View File

@ -0,0 +1 @@
version = "2.6.4"

3
assets.jmp Normal file
View File

@ -0,0 +1,3 @@
#assets properties
#Fri Oct 23 22:34:43 IST 2020
assets.folder.name=src/main/resources/assets

192
build.sbt Normal file
View File

@ -0,0 +1,192 @@
// The simplest possible sbt build file is just one line:
scalaVersion := "2.13.3"
// That is, to create a valid sbt build, all you've got to do is define the
// version of Scala you'd like your project to use.
// ============================================================================
// Lines like the above defining `scalaVersion` are called "settings". Settings
// are key/value pairs. In the case of `scalaVersion`, the key is "scalaVersion"
// and the value is "2.13.1"
// It's possible to define many kinds of settings, such as:
// Note, it's not required for you to define these three settings. These are
// mostly only necessary if you intend to publish your library's binaries on a
// place like Sonatype or Bintray.
// Want to use a published library in your project?
// You can define other libraries as dependencies in your build like this:
resolvers += "Jcenter" at "https://jcenter.bintray.com/"
resolvers += "JME Bintray" at "https://bintray.com/jmonkeyengine/com.jme3"
resolvers += Resolver.mavenLocal
resolvers += Resolver.sonatypeRepo("snapshots")
lazy val jmeVersion = "3.3.2-stable"
lazy val osName = System.getProperty("os.name") match {
case n if n.startsWith("Linux") => "linux"
case n if n.startsWith("Mac") => "mac"
case n if n.startsWith("Windows") => "win"
case _ => throw new Exception("Unknown platform!")
}
lazy val javaFXModules =
Seq("base", "controls", "fxml", "graphics", "media", "swing", "web")
lazy val root = (project in file(".")).settings(
inThisBuild(
List(
scalaVersion := scalaVersion.value, // 2.11.12, or 2.13.3
semanticdbEnabled := true, // enable SemanticDB
semanticdbVersion := "4.3.24" // use Scalafix compatible version
)
),
name := "mygame",
organization := "wow.doge",
version := "1.0-SNAPSHOT",
libraryDependencies ++= Seq(
"org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2",
// https://mvnrepository.com/artifact/org.jmonkeyengine/jme3-core
"org.jmonkeyengine" % "jme3-core" % jmeVersion,
// https://mvnrepository.com/artifact/org.jmonkeyengine/jme3-desktop
"org.jmonkeyengine" % "jme3-desktop" % jmeVersion,
// https://mvnrepository.com/artifact/org.jmonkeyengine/jme3-lwjgl3
"org.jmonkeyengine" % "jme3-lwjgl3" % jmeVersion,
"org.jmonkeyengine" % "jme3-effects" % jmeVersion,
"org.jmonkeyengine" % "jme3-plugins" % jmeVersion,
"org.jmonkeyengine" % "jme3-blender" % jmeVersion,
// https://mvnrepository.com/artifact/com.github.stephengold/Minie
"com.github.stephengold" % "Minie" % "3.0.0",
// https://mvnrepository.com/artifact/com.simsilica/zay-es
"com.simsilica" % "zay-es" % "1.2.1",
"org.typelevel" %% "cats-core" % "2.1.1",
"com.lihaoyi" % "ammonite" % "2.2.0" cross CrossVersion.full,
"org.jetbrains.kotlin" % "kotlin-main-kts" % "1.4.10",
"org.jetbrains.kotlin" % "kotlin-scripting-jsr223" % "1.4.10",
// "wow.doge" % "game" % "1.0-SNAPSHOT",
"org.scalafx" %% "scalafx" % "14-R19",
"com.typesafe.akka" %% "akka-actor-typed" % "2.6.10",
"ch.qos.logback" % "logback-classic" % "1.2.3",
"org.typelevel" %% "cats-core" % "2.1.1",
"org.typelevel" %% "cats-effect" % "2.1.4",
"io.monix" %% "monix" % "3.2.2",
"io.monix" %% "monix-bio" % "1.0.0",
"io.circe" %% "circe-core" % "0.13.0",
"io.circe" %% "circe-generic" % "0.13.0",
"com.softwaremill.sttp.client" %% "core" % "2.2.5",
"com.softwaremill.sttp.client" %% "monix" % "2.2.5",
"com.softwaremill.sttp.client" %% "circe" % "2.2.5",
"com.softwaremill.sttp.client" %% "async-http-client-backend-monix" % "2.2.5",
"com.github.valskalla" %% "odin-monix" % "0.8.1",
"com.softwaremill.macwire" %% "util" % "2.3.7",
"com.softwaremill.macwire" %% "macros" % "2.3.6" % "provided",
"com.softwaremill.macwire" %% "macrosakka" % "2.3.6" % "provided",
"com.github.valskalla" %% "odin-slf4j" % "0.8.1",
"com.softwaremill.quicklens" %% "quicklens" % "1.6.1"
),
// Determine OS version of JavaFX binaries
// Add JavaFX dependencies
libraryDependencies ++= javaFXModules.map(m =>
"org.openjfx" % s"javafx-$m" % "14.0.1" classifier osName
),
scalacOptions ++= Seq(
"-encoding",
"UTF-8",
"-deprecation",
"-feature",
"-unchecked",
"-Xlint",
"-Ywarn-numeric-widen",
"-Ymacro-annotations",
// "utf-8", // Specify character encoding used by source files.
"-explaintypes" // Explain type errors in more detail.
),
javacOptions ++= Seq("-source", "11", "-target", "11"),
javaOptions ++= Seq("-Xmx2G", "-Xms2G"),
fork := true,
assemblyMergeStrategy in assembly := {
case PathList("javax", "servlet", xs @ _*) => MergeStrategy.first
case PathList(ps @ _*) if ps.last endsWith ".html" => MergeStrategy.first
case "application.conf" => MergeStrategy.concat
case "unwanted.txt" => MergeStrategy.discard
case x if Assembly.isConfigFile(x) =>
MergeStrategy.concat
case PathList("META-INF", xs @ _*) =>
(xs map { _.toLowerCase }) match {
case ("manifest.mf" :: Nil) | ("index.list" :: Nil) |
("dependencies" :: Nil) =>
MergeStrategy.discard
case ps @ (x :: xs)
if ps.last.endsWith(".sf") || ps.last.endsWith(".dsa") =>
MergeStrategy.discard
case "plexus" :: xs =>
MergeStrategy.discard
case "services" :: xs =>
MergeStrategy.filterDistinctLines
case ("spring.schemas" :: Nil) | ("spring.handlers" :: Nil) =>
MergeStrategy.filterDistinctLines
case _ => MergeStrategy.first // Changed deduplicate to first
}
case PathList(_*) => MergeStrategy.first
// case x =>
// val oldStrategy = (assemblyMergeStrategy in assembly).value
// oldStrategy(x)
}
// scalaVersion := "2.13.2", // 2.11.12, or 2.13.3
// semanticdbEnabled := true, // enable SemanticDB
// semanticdbVersion := scalafixSemanticdb.revision // use Scalafix compatible version
// semanticdbVersion := "4.3.24",
)
// Here, `libraryDependencies` is a set of dependencies, and by using `+=`,
// we're adding the scala-parser-combinators dependency to the set of dependencies
// that sbt will go and fetch when it starts up.
// Now, in any Scala file, you can import classes, objects, etc., from
// scala-parser-combinators with a regular import.
// TIP: To find the "dependency" that you need to add to the
// `libraryDependencies` set, which in the above example looks like this:
// "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2"
// You can use Scaladex, an index of all known published Scala libraries. There,
// after you find the library you want, you can just copy/paste the dependency
// information that you need into your build file. For example, on the
// scala/scala-parser-combinators Scaladex page,
// https://index.scala-lang.org/scala/scala-parser-combinators, you can copy/paste
// the sbt dependency from the sbt box on the right-hand side of the screen.
// IMPORTANT NOTE: while build files look _kind of_ like regular Scala, it's
// important to note that syntax in *.sbt files doesn't always behave like
// regular Scala. For example, notice in this build file that it's not required
// to put our settings into an enclosing object or class. Always remember that
// sbt is a bit different, semantically, than vanilla Scala.
// ============================================================================
// Most moderately interesting Scala projects don't make use of the very simple
// build file style (called "bare style") used in this build.sbt file. Most
// intermediate Scala projects make use of so-called "multi-project" builds. A
// multi-project build makes it possible to have different folders which sbt can
// be configured differently for. That is, you may wish to have different
// dependencies or different testing frameworks defined for different parts of
// your codebase. Multi-project builds make this possible.
// Here's a quick glimpse of what a multi-project build looks like for this
// build, with only one "subproject" defined, called `root`:
// lazy val root = (project in file(".")).
// settings(
// inThisBuild(List(
// organization := "ch.epfl.scala",
// scalaVersion := "2.13.1"
// )),
// name := "hello-world"
// )
// To learn more about multi-project builds, head over to the official sbt
// documentation at http://www.scala-sbt.org/documentation.html

BIN
libbulletjme.so Normal file

Binary file not shown.

1
project/build.properties Normal file
View File

@ -0,0 +1 @@
sbt.version=1.3.13

2
project/plugins.sbt Normal file
View File

@ -0,0 +1,2 @@
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.15.0")
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.23")

View File

@ -0,0 +1 @@
org.jetbrains.kotlin.mainKts.jsr223.KotlinJsr223MainKtsScriptEngineFactory

View File

@ -0,0 +1,7 @@
jme-dispatcher {
type = "Dispatcher"
name = "JME-Thread"
executor = "wow.doge.mygame.executors.JMEThreadExecutorServiceConfigurator"
throughput = 1
}
akka.jvm-exit-on-fatal-error = on

View File

@ -0,0 +1,2 @@
// println("hello from dep")
class Test(x: Int)

View File

@ -0,0 +1,36 @@
// @file:Import("src/main/resources/hello2.main.kts")
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.0-M1")
@file:DependsOn("/home/rohan/.m2/repository/wow/doge/game/1.0-SNAPSHOT/game-1.0-SNAPSHOT.jar")
@file:DependsOn("/home/rohan/.ivy2/local/wow.doge/mygame_2.13/1.0-SNAPSHOT/jars/mygame_2.13.jar")
import wow.doge.game.types.GameScript
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.random.Random
import wow.doge.mygame.components.Test
//println(x * 2)
println("hello from main script")
class GameScriptImpl : GameScript {
override fun start() = runBlocking {
for(x in 0 until 5) {
launch {
val del = Random.nextLong(20, 100)
delay(del)
println("hello from start $x, delay is $del")
}
}
}
override fun stop() {println("hello from stop")}
}
GameScriptImpl()
class MyTest : Test()

View File

@ -0,0 +1,35 @@
// #!/usr/bin/env amm
// import coursierapi.MavenRepository
// interp.repositories.update(
// interp.repositories() ::: List(
// MavenRepository.of("file://home/rohan/.m2/repository")
// )
// )
// @
// import $repo.`https://jcenter.bintray.com`
// // import $repo.`https://bintray.com/jmonkeyengine/com.jme3`
// import $file.dep
// import $ivy.`org.jmonkeyengine:jme3-core:3.2.4-stable`
// import $ivy.`wow.doge:game:1.0-SNAPSHOT`
// import wow.doge.game.types.GameScript
// import com.jme3.scene.control.Control
// println("hello from script")
// class Scr extends GameScript {
// def start(): Unit = println("hello from start")
// def stop(): Unit = println("hello from stop")
// }
// // class SomeClass extends Control {}
// @main
// def main(): GameScript = new Scr()
import $file.dep
import dep.Test
new Test(1)

View File

@ -0,0 +1,5 @@
println("hello from dep")
class Test(val x: Int)
var x = 2

View File

@ -0,0 +1,107 @@
#!/usr/bin/env amm
// import coursierapi.MavenRepository
// interp.repositories.update(
// interp.repositories() ::: List(
// MavenRepository.of("file://home/rohan/.m2/repository")
// )
// )
// @
import $repo.`https://jcenter.bintray.com`
// import $repo.`https://bintray.com/jmonkeyengine/com.jme3`
// import $file.dep
import $ivy.`org.jmonkeyengine:jme3-core:3.2.4-stable`
// import $ivy.`wow.doge:game:1.0-SNAPSHOT`
import $ivy.`wow.doge::mygame:1.0-SNAPSHOT`
// import wow.doge.game.types.GameScript
import com.jme3.scene.control.Control
// println("hello from script")
// class Scr extends GameScript {
// def start(): Unit = println("hello from start")
// def stop(): Unit = println("hello from stop")
// }
// // class SomeClass extends Control {}
// @main
// def main(): GameScript = new Scr()
import com.simsilica.es.base.DefaultEntityData
import com.simsilica.es.EntityData
import com.jme3.app.Application
import wow.doge.mygame.game.Implicits._
import wow.doge.mygame.components.TestComponent
import com.jme3.scene.shape.Box
import com.jme3.scene.Geometry
import com.jme3.material.Material
import com.jme3.math.ColorRGBA
import com.jme3.asset.AssetManager
import com.jme3.math.Vector3f
import wow.doge.mygame.state._
class TestAppState(
// private var _entity: Option[EntityData] = Some(new DefaultEntityData())
) extends MyBaseState {
protected lazy val b = new Box(1, 1, 1)
protected lazy val geom = new Geometry("Box", b)
protected lazy val mat = Material(
assetManager = assetManager,
path = "Common/MatDefs/Misc/Unshaded.j3md"
)
// def entity = _entity
// override def initialize(app: Application): Unit = {
// super.initialize(app)
// }
override def init() = {
entityData
.createEntity()
.withComponents(TestComponent())
// entityData.setComponents(x, TestComponent())
val es = entityData.getEntities(classOf[TestComponent])
println(es)
geom.setMaterial(mat)
rootNode.attachChild(geom)
// geom.foreach(e => {
// })
}
override def update(tpf: Float) = {
geom.rotate(0, 0.5f * tpf, 0)
geom.move(new Vector3f(0, 1 * tpf, 0))
}
override def cleanup(app: Application): Unit = {
// _entity.map(_.close())
// _entity = None
}
override def onEnable(): Unit = {}
override def onDisable(): Unit = {}
}
object Material {
def apply(
color: String = "Color",
colorType: com.jme3.math.ColorRGBA = ColorRGBA.Blue,
assetManager: AssetManager,
path: String
): Material = {
val mat =
new Material(assetManager, path)
mat.setColor(color, colorType)
mat
}
}
@main
def main(): MyBaseState = new TestAppState()

View File

@ -0,0 +1,19 @@
{
"record": "Weapon",
"values": {
"baseId": "4F00000062",
"weaponType": "sword",
"name": "Exquisite Steel Sword",
"attack": "40",
"weight": "20"
}
}
val entity = ed.createEntity()
entity.setComponents(
Record("Weapon"),
WeaponType("Sword"),
Name("Exquisite Steel Sword"),
Attack(40),
Weight(20)
)

View File

@ -0,0 +1,62 @@
package com.jme3
import com.jme3.input.Action
package object animation {
implicit class AnimChannelWrap(val uval: AnimChannel) extends AnyVal {
/**
* Set the current animation that is played by this AnimChannel.
* <p>
* See {@link #setAnim(java.lang.String, float)}.
* The blendTime argument by default is 150 milliseconds.
*
* @param action The action (name) of the animation to play
*/
def setAnim(action: Action): Unit = uval.setAnim(action.name)
/**
* Set the current animation that is played by this AnimChannel.
* <p>
* This resets the time to zero, and optionally blends the animation
* over <code>blendTime</code> seconds with the currently playing animation.
* Notice that this method will reset the control's speed to 1.0.
*
* @param action The action (name) of the animation to play
* @param blendTime The blend time over which to blend the new animation
* with the old one. If zero, then no blending will occur and the new
* animation will be applied instantly.
*/
def setAnim(action: Action, blendTime: Float): Unit = uval.setAnim(action.name, blendTime)
}
implicit class AnimEventListenerWrap(val uval: AnimEventListener) extends AnyVal {
/**
* Invoked when an animation "cycle" is done. For non-looping animations,
* this event is invoked when the animation is finished playing. For
* looping animations, this even is invoked each time the animation is restarted.
*
* @param control The control to which the listener is assigned.
* @param channel The channel being altered
* @param action The new animation action that is done.
*/
def onAnimCycleDone(control: AnimControl, channel: AnimChannel, action: Action): Unit =
uval.onAnimCycleDone(control, channel, action.name)
/**
* Invoked when a animation is set to play by the user on the given channel.
*
* @param control The control to which the listener is assigned.
* @param channel The channel being altered
* @param action The new animation action set.
*/
def onAnimChange(control: AnimControl, channel: AnimChannel, action: Action): Unit =
uval.onAnimChange(control, channel, action.name)
}
}

View File

@ -0,0 +1,16 @@
package com.jme3
/**
* Created by Brandon Barker on 6/19/17.
*/
package object app {
implicit class SimpleApplicationWrap(val uval: SimpleApplication) extends AnyVal {
//FIXME: proof of concept, remove later
def testWrap: String = uval.hashCode().toString
}
}

View File

@ -0,0 +1,6 @@
package com.jme3.input
/**
* Created by Brandon Barker on 6/19/17.
*/
final case class Action(name: String) extends AnyVal

View File

@ -0,0 +1,37 @@
package com.jme3.input
/**
* Created by Brandon Barker on 6/19/17.
*/
package object controls {
implicit class ActionListenerWrap(val uval: ActionListener) extends AnyVal {
/**
* Called when an input to which this listener is registered to is invoked.
*
* @param action The action (name) of the mapping that was invoked
* @param isPressed True if the action is "pressed", false otherwise
* @param tpf The time per frame value.
*/
def onAction(action: Action, keyPressed: Boolean, tpf: Float): Unit =
uval.onAction(action.name, keyPressed, tpf)
}
implicit class AnalogListenerWrap(val uval: AnalogListener) extends AnyVal {
/**
* Called to notify the implementation that an analog event has occurred.
*
* The results of KeyTrigger and MouseButtonTrigger events will have tpf
* == value.
*
* @param action The action (name) of the mapping that was invoked
* @param value Value of the axis, from 0 to 1.
* @param tpf The time per frame value.
*/
def onAnalog(action: Action, value: Float, tpf: Float): Unit =
uval.onAnalog(action.name, value, tpf)
}
}

View File

@ -0,0 +1,18 @@
package com.jme3
import com.jme3.input.controls.{InputListener, Trigger}
/**
* Created by Brandon Barker on 6/21/17.
*/
package object input {
implicit class InputManagerWrap(val uval: InputManager) extends AnyVal {
def addMapping(action: Action, triggers: Trigger*): Unit =
uval.addMapping(action.name, triggers: _*)
def addListener(listener: InputListener, actions: Action*): Unit =
uval.addListener(listener, actions.map(act => act.name): _*)
}
}

View File

@ -0,0 +1,11 @@
package com.jme3
import com.jme3.asset.AssetManager
package object material {
object Material {
def apply(contentMan: AssetManager, defName: String): Material =
new Material(contentMan, defName)
}
}

View File

@ -0,0 +1,19 @@
package com.jme3.scene
import com.jme3.animation.Skeleton
package object debug {
object SkeletonDebugger {
/**
* Creates a debugger with no length data. The wires will be a connection between the bones' heads only.
* The points will show the bones' heads only and no dotted line of inter bones connection will be visible.
* @param name
* the name of the debugger's node
* @param skeleton
* the skeleton that will be shown
*/
def apply(name: String, skeleton: Skeleton) = new SkeletonDebugger(name, skeleton)
}
}

View File

@ -0,0 +1,56 @@
package com.jme3
import com.jme3.scene.control.Control
/**
* Created by Brandon Barker on 6/19/17.
*/
package object scene {
object Geometry {
/**
* Create a geometry node with mesh data.
* The material of the geometry is null, it cannot
* be rendered until it is set.
*
* @param name The name of this geometry
* @param mesh The mesh data for this geometry
*/
def apply(name: String, mesh: Mesh): Geometry = new Geometry(name, mesh)
}
object Node {
/**
* Constructor instantiates a new <code>Node</code> with a default empty
* list for containing children.
*
* @param name the name of the scene element. This is required for
* identification and comparison purposes.
*/
def apply(name: String): Node = new Node(name)
}
implicit class NodeWrap(val uval: Node) extends AnyVal {
def getControlMaybe[T <: Control](controlType: Class[T]): Option[T] =
Option(uval.getControl(controlType))
}
implicit class SpatialWrap(val uval: Spatial) extends AnyVal {
def toNode: Either[ClassCastException, Node] =
uval match {
case ul: Node => Right(ul)
case ul =>
Left(
new ClassCastException(s"Couldn't convert ${ul.getName} to Node")
)
}
}
}

View File

@ -0,0 +1,20 @@
package com.jme3.scene
package object shape {
object Box {
/**
* Creates a new box.
* <p>
* The box has a center of 0,0,0 and extends in the out from the center by
* the given amount in <em>each</em> direction. So, for example, a box
* with extent of 0.5 would be the unit cube.
*
* @param xs the size of the box along the x axis, in both directions.
* @param ys the size of the box along the y axis, in both directions.
* @param zs the size of the box along the z axis, in both directions.
*/
def apply(xs: Float, ys: Float, zs: Float): Box = new Box(xs, ys, zs)
}
}

View File

@ -0,0 +1,14 @@
package com.jme3
/**
* Created by Brandon Barker on 6/21/17.
*/
package object syntax {
@specialized def discard[A](evaluateForSideEffectOnly: A): Unit = {
val _: A = evaluateForSideEffectOnly
() //Return unit to prevent warning due to discarding value
}
}

View File

@ -0,0 +1,5 @@
Hey guys, few days ago I discovered I could load objects created in scripts at runtime, and cast them to an interface to call their methods provided
1. both host program and script have access to the same interface via a common library
2. script object implements that interface
I was thinking, maybe I could implement appstates in scripts to implement game mechanics and attach them to the state manager at runtime, and similarly for components of an ECS. What do you guys think?

View File

@ -0,0 +1,127 @@
package wow.doge.mygame
import game.GameApp
import com.jme3.app.StatsAppState
import akka.actor.typed.ActorSystem
import akka.actor.typed.SpawnProtocol
import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.Behavior
import akka.util.Timeout
import com.jme3.system.AppSettings
import wow.doge.mygame.game.GameAppActor
import wow.doge.mygame.scriptsystem.ScriptCachingActor
object Main extends App {
import java.util.logging.{Logger, Level}
Logger.getLogger("").setLevel(Level.SEVERE)
// runner.runCode("""|println("starting scala script engine")""".stripMargin)
val gameApp = new GameApp(
// new EntityDataState(),
// new TestAppState(),
// new PlayerMovementState(),
// new FlyCamAppState(),
new StatsAppState()
)
val settings = new AppSettings(true)
// settings.setVSync(true)
settings.setFrameRate(144)
gameApp.setSettings(settings)
val actorSystem = ActorSystem(RootActor(gameApp), "rootActor")
// actorSystem.eventStream
// gameApp.start()
println("here 1")
// actorSystem.terminate()
// JMEExecutorService.shutdown()
// println("here 2")
//FIXME remove this
// System.exit(0)
}
object RootActor {
def apply(app: GameApp): Behavior[SpawnProtocol.Command] =
Behaviors.setup { ctx =>
ctx.log.debug("Starting root actor")
val testActor = ctx.spawn(TestActor(), "testActor")
val _ = ctx.spawn(GameAppActor(app), "gameAppActor")
testActor ! TestActor.Test
SpawnProtocol()
}
}
object TestActor {
sealed trait Command
case object Test extends Command
private case object Done extends Command
// sealed trait Result
// case object Done extends Result
import scala.concurrent.duration._
implicit val timeout = Timeout(15.seconds)
// implicit val scheduler =
def apply(): Behavior[Command] =
Behaviors.setup { ctx =>
ctx.spawn(ScriptCachingActor(), "scriptCacher")
Behaviors.receiveMessage { msg =>
msg match {
case Test =>
// ctx.ask(
// router,
// ScriptActor.Compile(
// // os.pwd / "some.sc",
// os.pwd / "src" / "main" / "resources" / "hello2.main.kts",
// _
// )
// ) {
// case Success(value) =>
// ctx.log.debug("Received Value")
// ctx.log.debug(value.toString())
// Done
// case Failure(exception) =>
// ctx.log.debug(s"Received Error ${exception.getMessage()}")
// Done
// }
// val x = scriptStorer
// .askT(
// ScriptStoringActor
// .Get(os.pwd / "src" / "main" / "resources" / "hello2.sc", _)
// )(timeout, ctx.system.scheduler)
// ctx.ask(
// scriptStorer,
// ScriptStoringActor
// .Get(os.pwd / "src" / "main" / "resources" / "hello2.sc", _)
// ) {
// case Success(value) => {
// ctx.log.debug(value.toString())
// ctx.ask(
// scriptStorer,
// ScriptStoringActor
// .Get(os.pwd / "src" / "main" / "resources" / "hello2.sc", _)
// ) {
// case Success(value) => {
// ctx.log.debug(value.toString())
// Done
// }
// case Failure(exception) =>
// ctx.log.debug(exception.getMessage())
// Done
// }
// Done
// }
// case Failure(exception) =>
// ctx.log.debug(exception.getMessage())
// Done
// }
Behaviors.same
case Done => Behaviors.same
}
// SpawnProtocol()
// Behaviors.same
}
}
}

View File

@ -0,0 +1,6 @@
package wow.doge.mygame.components
import com.simsilica.es.EntityComponent;
import wow.doge.mygame.math.ImVector3f
final case class Position(location: ImVector3f) extends EntityComponent

View File

@ -0,0 +1,28 @@
package wow.doge.mygame.components
import com.simsilica.es.EntityComponent
final case class Tag(name: String) extends EntityComponent
object Tag {
val SpaceShip = "SpaceShip"
val BasicInvader = "BasicInvader"
}
// public class Model implements EntityComponent {
// private final String name;
// public final static String SpaceShip = "SpaceShip";
// public final static String BasicInvader = "BasicInvader";
// public Model(String name) {
// this.name = name;
// }
// public String getName() {
// return name;
// }
// @Override
// public String toString() {
// return "Model[" + name + "]";
// }
// }

View File

@ -0,0 +1,11 @@
package wow.doge.mygame.components;
import com.jme3.math.Vector3f;
import wow.doge.mygame.math.ImVector3f;
//test java final case class instantiation
public class Test {
public void test() {
var pos = Position.apply(ImVector3f.apply(1, 1, 1));
}
}

View File

@ -0,0 +1,5 @@
package wow.doge.mygame.components
import com.simsilica.es.EntityComponent
final case class TestComponent() extends EntityComponent

View File

@ -0,0 +1,139 @@
package wow.doge.mygame.events
// import akka.event.ActorEventBus
// import akka.event.ManagedActorClassification
// import akka.event.ActorClassifier
import akka.actor.typed.ActorRef
// import akka.actor.ActorSystem
// import akka.event.EventBus
// import akka.util.Subclassification
// import java.util.concurrent.atomic.AtomicReference
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.Behaviors
import scala.reflect.ClassTag
import akka.event.EventStream
// private[events] final case class ClassificationMessage(ref: ActorRef, id: Int)
// class ActorBusImpl(val system: ActorSystem, val busSize: Int)
// extends ActorEventBus
// with ActorClassifier
// with ManagedActorClassification {
// type Event = ClassificationMessage
// // is used for extracting the classifier from the incoming events
// override protected def classify(event: Event): ActorRef = event.ref
// // determines the initial size of the index data structure
// // used internally (i.e. the expected number of different classifiers)
// override protected def mapSize: Int = busSize
// }
// class StartsWithSubclassification extends Subclassification[String] {
// override def isEqual(x: String, y: String): Boolean =
// x == y
// override def isSubclass(x: String, y: String): Boolean =
// x.startsWith(y)
// }
// import akka.event.SubchannelClassification
// final case class MsgEnvelope(topic: String, payload: Any)
// import akka.actor.typed.scaladsl.adapter._
// /**
// * Publishes the payload of the MsgEnvelope when the topic of the
// * MsgEnvelope starts with the String specified when subscribing.
// */
// class SubchannelBusImpl extends EventBus with SubchannelClassification {
// type Event = Any
// type Classifier = Class[_]
// type Subscriber = ActorRef
// // Subclassification is an object providing `isEqual` and `isSubclass`
// // to be consumed by the other methods of this classifier
// // override protected val subclassification: Subclassification[Classifier] =
// // new StartsWithSubclassification
// private val initiallySubscribedOrUnsubscriber =
// new AtomicReference[Either[Set[ActorRef], ActorRef]](Left(Set.empty))
// override protected implicit val subclassification
// : Subclassification[Classifier] = new Subclassification[Class[_]] {
// def isEqual(x: Class[_], y: Class[_]) = x == y
// def isSubclass(x: Class[_], y: Class[_]) = y.isAssignableFrom(x)
// }
// // is used for extracting the classifier from the incoming events
// override protected def classify(event: Event): Classifier = event.getClass()
// // will be invoked for each event for all subscribers which registered
// // themselves for the events 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
}
}

View File

@ -0,0 +1,17 @@
package wow.doge.mygame.events
// object Test {
// Events.BulletFired
// }
object Events {
sealed trait Event
case object BulletFired extends Event
// type BulletFired = BulletFired.type
case class EventWithData(data: Int) extends Event
sealed trait Tick extends Event
case object RenderTick extends Tick
case object PhysicsTick extends Tick
}

View File

@ -0,0 +1,3 @@
package wow.doge.mygame.events
trait EventsModule {}

View File

@ -0,0 +1,5 @@
package wow.doge.mygame.executors
trait ExecutorsModule {
lazy val schedulers = new Schedulers()
}

View File

@ -0,0 +1,103 @@
package wow.doge.mygame.executors
import akka.dispatch.{
DispatcherPrerequisites,
ExecutorServiceFactory,
ExecutorServiceConfigurator
}
import com.typesafe.config.Config
import java.util.concurrent.{
ExecutorService,
AbstractExecutorService,
ThreadFactory,
TimeUnit
}
import java.util.Collections
import javax.swing.SwingUtilities
import javafx.application.Platform
import monix.execution.Scheduler
import scala.concurrent.ExecutionContext
import java.util.concurrent.Executor
import wow.doge.mygame.Main
// First we wrap invokeLater/runLater as an ExecutorService
trait GUIExecutorService extends AbstractExecutorService {
def execute(command: Runnable): Unit
def shutdown(): Unit = ()
def shutdownNow() = Collections.emptyList[Runnable]
def isShutdown = false
def isTerminated = false
def awaitTermination(l: Long, timeUnit: TimeUnit) = true
}
object JavaFXExecutorService extends GUIExecutorService {
override def execute(command: Runnable) = Platform.runLater(command)
}
object SwingExecutorService extends GUIExecutorService {
override def execute(command: Runnable) = SwingUtilities.invokeLater(command)
}
object JMEExecutorService extends GUIExecutorService {
override def execute(command: Runnable) = Main.gameApp.enqueue(command)
}
class JavaFXEventThreadExecutorServiceConfigurator(
config: Config,
prerequisites: DispatcherPrerequisites
) extends ExecutorServiceConfigurator(config, prerequisites) {
private val f = new ExecutorServiceFactory {
def createExecutorService: ExecutorService = JavaFXExecutorService
}
def createExecutorServiceFactory(
id: String,
threadFactory: ThreadFactory
): ExecutorServiceFactory = f
}
class JMEThreadExecutorServiceConfigurator(
config: Config,
prerequisites: DispatcherPrerequisites
) extends ExecutorServiceConfigurator(config, prerequisites) {
private val f = new ExecutorServiceFactory {
def createExecutorService: ExecutorService = JMEExecutorService
}
def createExecutorServiceFactory(
id: String,
threadFactory: ThreadFactory
): ExecutorServiceFactory = f
}
// Then we create an ExecutorServiceConfigurator so that Akka can use our SwingExecutorService for the dispatchers
class SwingEventThreadExecutorServiceConfigurator(
config: Config,
prerequisites: DispatcherPrerequisites
) extends ExecutorServiceConfigurator(config, prerequisites) {
private val f = new ExecutorServiceFactory {
def createExecutorService: ExecutorService = SwingExecutorService
}
def createExecutorServiceFactory(
id: String,
threadFactory: ThreadFactory
): ExecutorServiceFactory = f
}
object JFXExecutionContexts {
val javaFxExecutionContext: ExecutionContext =
ExecutionContext.fromExecutor(new Executor {
def execute(command: Runnable): Unit = {
Platform.runLater(command)
}
})
val fxScheduler =
Scheduler(javaFxExecutionContext)
}

View File

@ -0,0 +1,10 @@
package wow.doge.mygame.executors
import monix.execution.Scheduler
final case class Schedulers(
blockingIO: Scheduler = Scheduler.io(),
cpu: Scheduler = Scheduler.global,
fx: Scheduler = JFXExecutionContexts.fxScheduler,
jme: Option[Scheduler] = None
)

View File

@ -0,0 +1,109 @@
package wow.doge.mygame.game
import com.jme3.app.SimpleApplication
import com.jme3.app.state.AppState
import akka.actor.typed.ActorRef
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.Behaviors
object Greeter {
final case class Greet(whom: String, replyTo: ActorRef[Greeted])
final case class Greeted(whom: String, from: ActorRef[Greet])
def apply(): Behavior[Greet] =
Behaviors.receive { (context, message) =>
// context.log.info("Hello {}!", message.whom)
//#greeter-send-messages
message.replyTo ! Greeted(message.whom, context.self)
//#greeter-send-messages
Behaviors.same
}
}
class GameApp(
// actorSystem: ActorSystem[SpawnProtocol.Command],
appStates: AppState*
) extends SimpleApplication(appStates: _*) {
// implicit val timeout = Timeout(10.seconds)
// implicit val scheduler = actorSystem.scheduler
override def simpleInitApp(): Unit = {
// val ship = ed.createEntity()
// val mbState = stateManager().state[EntityDataState]().map(_.getEntityData())
// val mbState = Try(
// stateManager()
// .state[TestAppState]()
// .entity
// ).toOption.flatten.toRight(println("empty"))
// // .flatMap(_.entity)
// val x = mbState.flatMap(
// _.query
// .filter[TestComponent]("name", new Object())
// // .filterOr[TestEntity](
// // Filters
// // .fieldEquals(classOf[TestEntity], "", null)
// // )
// .component[Tag]()
// .component[TestComponent]()
// .result
// .toRight(println("failed"))
// )
// rootNode
// .child(geom)
// .child(geom)
// .child(geom)
// .child(geom)
// .child(geom)
// .child(geom)
// .child(geom)
// .child(geom)
// Future(println("hello"))(jmeEC(this))
// val wbActor: Future[ActorRef[Greeter.Greet]] = actorSystem.ask(
// SpawnProtocol.Spawn(
// behavior = Greeter(),
// name = "listener",
// DispatcherSelector.fromConfig("jme-dispatcher"),
// _
// )
// )
// wbActor.map(a => a.ask(Greeter.Greet("hello", _)).map(println))
}
override def simpleUpdate(tpf: Float): Unit = {
// val rot2 = rot.fromAngleAxis(FastMath.PI, new Vector3f(0, 0, 1))
// val rotation = geom.getLocalRotation()
// rotation.add(rot2)
// geom.rotate(rot2)
// geom.updateModelBound()
// geom.updateGeometricState()
}
// override def stop(): Unit = {
// actorSystem.terminate()
// super.stop()
// }
}
object GameApp {
// def myExec(app: SimpleApplication, command: Runnable) = {
// app.enqueue(command)
// }
// val javaFxExecutionContext: ExecutionContext =
// ExecutionContext.fromExecutor(new Executor {
// def execute(command: Runnable): Unit = {
// Platform.runLater(command)
// }
// })
// def jmeEC(app: SimpleApplication): ExecutionContext =
// ExecutionContext.fromExecutor(new Executor {
// override def execute(command: Runnable): Unit = app.enqueue(command)
// })
// def jmeScheduler(app: SimpleApplication) = Sch
}

View File

@ -0,0 +1,67 @@
package wow.doge.mygame.game
import akka.actor.typed.scaladsl.Behaviors
import wow.doge.mygame.state.MovementActor
import wow.doge.mygame.state.PlayerMovementState2
import wow.doge.mygame.state.MovementActorTimer
import com.jme3.scene.shape.Box
import com.jme3.scene.Geometry
import wow.doge.mygame.implicits._
import wow.doge.mygame.events.EventBus
import wow.doge.mygame.events.Events
import wow.doge.mygame.state.ImMovementActor
object GameAppActor {
sealed trait Command
def apply(app: GameApp) =
Behaviors.setup[Command] { ctx =>
lazy val b = new Box(1, 1, 1)
lazy val geom = new Geometry("Box", b)
val movementActor =
ctx.spawn(
MovementActor(MovementActor.Props(app, geom)),
"movementActor"
// DispatcherSelector.fromConfig("jme-dispatcher")
)
val movementActorTimer = ctx.spawn(
MovementActorTimer(movementActor),
"movementActorTimer"
)
val imMovementActor = ctx.spawn(
ImMovementActor(ImMovementActor.Props(app, geom)),
"imMovementActor"
)
val subscribingActor = ctx.spawn(SubscribingActor(), "subscriber-1")
val eventBus =
ctx.spawn(Behaviors.logMessages(EventBus[Events.Tick]()), "eventBus1")
eventBus ! EventBus.Subscribe(subscribingActor)
eventBus ! EventBus.Publish(Events.PhysicsTick, ctx.self)
app
.getStateManager()
.attach(
new PlayerMovementState2(
movementActor,
movementActorTimer,
imMovementActor,
geom
)
)
app.start()
Behaviors.stopped
}
}
object SubscribingActor {
def apply() =
Behaviors.receive[Events.PhysicsTick.type] { (ctx, msg) =>
ctx.log.debug(s"received event $msg")
Behaviors.same
}
}

View File

@ -0,0 +1,55 @@
package wow.doge.mygame.implicits
import com.simsilica.es.ComponentFilter
import com.simsilica.es.EntityComponent
import com.simsilica.es.EntityData
import com.simsilica.es.EntitySet
import com.simsilica.es.Filters
import scala.reflect.ClassTag
import scala.util.Try
class EntityQuery(ed: EntityData) {
private var cfilter: Option[ComponentFilter[_ <: EntityComponent]] = None
private val buf = collection.mutable.ListBuffer.empty[Class[_]]
def filter[T <: EntityComponent](field: String, value: Object)(implicit
ev: ClassTag[T]
): EntityQuery = {
val c = ev.runtimeClass.asInstanceOf[Class[T]]
cfilter = Try(Filters.fieldEquals(c, field, value)).toOption
this
}
def filterOr[T <: EntityComponent](operands: ComponentFilter[_ <: T]*)(
implicit ev: ClassTag[T]
): EntityQuery = {
val c = ev.runtimeClass.asInstanceOf[Class[T]]
cfilter = Try(Filters.or(c, operands: _*)).toOption
this
}
def filterAnd[T <: EntityComponent](operands: ComponentFilter[_ <: T]*)(
implicit ev: ClassTag[T]
): EntityQuery = {
val c = ev.runtimeClass.asInstanceOf[Class[T]]
cfilter = Try(Filters.and(c, operands: _*)).toOption
this
}
def component[T <: EntityComponent]()(implicit
ev: ClassTag[T]
): EntityQuery = {
val c = ev.runtimeClass
buf += c
this
}
def components[T <: EntityComponent](lst: Class[T]*): EntitySet = {
ed.getEntities(lst: _*)
}
def result: EntitySet =
cfilter.fold(ed.getEntities(buf.toList: _*)) { filters =>
ed.getEntities(filters, buf.toList: _*)
}
}

View File

@ -0,0 +1,175 @@
package wow.doge.mygame
import com.jme3.app.SimpleApplication
import com.jme3.app.state.AppStateManager
import scala.reflect.ClassTag
import com.jme3.app.state.AppState
import com.jme3.scene.Node
import com.jme3.scene.Spatial
import com.simsilica.es.EntityData
import com.simsilica.es.EntityComponent
import com.simsilica.es.EntityId
import akka.actor.typed.ActorRef
import akka.util.Timeout
import akka.actor.typed.Scheduler
import monix.eval.Task
import com.jme3.input.InputManager
import com.jme3.input.controls.Trigger
import com.jme3.input.controls.InputListener
import com.jme3.math.Vector3f
import wow.doge.mygame.math.ImVector3f
import com.jme3.scene.Geometry
import wow.doge.mygame.state.CardinalDirection
import wow.doge.mygame.state.CanMove
import com.jme3.renderer.Camera
package object implicits {
implicit class StateManagerExt(val sm: AppStateManager) extends AnyVal {
def state[S <: AppState]()(implicit c: ClassTag[S]): S =
sm.getState(c.runtimeClass.asInstanceOf[Class[S]])
}
implicit class SimpleApplicationExt(val sa: SimpleApplication)
extends AnyVal {
def stateManager() = sa.getStateManager()
}
implicit class NodeExt(val n: Node) extends AnyVal {
def child(s: Spatial): Node = {
n.attachChild(s)
n
}
}
implicit class EntityDataExt(val ed: EntityData) extends AnyVal {
def query = new EntityQuery(ed)
// def entities[T <: EntityComponent](entities: Seq[T])
}
implicit class EntityExt(val e: EntityId) extends AnyVal {
def withComponents(classes: EntityComponent*)(implicit
ed: EntityData
): EntityId = {
ed.setComponents(e, classes: _*)
e
}
}
implicit class ActorRefExt[Req](val a: ActorRef[Req]) extends AnyVal {
import akka.actor.typed.scaladsl.AskPattern._
def askT[Res](
replyTo: ActorRef[Res] => Req
)(implicit timeout: Timeout, scheduler: Scheduler): Task[Res] = {
Task.deferFuture(a.ask(replyTo)(timeout, scheduler))
}
}
// def ?[Res](replyTo: ActorRef[Res] => Req)(implicit timeout: Timeout, scheduler: Scheduler): Future[Res] = {
// ask(replyTo)(timeout, scheduler)
// }
implicit class InputManagerExt(val inputManager: InputManager)
extends AnyVal {
def withMapping(mapping: String, triggers: Trigger*): InputManager = {
inputManager.addMapping(mapping, triggers: _*)
inputManager
}
def withListener(listener: InputListener, mappings: String*) = {
inputManager.addListener(listener, mappings: _*)
inputManager
}
}
implicit class Vector3fExt(val v: Vector3f) extends AnyVal {
def +=(that: Vector3f) = v.addLocal(that)
def *=(that: Vector3f) = v.multLocal(that)
def -=(that: Vector3f) = v.subtractLocal(that)
def /=(that: Vector3f) = v.divideLocal(that)
def unary_- = v.negateLocal()
def immutable = ImVector3f(v.x, v.y, v.z)
}
implicit class ImVector3fExt(val v: ImVector3f) extends AnyVal {
def +(that: ImVector3f) = v.copy(v.x + that.x, v.y + that.y, v.z + that.z)
def *(that: ImVector3f) = v.copy(v.x * that.x, v.y * that.y, v.z * that.z)
def *(f: Float): ImVector3f =
// v.copy(v.x * f, v.y * f, v.x * f)
v * ImVector3f(f, f, f)
def -(that: ImVector3f) = v.copy(v.x - that.x, v.y - that.y, v.z - that.z)
def /(that: ImVector3f) = v.copy(v.x / that.x, v.y / that.y, v.z / that.z)
def unary_- = v.copy(-v.x, -v.y, -v.z)
// def unary_-(that: ImVector3f) = this.copy(this.x, this.y, this.z)
def mutable = new Vector3f(v.x, v.y, v.z)
}
// implicit val implVector3fForVector3 = new Vector3[Vector3f] {
// override def +(implicit v: Vector3f, that: com.jme3.math.Vector3f): Unit =
// v += that
// override def *(implicit v: Vector3f, that: Vector3f): Unit = v *= that
// override def -(implicit v: Vector3f, that: Vector3f): Unit = v -= that
// override def /(implicit v: Vector3f, that: Vector3f): Unit = v /= that
// }
// implicit val implImVector3fForVector3 = new Vector3[ImVector3f] {
// override def +(implicit v: ImVector3f, that: ImVector3f): Unit =
// v + that
// override def *(implicit v: ImVector3f, that: ImVector3f): Unit = v * that
// override def -(implicit v: ImVector3f, that: ImVector3f): Unit = v - that
// override def /(implicit v: ImVector3f, that: ImVector3f): Unit = v / that
// }
// def test[T](v: T)(implicit ev: Vector3[T]) = {
// import ev._
// ev.+
// }
implicit val implCanMoveForGeom = new CanMove[Geometry] {
override def getDirection(
cam: Camera,
cardinalDir: CardinalDirection
): ImVector3f = {
val camDir =
cam.getDirection().immutable * 0.6f
val camLeft = cam.getLeft().immutable * 0.4f
val zero = ImVector3f.ZERO
val dir = cardinalDir
val walkDir = {
val mutWalkDir = new Vector3f()
if (dir.left) {
// ctx.log.trace("left")
mutWalkDir += (zero + camLeft).mutable
}
if (dir.right) {
// ctx.log.trace("right")
mutWalkDir += (zero + -camLeft).mutable
}
if (dir.up) {
// ctx.log.trace("up")
mutWalkDir += (zero + camDir).mutable
}
if (dir.down) {
// ctx.log.trace("down")
mutWalkDir += (zero + -camDir).mutable
}
mutWalkDir.immutable
}
walkDir
}
override def move(geom: Geometry, direction: ImVector3f): Unit = {
val v = geom.getLocalTranslation()
geom.setLocalTranslation(v += direction.mutable)
}
}
}

View File

@ -0,0 +1,11 @@
package wow.doge.mygame.math
case class ImVector3f(x: Float = 0f, y: Float = 0f, z: Float = 0f)
object ImVector3f {
val ZERO = ImVector3f(0, 0, 0)
val UNIT_X = ImVector3f(1, 0, 0)
val UNIT_Y = ImVector3f(0, 1, 0)
val UNIT_Z = ImVector3f(0, 0, 1)
}

View File

@ -0,0 +1,157 @@
package wow.doge.mygame.state
import akka.actor.typed.scaladsl.Behaviors
import ammonite.Main
import akka.actor.typed.ActorRef
import com.jme3.app.state.AppState
import ammonite.runtime.Storage.Folder
import ammonite.main.Defaults
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.ActorContext
import ammonite.util.Res.Success
import javax.script.ScriptEngine
import javax.script.ScriptEngineManager
import scala.util.Try
import cats.implicits._
object ScriptActor {
sealed trait Result
final case class AppStateResult(state: AppState) extends Result
final case class Error(reason: String) extends Result
sealed trait Command
final case class Compile(path: os.Path, sender: ActorRef[Result])
extends Command
final case class CompileAny(
path: os.Path,
result: ActorRef[Either[Error, Any]]
) extends Command
def defaultScalaRunner() =
ammonite
.Main(
storageBackend = new Folder(
// os.pwd / "target"
Defaults.ammoniteHome,
isRepl = false
)
)
def defaultKotlinRunner(): ScriptEngine = {
val manager = new ScriptEngineManager()
val engine = manager.getEngineByExtension("main.kts")
engine
}
def apply(
scalaRunner: Main = defaultScalaRunner(),
kotlinRunner: ScriptEngine = defaultKotlinRunner()
// parent: ActorRef[ScriptStoringActor.Command]
): Behavior[ScriptActor.Command] =
Behaviors.setup(ctx =>
new ScriptActor(scalaRunner, kotlinRunner, ctx).receiveMessage
)
sealed trait ScriptType
case object ScalaType extends ScriptType
case object KotlinType extends ScriptType
case object GroovyType extends ScriptType
def determineScriptType(path: os.Path): Either[Error, ScriptType] =
path.toString match {
case s if s.endsWith(".sc") => Right(ScalaType)
case s if s.endsWith(".main.kts") => Right(KotlinType)
case s if s.endsWith(".groovy") => Right(GroovyType)
case _ => Left(Error("Unknown script type"))
}
def runScala(path: os.Path, scalaRunner: ammonite.Main): Either[Error, Any] =
scalaRunner
.runScript(
path,
Seq.empty
)
._1 match {
case ammonite.util.Res.Exception(t, msg) => Left(Error(msg))
case Success(obj) => Right(obj)
case _ => Left(Error("Failed to run script"))
}
def runKotlin(path: os.Path, kotlinRunner: ScriptEngine): Either[Error, Any] =
Try(kotlinRunner.eval(os.read(path))).toEither.leftMap(t =>
Error(t.getMessage())
)
def runGroovy(path: os.Path): Either[Error, Any] =
Left(Error("Not implemented yet"))
}
class ScriptActor(
val scalaRunner: Main,
val kotlinRunner: ScriptEngine,
// parent: ActorRef[ScriptStoringActor.Command],
context: ActorContext[ScriptActor.Command]
) {
import ScriptActor._
def receiveMessage: Behavior[Command] =
Behaviors.receiveMessage { msg =>
msg match {
case Compile(path, sender) =>
context.log.debug(s"Received $path")
val res = getScript(path)
sender ! res
Behaviors.same
// case CompileScripts(sender, paths) =>
case CompileAny(path, requester) =>
context.log.debug(s"Received $path")
val res = getScript2(path)
context.log.debug(s"result = $res")
requester ! res
// parent ! ScriptStoringActor.Put(path, res)
Behaviors.same
}
}
def getScript(path: os.Path) = {
val res = determineScriptType(path) match {
case Right(ScalaType) => runScala(path, scalaRunner)
case Right(KotlinType) => runKotlin(path, kotlinRunner)
case Right(GroovyType) => runGroovy(path)
case l @ Left(err) => l
}
res match {
case Left(err) => err
case Right(obj) =>
obj match {
case s: MyBaseState => AppStateResult(s)
case _ => Error("Class in script does not match known types")
}
}
}
def getScript2(path: os.Path): Either[Error, Any] = {
val res = determineScriptType(path) match {
case Right(ScalaType) => runScala(path, scalaRunner)
case Right(KotlinType) => runKotlin(path, kotlinRunner)
case Right(GroovyType) => runGroovy(path)
case l @ Left(err) => l
}
// res match {
// case Left(err) => err
// case Right(obj) =>
// obj match {
// case s: MyBaseState => AppStateResult(s)
// case _ => Error("Class in script does not match known types")
// }
// }
res
}
}

View File

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

View File

@ -0,0 +1,38 @@
package wow.doge.mygame.state;
import com.jme3.app.state.AbstractAppState;
import com.simsilica.es.EntityData;
import com.simsilica.es.base.DefaultEntityData;
import com.jme3.app.state.BaseAppState;
import com.jme3.app.Application;
public class EntityDataState extends BaseAppState {
private EntityData entityData;
public EntityDataState() {
this(new DefaultEntityData());
}
public EntityDataState(EntityData ed) {
this.entityData = ed;
}
public EntityData getEntityData() {
return entityData;
}
public void onEnable() {
}
public void onDisable() {
}
// @Override
public void cleanup(Application application) {
entityData.close();
entityData = null; // cannot be reused
}
public void initialize(Application application) {
}
}

View File

@ -0,0 +1,86 @@
package wow.doge.mygame.state
import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.Behaviors
import com.softwaremill.quicklens._
import wow.doge.mygame.implicits._
import com.jme3.renderer.Camera
import wow.doge.mygame.math.ImVector3f
trait CanMove[T] {
def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f
def move(inst: T, direction: ImVector3f): Unit
}
object ImMovementActor {
sealed trait Command
// final case class Tick(tpf: Float) extends Command
final case class Tick(tpf: Float) extends Command
sealed trait Movement extends Command
final case class MovedLeft(pressed: Boolean) extends Movement
final case class MovedUp(pressed: Boolean) extends Movement
final case class MovedRight(pressed: Boolean) extends Movement
final case class MovedDown(pressed: Boolean) extends Movement
final case class Props[T: CanMove](
app: com.jme3.app.Application,
movable: T
)
/**
* Internal state of the actor
*
* @param cardinalDir Immutable, can be shared as is
* @param walkDirection Immutable
*/
final case class State(
cardinalDir: CardinalDirection = CardinalDirection()
)
def apply[T: CanMove](props: Props[T]): Behavior[Command] =
Behaviors.setup(ctx => new ImMovementActor(ctx, props).receive(State()))
}
class ImMovementActor[T](
ctx: ActorContext[ImMovementActor.Command],
props: ImMovementActor.Props[T]
) {
import ImMovementActor._
def receive(
state: ImMovementActor.State
)(implicit cm: CanMove[T]): Behavior[Command] =
Behaviors.receiveMessage { msg =>
msg match {
case m: Movement =>
m match {
case MovedLeft(pressed) =>
receive(state = state.modify(_.cardinalDir.left).setTo(pressed))
case MovedUp(pressed) =>
receive(state = state.modify(_.cardinalDir.up).setTo(pressed))
case MovedRight(pressed) =>
receive(state = state.modify(_.cardinalDir.right).setTo(pressed))
case MovedDown(pressed) =>
receive(state = state.modify(_.cardinalDir.down).setTo(pressed))
}
case Tick(tpf) =>
val walkDir =
cm.getDirection(props.app.getCamera(), state.cardinalDir)
if (walkDir != ImVector3f.ZERO) {
val tmp = walkDir * 2f
props.app.enqueue(new Runnable {
override def run(): Unit = {
cm.move(props.movable, tmp)
}
})
}
Behaviors.same
// receive(state = state.modify(_.walkDirection).setTo(walkDir))
}
}
}

View File

@ -0,0 +1,63 @@
package wow.doge.mygame.state
import com.jme3.app.Application
import com.jme3.app.SimpleApplication
import com.jme3.app.state.AppState
import com.jme3.scene.Node
import com.jme3.app.state.BaseAppState
import com.simsilica.es.EntityData
import com.simsilica.es.base.DefaultEntityData
trait MyBaseState extends BaseAppState {
var simpleApp: SimpleApplication = null
implicit val entityData: EntityData = new DefaultEntityData()
def stateManager = simpleApp.getStateManager
def guiNode = simpleApp.getGuiNode
def rootNode = simpleApp.getRootNode
def assetManager = simpleApp.getAssetManager
def inputManager = simpleApp.getInputManager
def cam = simpleApp.getCamera
override protected final def initialize(app: Application): Unit = {
simpleApp = app.asInstanceOf[SimpleApplication]
init()
// stateManager.getState(classOf[FlyCamAppState]).getCamera().setMoveSpeed(100)
}
protected def init(): Unit
override protected def cleanup(app: Application): Unit = {
entityData.close()
}
protected def getOrCreateNode(parent: Node, id: String) =
Option(parent.getChild(id)).fold {
val node = new Node(id)
parent.attachChild(node)
node
}(node => node.asInstanceOf[Node])
protected def enableStates(classes: Class[_ <: AppState]*) =
setEnabledToStates(true, classes: _*)
protected def disableStates(classes: Class[_ <: AppState]*) =
setEnabledToStates(false, classes: _*)
protected def setEnabledToStates(
enabled: Boolean,
classes: Class[_ <: AppState]*
) = {
for (clazz <- classes) {
val st = stateManager.getState(clazz)
if (st != null) st.setEnabled(enabled)
}
}
protected def removeStates(classes: Class[_ <: AppState]*) = {
for (clazz <- classes) {
val st = stateManager.getState(clazz)
if (st != null) stateManager.detach(st)
}
}
}

View File

@ -0,0 +1,286 @@
package wow.doge.mygame.state
import scala.concurrent.duration.DurationInt
import com.jme3.input.InputManager
import com.jme3.input.KeyInput
import com.jme3.input.controls.ActionListener
import com.jme3.input.controls.KeyTrigger
import com.jme3.math.Vector3f
import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.Behavior
import akka.actor.typed.ActorRef
import com.jme3.scene.Geometry
import akka.actor.typed.scaladsl.TimerScheduler
import wow.doge.mygame.implicits._
class PlayerMovementState2(
movementActor: ActorRef[MovementActor.Command],
movementActorTimer: ActorRef[MovementActorTimer.Command],
imMovementActor: ActorRef[ImMovementActor.Command],
geom: Geometry
) extends MyBaseState
with ActionListener {
protected lazy val mat = MyMaterial(
assetManager = assetManager,
path = "Common/MatDefs/Misc/Unshaded.j3md"
)
override protected[state] def onEnable(): Unit = {}
override protected[state] def onDisable(): Unit = {}
override protected def init(): Unit = {
setupKeys(inputManager)
geom.setMaterial(mat)
rootNode.attachChild(geom)
// movementActorTimer ! MovementActorTimer.Start(geom, cam)
// movementActorTimer ! MovementActorTimer.Start
}
// def system =
// simpleApp.getStateManager.getState(classOf[ActorSystemState]).system
// def player = system.actorSelection("/user/player") //.resolveOne(1.second)
var lastDir: Vector3f = Vector3f.UNIT_X
override def update(tpf: Float) = {
// val direction = new Vector3f()
// direction.multLocal(10 * tpf)
// if (direction.length() > 0f) {
// // player ! PlayerMove(direction)
// lastDir = direction.normalize
// }
// if (shoot) {
// shoot = false
// // player ! Shoot(lastDir)
// }
// movementActor ! MovementActor.Tick(tpf, geom, cam)
imMovementActor ! ImMovementActor.Tick(tpf)
// movementActorTimer ! MovementActorTimer.Update(tpf)
}
def setupKeys(inputManager: InputManager) = {
inputManager
.withMapping(
"Left",
// new KeyTrigger(KeyInput.KEY_A),
new KeyTrigger(KeyInput.KEY_LEFT)
)
.withMapping(
"Right",
// new KeyTrigger(KeyInput.KEY_D),
new KeyTrigger(KeyInput.KEY_RIGHT)
)
inputManager.addMapping(
"Up",
// new KeyTrigger(KeyInput.KEY_W),
new KeyTrigger(KeyInput.KEY_UP)
)
inputManager.addMapping(
"Down",
// new KeyTrigger(KeyInput.KEY_S),
new KeyTrigger(KeyInput.KEY_DOWN)
)
inputManager.addMapping(
"Space",
new KeyTrigger(KeyInput.KEY_SPACE),
new KeyTrigger(KeyInput.KEY_H)
)
inputManager.addMapping(
"Reset",
new KeyTrigger(KeyInput.KEY_R),
new KeyTrigger(KeyInput.KEY_RETURN)
)
inputManager
.withListener(this, "Left")
.withListener(this, "Right")
inputManager.addListener(this, "Up")
inputManager.addListener(this, "Down")
inputManager.addListener(this, "Space")
inputManager.addListener(this, "Reset")
}
def onAction(binding: String, value: Boolean, tpf: Float) =
binding match {
case "Left" => imMovementActor ! ImMovementActor.MovedLeft(value)
case "Right" => imMovementActor ! ImMovementActor.MovedRight(value)
case "Up" => imMovementActor ! ImMovementActor.MovedUp(value)
case "Down" => imMovementActor ! ImMovementActor.MovedDown(value)
case "Space" =>
case _ =>
}
}
final case class CardinalDirection(
left: Boolean = false,
right: Boolean = false,
up: Boolean = false,
down: Boolean = false
)
object MovementActor {
sealed trait Command
// final case class Tick(tpf: Float, geom: Geometry, cam: Camera) extends Command
// final case class Tick(tpf: Float) extends Command
final case object Tick extends Command
sealed trait Movement extends Command
final case class MovedLeft(pressed: Boolean) extends Movement
final case class MovedUp(pressed: Boolean) extends Movement
final case class MovedRight(pressed: Boolean) extends Movement
final case class MovedDown(pressed: Boolean) extends Movement
final case class Props(app: com.jme3.app.Application, geom: Geometry)
/**
* Internal state of the actor
*
* @param cardinalDir Immutable, can be shared as is
* @param walkDirection scratch space to avoid allocations on every tick. Do not share outside the actor
*/
final case class State(
cardinalDir: CardinalDirection = CardinalDirection(),
walkDirection: Vector3f = Vector3f.UNIT_X
)
def apply(props: Props): Behavior[Command] =
Behaviors.setup(ctx => new MovementActor(ctx, props).receive(State()))
}
class MovementActor(
ctx: ActorContext[MovementActor.Command],
props: MovementActor.Props
) {
import MovementActor._
import com.softwaremill.quicklens._
def receive(state: MovementActor.State): Behavior[Command] =
Behaviors.receiveMessage { msg =>
msg match {
case m: Movement =>
m match {
case MovedLeft(pressed) =>
receive(state = state.modify(_.cardinalDir.left).setTo(pressed))
case MovedUp(pressed) =>
receive(state = state.modify(_.cardinalDir.up).setTo(pressed))
case MovedRight(pressed) =>
receive(state = state.modify(_.cardinalDir.right).setTo(pressed))
case MovedDown(pressed) =>
receive(state = state.modify(_.cardinalDir.down).setTo(pressed))
}
case Tick =>
val camDir =
props.app.getCamera.getDirection().clone().multLocal(0.6f)
val camLeft = props.app.getCamera.getLeft().clone().multLocal(0.4f)
val walkDir = state.walkDirection.set(0, 0, 0)
// val walkDir = new Vector3f
val dir = state.cardinalDir
if (dir.up) {
ctx.log.debug("up")
// ctx.log.debug(Thread.currentThread().getName())
// walkDir.addLocal(0, 0, -1)
walkDir += camDir
}
if (dir.left) {
ctx.log.debug("left")
// walkDir.addLocal(-1, 0, 0)
walkDir.addLocal(camLeft)
}
if (dir.right) {
ctx.log.debug("right")
// walkDir.addLocal(1, 0, 0)
walkDir.addLocal(camLeft.negateLocal())
}
if (dir.down) {
ctx.log.debug("down")
walkDir.addLocal(camDir.negateLocal())
// walkDir.addLocal(0, 0, 1)
}
// (dir.up, dir.down, dir.left, dir.right) match {
// case (true, false, true, false) =>
// case _ =>
// }
walkDir.multLocal(2f)
// walkDir.multLocal(100f)
// .multLocal(tpf)
// val v = props.geom.getLocalTranslation()
// props.geom.setLocalTranslation(
// (v += walkDir)
// )
props.app.enqueue(new Runnable {
override def run(): Unit = {
// geom.setLocalTranslation(walkDir)
val v = props.geom.getLocalTranslation()
props.geom.setLocalTranslation(
(v += walkDir)
)
}
})
Behaviors.same
// receive(state = state.modify(_.walkDirection).setTo(walkDir))
}
}
}
object MovementActorTimer {
sealed trait Command
final case object Start extends Command
final case object Update extends Command
private case object Send extends Command
case object TimerKey
final case class Props(
timers: TimerScheduler[MovementActorTimer.Command],
target: ActorRef[MovementActor.Command]
)
final case class State()
def apply(target: ActorRef[MovementActor.Command]) =
Behaviors.withTimers[Command] { timers =>
new MovementActorTimer(Props(timers, target)).idle()
}
}
class MovementActorTimer(
props: MovementActorTimer.Props
) {
import MovementActorTimer._
// import com.softwaremill.quicklens._
def idle(): Behavior[Command] =
Behaviors.receiveMessage { msg =>
msg match {
case Start =>
props.timers.startTimerWithFixedDelay(
Send,
10.millis
)
active()
case _ => Behaviors.unhandled
}
}
def active(): Behavior[Command] =
Behaviors.receiveMessage { msg =>
msg match {
case Update => active()
case Send =>
props.target ! MovementActor.Tick
Behaviors.same
case _ => Behaviors.unhandled
}
}
}

View File

@ -0,0 +1,206 @@
package wow.doge.mygame.state
import ammonite.runtime.Storage.Folder
import ammonite.main.Defaults
import ammonite.Main
import javax.script.ScriptEngine
import com.jme3.app.Application
import com.jme3.app.state.AppState
import akka.actor.typed.scaladsl.AbstractBehavior
import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.Behavior
import akka.actor.typed.ActorRef
import ammonite.util.Res.Success
import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.SpawnProtocol
class ScriptingEngineState(
sse: ScalaScriptingEngine,
kse: KotlinScriptingEngine
) extends MyBaseState {
// implicit val actorSystem =
// ActorSystem.create(MyActorSystem(), "rootActor")
// implicit val timeout: Timeout = Timeout(3.seconds)
// val scalaScriptActor: Future[ActorRef[ScalaScriptBehavior.Command]] =
// actorSystem.ask(
// SpawnProtocol.Spawn(
// ScalaScriptBehavior(sse.runner),
// name = "ScalaScriptCompilerActor",
// Props.empty,
// _
// )
// )
override protected def cleanup(app: Application): Unit = {
// actorSystem.terminate()
}
// override protected def initialize(app: Application): Unit = {
// super.initialize(app)
// }
override def init() = {
// Future {
// while (true) {
// // super.update(tpf)
// val (res, k) = sse.runner.runScript(
// // os.Path(getClass().getResource("/hello.sc").getPath),
// os.pwd / "src" / "main" / "resources" / "hello.sc",
// Seq.empty
// // Seq(("start", None))
// // Scripts.groupArgs(List(""))
// )
// val ms = res.map(_.asInstanceOf[GameScript])
// ms.map(_.start())
// val res2 = kse.engine.eval(
// os.read(os.pwd / "src" / "main" / "resources" / "hello.main.kts")
// )
// // val res2 = engine.eval(getClass().getResource("/hello.main.kts").getPath)
// // val invoker = engine.asInstanceOf[Invocable]
// // val scr = invoker.getInterface(res2, classOf[GameScript])
// val scr = res2.asInstanceOf[GameScript]
// scr.start()
// Thread.sleep(2000)
// }
// }
// Future {
// sse.runner
// .runScript(
// os.pwd / "src" / "main" / "resources" / "hello2.sc",
// Seq.empty
// )
// ._1
// .map(_.asInstanceOf[MyBaseState])
// .map(s => stateManager.attach(s))
// ()
// }
// val res = scalaScriptActor
// .map(
// _.ask(ref =>
// ScalaScriptBehavior.Compile(
// ref,
// os.pwd / "src" / "main" / "resources" / "hello2.sc"
// // os.Path(getClass().getResource("/hello2.sc").getPath)
// )
// )(Timeout(10.seconds), actorSystem.scheduler)
// )
// .flatten
// res.foreach(_ match {
// case AppStateResult(state) => {
// stateManager.attach(state)
// }
// case wow.doge.mygame.state.ScalaScriptBehavior.Error(reason) =>
// println("error")
// })
}
override def update(tpf: Float): Unit = {}
override protected def onEnable(): Unit = {}
override protected def onDisable(): Unit = {}
}
object MyActorSystem {
def apply(): Behavior[SpawnProtocol.Command] =
Behaviors.setup { context =>
// Start initial tasks
// context.spawn(...)
SpawnProtocol()
}
}
class ScalaScriptingEngine(
val runner: Main = ammonite
.Main(
// predefCode = """
// import coursierapi.MavenRepository
// interp.repositories.update(
// interp.repositories() ::: List(
// MavenRepository.of("file://home/rohan/.m2/repository")
// )
// )
// @
// """,
defaultPredef = false,
storageBackend = new Folder(Defaults.ammoniteHome, isRepl = false)
)
) {}
class KotlinScriptingEngine(val engine: ScriptEngine) {
// val manager = new ScriptEngineManager()
// val engine = manager.getEngineByExtension("main.kts")
}
object ScalaScriptBehavior {
sealed trait Result
final case class AppStateResult(state: AppState) extends Result
final case class Error(reason: String) extends Result
sealed trait Command
final case class Compile(sender: ActorRef[Result], path: os.Path)
extends Command
// final case class CompileScripts(sender: ActorRef[Result], paths: os.Path*)
// extends Command
def apply(
runner: Main = ammonite
.Main(
storageBackend = new Folder(
// os.pwd / "target"
Defaults.ammoniteHome,
isRepl = false
)
)
) =
Behaviors.setup(ctx => new ScalaScriptActor(runner, ctx))
private class ScalaScriptActor(
val runner: Main,
context: ActorContext[Command]
) extends AbstractBehavior[Command](context) {
override def onMessage(msg: Command): Behavior[Command] = {
msg match {
case Compile(sender, path) =>
context.log.debug(s"Received $path")
val res = getScript(path)
println(res)
sender ! res
Behaviors.same
// case CompileScripts(sender, paths) =>
}
}
def getScript(path: os.Path): Result = {
runner
.runScript(
path,
Seq.empty
)
._1 match {
case ammonite.util.Res.Exception(t, msg) => Error(msg)
case Success(obj) =>
obj match {
case s: MyBaseState => AppStateResult(s)
case _ => Error("Unknown script type")
// AppStateResult(s.asInstanceOf[AppState])
}
case _ => Error("Failed to run script")
}
}
}
}

View File

@ -0,0 +1,71 @@
package wow.doge.mygame.state
import com.jme3.app.Application
import wow.doge.mygame.implicits._
import wow.doge.mygame.components.TestComponent
import com.jme3.scene.shape.Box
import com.jme3.scene.Geometry
import com.jme3.material.Material
import com.jme3.math.ColorRGBA
import com.jme3.asset.AssetManager
import com.jme3.math.Vector3f
class TestAppState(
// private var _entity: Option[EntityData] = Some(new DefaultEntityData())
) extends MyBaseState {
var geom: Option[Geometry] = None
// def entity = _entity
// override def initialize(app: Application): Unit = {
// super.initialize(app)
// }
override def init() = {
entityData
.createEntity()
.withComponents(TestComponent())
// entityData.setComponents(x, TestComponent())
val es = entityData.getEntities(classOf[TestComponent])
println(es)
val b = new Box(1, 1, 1)
geom = Some(new Geometry("Box", b))
val mat = MyMaterial(
assetManager = assetManager,
path = "Common/MatDefs/Misc/Unshaded.j3md"
)
geom.foreach(e => {
e.setMaterial(mat)
rootNode.attachChild(e)
})
}
override def update(tpf: Float) = {
geom.foreach(_.rotate(0, 0.5f * tpf, 0))
geom.foreach(_.move(new Vector3f(0, 1 * tpf, 0)))
}
override def cleanup(app: Application): Unit = {
// _entity.map(_.close())
// _entity = None
}
override def onEnable(): Unit = {}
override def onDisable(): Unit = {}
}
object MyMaterial {
def apply(
color: String = "Color",
colorType: com.jme3.math.ColorRGBA = ColorRGBA.Blue,
assetManager: AssetManager,
path: String
): Material = {
val mat =
new Material(assetManager, path)
mat.setColor(color, colorType)
mat
}
}