package wow.doge.mygame import akka.actor.typed.ActorRef import akka.actor.typed.ActorSystem import akka.actor.typed.Scheduler import akka.actor.typed.SpawnProtocol import akka.util.Timeout import cats.effect.concurrent.Ref import com.jme3.app.state.AppStateManager import com.jme3.asset.AssetManager import com.jme3.asset.plugins.ZipLocator import com.jme3.bullet.BulletAppState import com.jme3.input.InputManager import com.jme3.renderer.Camera import com.jme3.scene.Node import com.softwaremill.macwire._ import com.softwaremill.tagging._ import io.odin.Logger import monix.bio.IO import monix.bio.Task import wow.doge.mygame.events.EventBus import wow.doge.mygame.game.GameApp2 import wow.doge.mygame.game.nodes.PlayerTag import wow.doge.mygame.game.nodes.PlayerController import wow.doge.mygame.game.subsystems.input.GameInputHandler import wow.doge.mygame.implicits._ import wow.doge.mygame.math.ImVector3f import wow.doge.mygame.subsystems.events.EntityMovementEvent import wow.doge.mygame.subsystems.events.EventsModule2 import wow.doge.mygame.subsystems.events.PlayerCameraEvent import wow.doge.mygame.game.subsystems.level.DefaultGameLevel import com.jme3.renderer.ViewPort import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource import wow.doge.mygame.subsystems.scriptsystem.ScriptInitMode import wow.doge.mygame.launcher.Launcher import wow.doge.mygame.executors.Schedulers import scalafx.application.JFXApp.PrimaryStage import scalafx.geometry.Insets import scalafx.scene.Scene import scalafx.scene.control.Button import scalafx.scene.layout.StackPane import scalafx.scene.paint.Color import scalafx.scene.shape.Rectangle import scalafx.Includes._ import scala.concurrent.duration._ import cats.effect.concurrent.Deferred import monix.bio.Fiber import wow.doge.mygame.launcher.Launcher.LauncherResult import scalafx.scene.control.TextArea import com.jayfella.jme.jfx.JavaFxUI import wow.doge.mygame.utils.GenericConsoleStream import java.io.PrintStream class MainApp( logger: Logger[Task], gameApp: GameApp2, spawnProtocol: ActorSystem[SpawnProtocol.Command], jmeThread: monix.execution.Scheduler, schedulers: Schedulers, consoleStream: GenericConsoleStream[TextArea] )(implicit @annotation.unused timeout: Timeout, @annotation.unused scheduler: Scheduler ) { lazy val scriptSystemInit = new ScriptSystemResource(os.pwd, spawnProtocol, ScriptInitMode.Eager).init def gameInit: Task[Fiber[Throwable, Unit]] = for { eventsModule <- Task(new EventsModule2(spawnProtocol)) playerMovementEventBus <- eventsModule.playerMovementEventBusTask playerCameraEventBus <- eventsModule.playerCameraEventBusTask gameAppFib <- gameApp.start.executeOn(jmeThread).start /** * schedule a task to run on the JME thread and wait for it's completion * before proceeding forward, as a signal that JME thread has been * initialized, otherwise we'll get NPEs trying to access the fields * of the game app */ res <- gameApp.enqueueL(() => Task("done")).flatten _ <- logger.info(s"Result = $res") inputManager <- gameApp.inputManager assetManager <- gameApp.assetManager stateManager <- gameApp.stateManager camera <- gameApp.camera rootNode <- gameApp.rootNode enqueueR <- Task(gameApp.enqueue _) viewPort <- gameApp.viewPort _ <- logger.info("before") // jfxUI <- Task(JavaFxUI.initialize(gameApp.app)) // .executeOn(gameApp.scheduler) >> Task.sleep(500.millis) >> Task( // JavaFxUI.getInstance() // ) // .start jfxUI <- gameApp.jfxUI consoleTextArea <- Task(new TextArea { text = "hello" editable = false wrapText = true // maxHeight = 150 // maxWidth = 300 }) _ <- Task(consoleStream := consoleTextArea) _ <- Task(jfxUI += consoleTextArea) // consoleStream <- Task( // GenericConsoleStream.textAreaStream(consoleTextArea) // ) _ <- logger.info("after") bulletAppState <- Task(new BulletAppState()) _ <- Task(stateManager.attach(bulletAppState)) _ <- logger.info("Initializing console stream") // _ <- Task(GenericConsoleStream.textAreaStream(consoleTextArea)).bracket( // consoleStream => // Task { System.setOut(consoleStream) } >> wire[MainAppDelegate] // .init(gameApp.scheduler, consoleStream) // // consoleLogger // // Console.withOut(consoleStream)( // // wire[MainAppDelegate].init(gameApp.scheduler, consoleStream) // // ) // )(stream => Task(stream.close()).onErrorHandle(_.printStackTrace())) // _ <- Task { System.setOut(new PrintStream(consoleStream, true)) } // _ <- Task { // Console.withOut(consoleStream)(println("hello")) // } _ <- wire[MainAppDelegate].init(gameApp.scheduler) } yield (gameAppFib) lazy val program = for { scriptSystem <- scriptSystemInit /** * Signal for synchronization between the JavaFX launcher and the in-game JavaFX GUI * Without this, we get a "Toolkit already initialized" excResult. The launch button * in the launcher completes the signal. The game init process which listens for this * signal can then continue */ launchSignal <- Deferred[Task, Launcher.LauncherResult] launcher <- new Launcher.Props(schedulers, launchSignal).create cancelToken <- launcher.init() launchResult <- launchSignal.get _ <- cancelToken.cancel _ <- if (launchResult == LauncherResult.Exit) logger.info("Exiting") else gameInit.flatMap(_.join) // _ <- Task.sleep(2000.millis) // gameAppFib <- gameInit /** * Wait for game window to close */ // _ <- gameAppFib.join } yield () } /** * Class with all dependencies in one place for easy wiring */ class MainAppDelegate( gameApp: GameApp2, spawnProtocol: ActorSystem[SpawnProtocol.Command], loggerL: Logger[Task], // eventBuses: EventsModule2 playerMovementEventBus: ActorRef[ EventBus.Command[EntityMovementEvent.PlayerMovementEvent] ], playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]], inputManager: InputManager, assetManager: AssetManager, stateManager: AppStateManager, camera: Camera, viewPort: ViewPort, enqueueR: Function1[() => Unit, Unit], rootNode: Ref[Task, Node], bulletAppState: BulletAppState )(implicit @annotation.unused timeout: Timeout, @annotation.unused scheduler: Scheduler ) { def init( appScheduler: monix.execution.Scheduler // consoleStream: GenericConsoleStream[TextArea] ) = for { _ <- loggerL.info("Initializing Systems") _ <- Task( assetManager.registerLocator( (os.rel / "assets" / "town.zip"), classOf[ZipLocator] ) ) _ <- loggerL.info("test hmm") // _ <- Task(consoleStream.println("text")) _ <- DefaultGameLevel(assetManager, viewPort) .addToGame( rootNode, bulletAppState.physicsSpace ) .executeOn(appScheduler) _ <- createPlayerController(appScheduler).startAndForget.onErrorRestart(3) _ <- wire[GameInputHandler.Props].begin.onErrorRestart(3) } yield () def createPlayerController( appScheduler: monix.execution.Scheduler // playerMovementEventBus: ActorRef[ // EventBus.Command[PlayerMovementEvent] // ], // playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]] ): IO[PlayerController.Error, Unit] = { @annotation.unused val playerPos = ImVector3f.ZERO @annotation.unused val playerNode = None.taggedWith[PlayerTag] @annotation.unused val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o" wire[PlayerController.Props].create } }