Testing out JmonkeyEngine to make a game in Scala with Akka Actors within a pure FP layer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
4.0 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. package wow.doge.mygame.state
  2. import akka.actor.typed.scaladsl.Behaviors
  3. import ammonite.Main
  4. import akka.actor.typed.ActorRef
  5. import ammonite.runtime.Storage.Folder
  6. import ammonite.main.Defaults
  7. import akka.actor.typed.Behavior
  8. import akka.actor.typed.scaladsl.ActorContext
  9. import ammonite.util.Res.Success
  10. import javax.script.ScriptEngine
  11. import javax.script.ScriptEngineManager
  12. import groovy.util.GroovyScriptEngine
  13. import cats.implicits._
  14. object ScriptActor {
  15. type Kotlin
  16. type MyScriptEngine[T] = ScriptEngine
  17. type KotlinScriptEngine = MyScriptEngine[Kotlin]
  18. final case class Error(reason: String)
  19. sealed trait Command
  20. final case class CompileAny(
  21. path: os.Path,
  22. result: ActorRef[Either[Error, Any]]
  23. ) extends Command
  24. def defaultScalaRunner() =
  25. ammonite
  26. .Main(
  27. storageBackend = new Folder(
  28. // os.pwd / "target"
  29. Defaults.ammoniteHome,
  30. isRepl = false
  31. )
  32. )
  33. def defaultKotlinRunner(): KotlinScriptEngine = {
  34. val manager = new ScriptEngineManager()
  35. val engine = manager.getEngineByExtension("main.kts")
  36. engine
  37. }
  38. def defaultGroovyRunner(): GroovyScriptEngine =
  39. new GroovyScriptEngine(os.pwd.toString())
  40. def apply(
  41. scalaRunner: Main = defaultScalaRunner(),
  42. kotlinRunner: KotlinScriptEngine = defaultKotlinRunner(),
  43. groovyRunner: GroovyScriptEngine = defaultGroovyRunner()
  44. // parent: ActorRef[ScriptStoringActor.Command]
  45. ): Behavior[ScriptActor.Command] =
  46. Behaviors.setup(ctx =>
  47. new ScriptActor(
  48. scalaRunner,
  49. kotlinRunner,
  50. groovyRunner,
  51. ctx
  52. ).receiveMessage
  53. )
  54. sealed trait ScriptType
  55. case object ScalaType extends ScriptType
  56. case object KotlinType extends ScriptType
  57. case object GroovyType extends ScriptType
  58. def determineScriptType(path: os.Path): Either[Error, ScriptType] =
  59. path.toString match {
  60. case s if s.endsWith(".sc") => Right(ScalaType)
  61. case s if s.endsWith(".main.kts") => Right(KotlinType)
  62. case s if s.endsWith(".groovy") => Right(GroovyType)
  63. case _ => Left(Error("Unknown script type"))
  64. }
  65. def runScala(path: os.Path, scalaRunner: ammonite.Main): Either[Error, Any] =
  66. scalaRunner
  67. .runScript(
  68. path,
  69. Seq.empty
  70. )
  71. ._1 match {
  72. case ammonite.util.Res.Exception(t, msg) => Left(Error(msg))
  73. case Success(obj) => Right(obj)
  74. case _ => Left(Error("Failed to run script"))
  75. }
  76. def runKotlin(
  77. path: os.Path,
  78. kotlinRunner: KotlinScriptEngine
  79. ): Either[Error, Any] =
  80. Either
  81. .catchNonFatal(kotlinRunner.eval(os.read(path)))
  82. .leftMap(t => Error(t.getMessage()))
  83. def runGroovy(
  84. path: os.Path,
  85. groovyRunner: GroovyScriptEngine
  86. ): Either[Error, Any] =
  87. Either
  88. .catchNonFatal(groovyRunner.run(path.relativeTo(os.pwd).toString(), ""))
  89. .leftMap(t => Error(t.getMessage()))
  90. def ensureReturnedObjectNotNull(scriptObject: Any): Either[Error, Any] =
  91. Either.fromOption(Option(scriptObject), Error("unknown object"))
  92. }
  93. class ScriptActor(
  94. val scalaRunner: ammonite.Main,
  95. val kotlinRunner: ScriptActor.KotlinScriptEngine,
  96. val groovyRunner: GroovyScriptEngine,
  97. context: ActorContext[ScriptActor.Command]
  98. ) {
  99. import ScriptActor._
  100. def receiveMessage: Behavior[Command] =
  101. Behaviors.receiveMessage { msg =>
  102. msg match {
  103. case CompileAny(path, requester) =>
  104. context.log.debug(s"Received $path")
  105. val res = getScript(path)
  106. context.log.debug(s"result = $res")
  107. requester ! res
  108. Behaviors.same
  109. }
  110. }
  111. def getScript(path: os.Path): Either[Error, Any] =
  112. determineScriptType(path) match {
  113. case Right(ScalaType) =>
  114. runScala(path, scalaRunner).flatMap(ensureReturnedObjectNotNull)
  115. case Right(KotlinType) =>
  116. runKotlin(path, kotlinRunner).flatMap(ensureReturnedObjectNotNull)
  117. case Right(GroovyType) =>
  118. runGroovy(path, groovyRunner).flatMap(ensureReturnedObjectNotNull)
  119. case l @ Left(err) => l
  120. }
  121. }