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.
 
 

164 lines
4.9 KiB

package wow.doge.mygame.subsystems.moddingsystem
import java.io.FileNotFoundException
import java.nio.file.NoSuchFileException
import scala.collection.View
import scala.collection.immutable.ArraySeq
import scala.util.Try
import cats.implicits._
import io.circe._
import io.circe.generic.JsonCodec
import io.circe.generic.semiauto._
import io.circe.parser._
import monix.bio.IO
import monix.bio.UIO
import monix.reactive.Consumer
import monix.reactive.Observable
import wow.doge.mygame.utils.IOUtils
@JsonCodec
final case class Test1(hello1: String, hello2: String)
@JsonCodec
final case class Test2(hello1: String)
final case class Plugin(name: String, priority: Int)
object Plugin {
implicit val pluginFormat: Decoder[Plugin] = deriveDecoder
}
object ModdingSystem {
sealed trait Error
final case class CouldNotDecode(cause: String) extends Error
final case class ParseFailure(cause: String) extends Error
final case class FileNotFound(fileName: String) extends Error
case object GenericError extends Error
def readPluginsList(dir: os.Path): Try[Either[Error, ArraySeq[Plugin]]] =
Try(
parse(os.read(dir / "plugins.json"))
.map(
_.as[ArraySeq[Plugin]]
.leftMap(e => CouldNotDecode(e.getMessage()))
)
.leftMap((e: ParsingFailure) => ParseFailure(e.message))
.flatten
)
// .toValidated
def findPluginFiles(dir: os.Path): View[os.Path] =
os.list(dir)
.view
.filter(f => f.ext == "json" && f.baseName.endsWith("plugin"))
def findAndReadPluginFiles(
dir: os.Path,
plugins: ArraySeq[Plugin]
): (View[(Plugin, Error)], View[(Plugin, String)]) =
plugins
.sortBy(_.priority)
.view
.map(p =>
p ->
Either
.catchNonFatal {
val path = dir / os.RelPath(p.name + ".plugin.json")
os.read(path)
}
.leftMap {
case _: FileNotFoundException =>
FileNotFound(p.name)
case _: NoSuchFileException => FileNotFound(p.name)
case e => GenericError
}
)
.partitionMap {
case (p, either) =>
either match {
case Left(value) => Left(p -> value)
case Right(value) => Right(p -> value)
}
}
def readPluginFiles(filePaths: View[os.Path]) =
filePaths.map(path => os.read(path))
def parsePluginFiles(files: View[(Plugin, String)]) =
files
.map {
case (p, s) => p -> parse(s)
}
.partitionMap {
case (p, Left(value)) => Left(p -> value)
case (p, Right(value)) => Right(p -> value)
}
def foldMerge(iterable: Iterable[Json]) =
iterable.foldLeft(Json.fromString("empty")) {
case (json, io.circe.Json.Null) => json //ignore null values
case (json, value) => json.deepMerge(value)
}
def mergePluginData(plugins: View[(Plugin, Json)]) =
foldMerge(plugins.map {
case (p, json) => json
})
def mergePluginDataConsumer =
Consumer.foldLeft[Json, Json](Json.fromString("empty")) {
case (json, io.circe.Json.Null) => json
case (json, that) => json.deepMerge(that)
}
def loadBalancedPluginDataMerger =
Consumer
.loadBalance(parallelism = 2, mergePluginDataConsumer)
.map(foldMerge)
// def test =
// for {
// filePaths <- Task(findPluginFiles(os.pwd))
// files <- Task(readPluginFiles(filePaths))
// (failures, successes) <- Task(parsePluginFiles(files))
// merged <- Task(mergePluginData(successes))
// _ <- Task {
// println(s"Successes = ${successes.to(Seq)}")
// println(s"Failure = ${failures.to(Seq)}")
// println(s"Merged = $merged")
// }
// } yield ()
def test(wd: os.Path = os.pwd) =
for {
plugins <- IO.fromTryEither(readPluginsList(wd))
(readFailures, readSuccesses) <- UIO(findAndReadPluginFiles(wd, plugins))
(parseFailures, parseSuccesses) <- UIO(parsePluginFiles(readSuccesses))
// res <- UIO(mergePluginData(parseSuccesses))
res <-
IOUtils
.toIO(
Observable
.fromIterable(parseSuccesses)
.map { case (p, json) => json }
.consumeWith(loadBalancedPluginDataMerger)
)
.hideErrors
_ <- UIO {
println(s"Read Successes = ${readSuccesses.to(Seq)}")
println(s"Read Failures = ${readFailures.to(Seq)}")
println(s"Parse Successes = ${parseSuccesses.to(Seq)}")
println(s"Parse Failures = ${parseFailures.to(Seq)}")
println(show"Merged = $res")
}
} yield ()
// monix.eval.Task.deferAction(implicit s =>
// ModdingSystem
// .test()
// .leftMap(e => new Throwable(e.toString()))
// .to[monix.eval.Task]
// )
// def test3(wd: os.Path = os.pwd) = {
// (readPluginsList(os.pwd).toValidatedNec)
// }
}