forked from nova/jmonkey-test
Rohan Sircar
4 years ago
41 changed files with 1492 additions and 411 deletions
-
4.jvmopts
-
9build.sbt
-
3launch.sh
-
BINlib/jme3-testdata.jar
-
4plugins.json
-
1project/plugins.sbt
-
3src/main/resources/hello.groovy
-
1src/main/resources/hello2.sc
-
59src/main/scala/org/slf4j/impl/StaticLoggerBuilder.scala
-
204src/main/scala/wow/doge/mygame/Main.scala
-
87src/main/scala/wow/doge/mygame/MainModule.scala
-
20src/main/scala/wow/doge/mygame/executors/ExecutorsModule.scala
-
11src/main/scala/wow/doge/mygame/executors/GUIExecutor.scala
-
6src/main/scala/wow/doge/mygame/executors/Schedulers.scala
-
99src/main/scala/wow/doge/mygame/game/GameApp.scala
-
195src/main/scala/wow/doge/mygame/game/GameAppActor.scala
-
25src/main/scala/wow/doge/mygame/game/GameModule.scala
-
13src/main/scala/wow/doge/mygame/game/GameSystemsInitializer.scala
-
84src/main/scala/wow/doge/mygame/game/TestActor.scala
-
2src/main/scala/wow/doge/mygame/game/appstates/EntityDataState.java
-
24src/main/scala/wow/doge/mygame/game/appstates/MovementActor.scala
-
14src/main/scala/wow/doge/mygame/game/appstates/MyBaseState.scala
-
117src/main/scala/wow/doge/mygame/game/appstates/PlayerMovementState.scala
-
8src/main/scala/wow/doge/mygame/game/appstates/ScriptingEngineState.scala
-
16src/main/scala/wow/doge/mygame/game/appstates/TestAppState.scala
-
0src/main/scala/wow/doge/mygame/game/components/Position.scala
-
0src/main/scala/wow/doge/mygame/game/components/Tag.scala
-
0src/main/scala/wow/doge/mygame/game/components/Test.java
-
0src/main/scala/wow/doge/mygame/game/components/TestComponent.scala
-
94src/main/scala/wow/doge/mygame/game/nodes/PlayerNode.scala
-
367src/main/scala/wow/doge/mygame/implicits/package.scala
-
2src/main/scala/wow/doge/mygame/math/ImVector3f.scala
-
0src/main/scala/wow/doge/mygame/subsystems/events/EventBus.scala
-
0src/main/scala/wow/doge/mygame/subsystems/events/Events.scala
-
0src/main/scala/wow/doge/mygame/subsystems/events/EventsModule.scala
-
142src/main/scala/wow/doge/mygame/subsystems/moddingsystem/ModdingSystem.scala
-
111src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptActor.scala
-
123src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptCachingActor.scala
-
53src/main/scala/wow/doge/mygame/utils/JFXConsoleStream.scala
-
1test.plugin.json
-
1test2.plugin.json
@ -0,0 +1,4 @@ |
|||
-Xms2G |
|||
-Xmx2G |
|||
-XX:+UseG1GC |
|||
-XX:MaxGCPauseMillis=50 |
@ -0,0 +1,3 @@ |
|||
# sdk use java 20.2.0.r11-grl |
|||
# java -J-Xms2G -J-Xmx2G -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=50 -jar target/scala-2.13/mygame-assembly-1.0-SNAPSHOT.jar |
|||
java -Xms2G -Xmx2G -XX:+UseG1GC -XX:MaxGCPauseMillis=50 -jar target/scala-2.13/mygame-assembly-1.0-SNAPSHOT.jar |
@ -0,0 +1,4 @@ |
|||
[ |
|||
{ "name": "test", "priority": 1 }, |
|||
{ "name": "test2", "priority": 2 } |
|||
] |
@ -1,2 +1,3 @@ |
|||
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.15.0") |
|||
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.23") |
|||
addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1") |
@ -0,0 +1,3 @@ |
|||
println "hello" |
|||
|
|||
this |
@ -0,0 +1,59 @@ |
|||
package org.slf4j.impl |
|||
|
|||
import cats.effect.{ContextShift, Clock, Effect, IO, Timer} |
|||
import io.odin._ |
|||
import io.odin.slf4j.OdinLoggerBinder |
|||
import cats.implicits._ |
|||
|
|||
import scala.concurrent.ExecutionContext |
|||
import _root_.monix.execution.Scheduler |
|||
import cats.arrow.FunctionK |
|||
import _root_.monix.execution.Scheduler.Implicits.global |
|||
import io.odin.syntax._ |
|||
import scala.concurrent.duration._ |
|||
|
|||
//effect type should be specified inbefore |
|||
//log line will be recorded right after the call with no suspension |
|||
class StaticLoggerBinder extends OdinLoggerBinder[IO] { |
|||
|
|||
val ec: ExecutionContext = Scheduler.global |
|||
implicit val timer: Timer[IO] = IO.timer(ec) |
|||
implicit val clock: Clock[IO] = timer.clock |
|||
implicit val cs: ContextShift[IO] = IO.contextShift(ec) |
|||
implicit val F: Effect[IO] = IO.ioEffect |
|||
|
|||
val monixToCats = new FunctionK[_root_.monix.bio.Task, IO] { |
|||
def apply[A](fa: _root_.monix.bio.Task[A]): IO[A] = fa.to[IO] |
|||
} |
|||
|
|||
val (fLogger, release) = |
|||
// MainModule.DefaultFileLogger.mapK(monixToCats).allocated.unsafeRunSync() |
|||
fileLogger[IO]( |
|||
"log2.log" |
|||
).withAsync(timeWindow = 1.seconds).allocated.unsafeRunSync() |
|||
// Runtime |
|||
// .getRuntime() |
|||
// .addShutdownHook(new Thread { |
|||
// release.unsafeRunSync() |
|||
// }) |
|||
scala.sys.addShutdownHook(release.unsafeRunSync()) |
|||
val loggers: PartialFunction[String, Logger[IO]] = { |
|||
case "some.external.package.SpecificClass" => |
|||
consoleLogger[IO](minLevel = Level.Warn) //disable noisy external logs |
|||
case asyncHttpClient |
|||
if asyncHttpClient.startsWith("org.asynchttpclient.netty") => |
|||
consoleLogger[IO](minLevel = Level.Warn) |
|||
case s if s.startsWith("akka.actor") || s.startsWith("wow.doge.mygame") => |
|||
consoleLogger[IO]() |+| fLogger |
|||
case _ => //if wildcard case isn't provided, default logger is no-op |
|||
consoleLogger[IO]() |
|||
} |
|||
} |
|||
|
|||
object StaticLoggerBinder extends StaticLoggerBinder { |
|||
|
|||
var REQUESTED_API_VERSION: String = "1.7" |
|||
|
|||
def getSingleton: StaticLoggerBinder = this |
|||
|
|||
} |
@ -1,127 +1,105 @@ |
|||
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) |
|||
import monix.bio.Task |
|||
import cats.effect.Resource |
|||
import io.odin.syntax._ |
|||
|
|||
// 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") |
|||
// import io.odin.monix._ |
|||
import cats.effect.ExitCode |
|||
import cats.implicits._ |
|||
import com.softwaremill.macwire._ |
|||
import scala.concurrent.duration._ |
|||
import monix.bio.BIOApp |
|||
import monix.bio.UIO |
|||
import monix.bio.IO |
|||
import io.odin._ |
|||
import wow.doge.mygame.executors.JMERunner |
|||
import com.jme3.bullet.BulletAppState |
|||
import wow.doge.mygame.implicits._ |
|||
|
|||
testActor ! TestActor.Test |
|||
SpawnProtocol() |
|||
} |
|||
} |
|||
// import wow.doge.mygame.implicits._ |
|||
|
|||
object TestActor { |
|||
sealed trait Command |
|||
case object Test extends Command |
|||
private case object Done extends Command |
|||
// sealed trait Result |
|||
// case object Done extends Result |
|||
// object Main extends App { |
|||
// import java.util.logging.{Logger, Level} |
|||
// Logger.getLogger("").setLevel(Level.SEVERE) |
|||
|
|||
import scala.concurrent.duration._ |
|||
implicit val timeout = Timeout(15.seconds) |
|||
// implicit val scheduler = |
|||
// // 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) |
|||
// } |
|||
|
|||
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) |
|||
object Main extends BIOApp with MainModule { |
|||
import java.util.logging.{Logger => JLogger, Level} |
|||
JLogger.getLogger("").setLevel(Level.SEVERE) |
|||
|
|||
// 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 |
|||
// } |
|||
def run(args: List[String]): UIO[ExitCode] = { |
|||
|
|||
Behaviors.same |
|||
case Done => Behaviors.same |
|||
} |
|||
lazy val appResource = for { |
|||
logger <- |
|||
consoleLogger().withAsync(timeWindow = 1.seconds) |+| fileLogger( |
|||
"log.log" |
|||
).withAsync(timeWindow = 1.seconds) |
|||
jmeScheduler <- jMESchedulerResource |
|||
// consoleTextArea <- Resource.liftF(Task(new TextArea())) |
|||
// consoleStream <- wireWith(JFXConsoleStream.textAreaStream _) |
|||
gameApp <- { |
|||
new BulletAppState() |
|||
// bas.setThreadingType(Thr) |
|||
gameAppResource(new StatsAppState()) |
|||
} |
|||
_ <- Resource.liftF(IO(JMERunner.runner = gameApp)) |
|||
actorSystem <- wireWith(actorSystemResource _) |
|||
// _ <- Resource.liftF( |
|||
// Task(gameApp.start()).asyncBoundary |
|||
// .executeOn(Scheduler(JMEExecutorService)) |
|||
// ) |
|||
|
|||
// SpawnProtocol() |
|||
// Behaviors.same |
|||
_ <- Resource.liftF(gameApp.enqueueT(actorSystem ! RootActor.Start)) |
|||
_ <- Resource.liftF { |
|||
IO(gameApp.start()) |
|||
.executeOn(jmeScheduler) |
|||
} |
|||
} |
|||
// (_ => IO(gameApp.stop(() => actorSystem ! RootActor.Stop))) |
|||
} yield () |
|||
|
|||
// Console.withOut( |
|||
// new JFXConsoleStream( |
|||
// new scalafx.scene.control.TextArea(), |
|||
// new ByteArrayOutputStream(35) |
|||
// ) |
|||
// )(()) |
|||
appResource |
|||
.use(_ => |
|||
// Task(gameApp.start()) |
|||
// .executeOn(Scheduler(JMEExecutorService)) |
|||
// .asyncBoundary |
|||
// Task.never |
|||
Task.unit |
|||
// >> |
|||
|
|||
// .executeOn(Scheduler(JMEExecutorService)) |
|||
) |
|||
.onErrorHandle(_.printStackTrace()) |
|||
.as(ExitCode.Success) |
|||
} |
|||
} |
@ -0,0 +1,87 @@ |
|||
package wow.doge.mygame |
|||
import akka.actor.typed.scaladsl.Behaviors |
|||
import wow.doge.mygame.game.GameApp |
|||
import akka.actor.typed.Behavior |
|||
import wow.doge.mygame.game.GameAppActor |
|||
import cats.effect.Resource |
|||
import akka.actor.typed.ActorSystem |
|||
import monix.bio.Task |
|||
import wow.doge.mygame.game.GameModule |
|||
import io.odin._ |
|||
import io.odin.syntax._ |
|||
import wow.doge.mygame.executors.ExecutorsModule |
|||
import akka.actor.typed.scaladsl.ActorContext |
|||
import wow.doge.mygame.executors.Schedulers |
|||
import com.softwaremill.macwire._ |
|||
|
|||
trait MainModule extends GameModule with ExecutorsModule { |
|||
def actorSystemResource( |
|||
logger: Logger[Task], |
|||
app: GameApp, |
|||
schedulers: Schedulers |
|||
): Resource[Task, ActorSystem[RootActor.Command]] = |
|||
Resource.make(logger.info("Creating Actor System") >> Task { |
|||
ActorSystem(RootActor(app, schedulers), name = "GameActorSystem") |
|||
})(sys => |
|||
logger.info("Shutting down actor system") >> Task( |
|||
sys.terminate() |
|||
) |
|||
) |
|||
} |
|||
|
|||
object MainModule { |
|||
|
|||
// import cats.implicits._ |
|||
import scala.concurrent.duration._ |
|||
val DefaultFileLogger: Resource[Task, Logger[Task]] = |
|||
fileLogger[Task]( |
|||
"log.log" |
|||
).withAsync(timeWindow = 1.seconds) |
|||
} |
|||
|
|||
object RootActor { |
|||
sealed trait Command |
|||
final case object Start extends Command |
|||
final case object Stop extends Command |
|||
|
|||
final case class State(initialized: Boolean = false) |
|||
def apply( |
|||
app: GameApp, |
|||
schedulers: Schedulers, |
|||
state: State = State() |
|||
): Behavior[Command] = |
|||
Behaviors.setup { ctx => |
|||
ctx.log.info("Hello from root actor") |
|||
wire[RootActor].receive(state) |
|||
} |
|||
} |
|||
|
|||
class RootActor( |
|||
ctx: ActorContext[RootActor.Command], |
|||
app: GameApp, |
|||
schedulers: Schedulers |
|||
) { |
|||
import RootActor._ |
|||
def receive(state: State): Behavior[Command] = |
|||
Behaviors.receiveMessage(msg => |
|||
msg match { |
|||
case Start => |
|||
if (!state.initialized) { |
|||
ctx.log.info("Starting GameAppActor") |
|||
val _ = ctx.spawn( |
|||
wireWith(GameAppActor.apply _), |
|||
"gameAppActor" |
|||
// DispatcherSelector.fromConfig("jme-dispatcher") |
|||
) |
|||
receive(state.copy(initialized = true)) |
|||
} else { |
|||
ctx.log.warn("Already Initialized") |
|||
Behaviors.same |
|||
} |
|||
case Stop => |
|||
ctx.log.info("Stopping") |
|||
Behaviors.stopped |
|||
|
|||
} |
|||
) |
|||
} |
@ -1,5 +1,23 @@ |
|||
package wow.doge.mygame.executors |
|||
|
|||
import monix.bio.Task |
|||
import cats.effect.Resource |
|||
import monix.execution.Scheduler |
|||
|
|||
trait ExecutorsModule { |
|||
lazy val schedulers = new Schedulers() |
|||
lazy val schedulers = Schedulers() |
|||
// Resource.make( |
|||
// Task( |
|||
// new Schedulers( |
|||
// jme = Scheduler |
|||
// .singleThread(name = "JME-Application-Thread", daemonic = false) |
|||
// ) |
|||
// ) |
|||
// )(s => Task(s.jme.shutdown())) |
|||
lazy val jMESchedulerResource = Resource.make( |
|||
Task( |
|||
Scheduler |
|||
.singleThread(name = "JME-Application-Thread", daemonic = false) |
|||
) |
|||
)(e => Task(e.shutdown())) |
|||
} |
@ -0,0 +1,25 @@ |
|||
package wow.doge.mygame.game |
|||
|
|||
import cats.effect.Resource |
|||
import com.jme3.app.state.AppState |
|||
import com.jme3.system.AppSettings |
|||
import monix.bio.Task |
|||
// import wow.doge.mygame.executors.JMERunner |
|||
|
|||
trait GameModule { |
|||
|
|||
def gameAppResource(appStates: AppState*): Resource[Task, GameApp] = |
|||
Resource.liftF { |
|||
for { |
|||
app <- Task(new GameApp(appStates: _*)) |
|||
_ <- Task { |
|||
val settings = new AppSettings(true) |
|||
// settings.setVSync(true) |
|||
settings.setFrameRate(144) |
|||
app.setSettings(settings) |
|||
// JMERunner.runner = app |
|||
app |
|||
} |
|||
} yield (app) |
|||
} |
|||
} |
@ -0,0 +1,13 @@ |
|||
package wow.doge.mygame.game |
|||
|
|||
import wow.doge.mygame.state.MyBaseState |
|||
|
|||
class GameSystemsInitializer extends MyBaseState { |
|||
|
|||
override protected def onEnable(): Unit = {} |
|||
|
|||
override protected def onDisable(): Unit = {} |
|||
|
|||
override protected def init(): Unit = {} |
|||
override def stop(): Unit = {} |
|||
} |
@ -0,0 +1,84 @@ |
|||
package wow.doge.mygame.game |
|||
|
|||
import akka.actor.typed.Behavior |
|||
import akka.actor.typed.scaladsl.Behaviors |
|||
import akka.util.Timeout |
|||
import wow.doge.mygame.scriptsystem.ScriptCachingActor |
|||
|
|||
object TestActor { |
|||
sealed trait Command |
|||
case object Test extends Command |
|||
private case object Done extends Command |
|||
|
|||
import scala.concurrent.duration._ |
|||
implicit val timeout = Timeout(15.seconds) |
|||
|
|||
def apply( |
|||
// scriptCacheBehavior: Behavior[ScriptCachingActor.Command] |
|||
): Behavior[Command] = |
|||
Behaviors.setup { ctx => |
|||
ctx.spawn(ScriptCachingActor(), "scriptCacher") |
|||
Behaviors.receiveMessage { msg => |
|||
msg match { |
|||
case Test => |
|||
Behaviors.same |
|||
case Done => Behaviors.same |
|||
} |
|||
} |
|||
} |
|||
def testKotlinScriptCompilation() = { |
|||
// 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 |
|||
// } |
|||
} |
|||
|
|||
def testTaskWrapper() = { |
|||
// val x = scriptStorer |
|||
// .askT( |
|||
// ScriptStoringActor |
|||
// .Get(os.pwd / "src" / "main" / "resources" / "hello2.sc", _) |
|||
// )(timeout, ctx.system.scheduler) |
|||
} |
|||
|
|||
def testScriptCaching() = { |
|||
// 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 |
|||
// } |
|||
} |
|||
} |
@ -1,4 +1,4 @@ |
|||
package wow.doge.mygame.state; |
|||
package wow.doge.mygame.game.appstates; |
|||
|
|||
import com.jme3.app.state.AbstractAppState; |
|||
import com.simsilica.es.EntityData; |
@ -0,0 +1,94 @@ |
|||
package wow.doge.mygame.game.nodes |
|||
|
|||
import com.jme3.scene.Node |
|||
import com.jme3.scene.CameraNode |
|||
import com.jme3.scene.Geometry |
|||
import com.jme3.renderer.Camera |
|||
import wow.doge.mygame.implicits._ |
|||
import com.jme3.asset.AssetManager |
|||
import wow.doge.mygame.state.MyMaterial |
|||
import com.jme3.math.Vector3f |
|||
import com.jme3.scene.control.CameraControl.ControlDirection |
|||
import com.jme3.syntax._ |
|||
import com.jme3.scene.shape.Box |
|||
|
|||
// class PlayerNode(val name: String) extends Node(name) {} |
|||
object PlayerNode { |
|||
def defaultMesh() = { |
|||
lazy val b = new Box(1, 1, 1) |
|||
lazy val geom = new Geometry("playerMesh", b) |
|||
geom |
|||
} |
|||
def defaultTexture(assetManager: AssetManager) = |
|||
MyMaterial( |
|||
assetManager = assetManager, |
|||
path = os.rel / "Common" / "MatDefs" / "Misc" / "Unshaded.j3md" |
|||
) |
|||
|
|||
def apply( |
|||
modelPath: os.RelPath, |
|||
cam: Camera |
|||
)(assetManager: AssetManager) = { |
|||
lazy val playerNode = new Node("PlayerNode") |
|||
lazy val camNode = new CameraNode("CameraNode", cam) |
|||
|
|||
// lazy val camNode = new CameraNode("CameraNode", simpleApp.getCamera()) |
|||
// camNode.setCamera(simpleApp.getCamera()) |
|||
|
|||
val playerModel: Node = |
|||
assetManager.loadModel(modelPath).asInstanceOf[Node] |
|||
discard { |
|||
playerNode |
|||
.child(camNode) |
|||
.child(playerModel) |
|||
// playerNode.children(Seq(camNode, geom)) |
|||
} |
|||
|
|||
{ |
|||
camNode.setControlDir(ControlDirection.SpatialToCamera) |
|||
camNode.setLocalTranslation( |
|||
new Vector3f(0, 1.5f, 10) |
|||
) |
|||
camNode.lookAt(playerNode.getLocalTranslation(), Vector3f.UNIT_Y) |
|||
} |
|||
|
|||
playerNode |
|||
} |
|||
def apply( |
|||
mesh: Geometry = defaultMesh(), |
|||
texturePath: os.RelPath = |
|||
os.rel / "Common" / "MatDefs" / "Misc" / "Unshaded.j3md", |
|||
cam: Camera |
|||
)(assetManager: AssetManager): Node = { |
|||
|
|||
lazy val playerNode = new Node("PlayerNode") |
|||
lazy val camNode = new CameraNode("CameraNode", cam) |
|||
|
|||
{ |
|||
val mat = MyMaterial( |
|||
assetManager = assetManager, |
|||
path = texturePath |
|||
) |
|||
mesh.setMaterial(mat) |
|||
} |
|||
|
|||
// lazy val camNode = new CameraNode("CameraNode", simpleApp.getCamera()) |
|||
// camNode.setCamera(simpleApp.getCamera()) |
|||
discard { |
|||
playerNode |
|||
.child(camNode) |
|||
.child(mesh) |
|||
// playerNode.children(Seq(camNode, geom)) |
|||
} |
|||
|
|||
{ |
|||
camNode.setControlDir(ControlDirection.SpatialToCamera) |
|||
camNode.setLocalTranslation( |
|||
new Vector3f(0, 1.5f, 10) |
|||
) |
|||
camNode.lookAt(playerNode.getLocalTranslation(), Vector3f.UNIT_Y) |
|||
} |
|||
|
|||
playerNode |
|||
} |
|||
} |
@ -0,0 +1,142 @@ |
|||
package wow.doge.mygame.subsystems.moddingsystem |
|||
import java.io.FileNotFoundException |
|||
|
|||
import scala.collection.View |
|||
import scala.collection.immutable.ArraySeq |
|||
import scala.util.Try |
|||
|
|||
import cats.implicits._ |
|||
import io.circe._ |
|||
import io.circe.generic.semiauto._ |
|||
import io.circe.parser._ |
|||
import monix.bio.IO |
|||
import monix.bio.UIO |
|||
import java.nio.file.NoSuchFileException |
|||
import io.circe.generic.JsonCodec |
|||
|
|||
@JsonCodec |
|||
case class Test1(hello1: String, hello2: String) |
|||
@JsonCodec |
|||
case class Test2(hello1: String) |
|||
case class Plugin(name: String, priority: Int) |
|||
object Plugin { |
|||
implicit val pluginFormat: Decoder[Plugin] = deriveDecoder |
|||
} |
|||
|
|||
object ModdingSystem { |
|||
sealed trait Error extends Serializable with Product |
|||
case class CouldNotDecode(cause: String) extends Error |
|||
case class ParseFailure(cause: String) extends Error |
|||
case class FileNotFound(name: 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] |
|||
) = |
|||
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 mergePluginData(plugins: View[(Plugin, Json)]) = { |
|||
plugins.foldLeft(Json.fromString("empty")) { |
|||
case (json, that) => |
|||
that match { |
|||
case (p, io.circe.Json.Null) => json //ignore null values |
|||
case (p, value) => json.deepMerge(value) |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 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)) |
|||
f <- 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(s"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) |
|||
// } |
|||
; |
|||
} |
@ -0,0 +1,53 @@ |
|||
package wow.doge.mygame.utils |
|||
|
|||
import java.io.PrintStream |
|||
import java.io.OutputStream |
|||
import java.io.ByteArrayOutputStream |
|||
import scalafx.scene.control.TextArea |
|||
import wow.doge.mygame.implicits._ |
|||
import cats.effect.Resource |
|||
import monix.bio.Task |
|||
|
|||
trait JFXConsoleStreamable[T] { |
|||
def println(inst: T, text: String): Unit |
|||
def print(inst: T, text: String): Unit |
|||
} |
|||
|
|||
class JFXConsoleStream[T]( |
|||
outputStream: OutputStream, |
|||
val config: JFXConsoleStream.Config = JFXConsoleStream.Config.default, |
|||
control: T |
|||
)(implicit |
|||
jcs: JFXConsoleStreamable[T] |
|||
) extends PrintStream(outputStream, true) { |
|||
private lazy val defaultOut = System.out |
|||
override def println(text: String): Unit = |
|||
if (config.exclusive) { |
|||
jcs.println(control, text + "\n") |
|||
} else { |
|||
defaultOut.println(text) |
|||
jcs.println(control, text + "\n") |
|||
} |
|||
override def print(text: String): Unit = jcs.println(control, text) |
|||
} |
|||
|
|||
object JFXConsoleStream { |
|||
|
|||
/** |
|||
* for future use |
|||
*/ |
|||
case class Config(exclusive: Boolean = false) |
|||
object Config { |
|||
lazy val default = Config() |
|||
} |
|||
|
|||
def textAreaStream(ta: TextArea) = |
|||
Resource.make( |
|||
Task( |
|||
new JFXConsoleStream( |
|||
outputStream = new ByteArrayOutputStream(), |
|||
control = ta |
|||
) |
|||
) |
|||
)(s => Task(s.close())) |
|||
} |
@ -0,0 +1 @@ |
|||
{ "hello1": "world1", "hello2": "world2" } |
@ -0,0 +1 @@ |
|||
{ "hello2": "world3" } |
Write
Preview
Loading…
Cancel
Save
Reference in new issue