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.
 
 

157 lines
4.5 KiB

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