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.Resource import cats.effect.concurrent.Deferred import cats.syntax.eq._ import com.jme3.app.state.AppStateManager import com.jme3.asset.plugins.ZipLocator import com.jme3.bullet.control.BetterCharacterControl import com.jme3.input.InputManager import com.jme3.material.Material import com.jme3.material.MaterialDef import com.jme3.math.FastMath import com.jme3.renderer.Camera import com.jme3.renderer.RenderManager import com.jme3.renderer.ViewPort import com.jme3.scene.Node import com.jme3.scene.control.AbstractControl import com.softwaremill.macwire._ import com.softwaremill.tagging._ import io.odin.Logger import monix.bio.Fiber import monix.bio.IO import monix.bio.Task import monix.bio.UIO import scalafx.scene.control.TextArea import wow.doge.mygame.executors.Schedulers import wow.doge.mygame.game.GameApp import wow.doge.mygame.game.GameAppActor import wow.doge.mygame.game.GameAppResource import wow.doge.mygame.game.GameAppTags import wow.doge.mygame.game.entities.EntityIds import wow.doge.mygame.game.entities.NpcActorSupervisor import wow.doge.mygame.game.entities.NpcMovementActor import wow.doge.mygame.game.entities.PlayerActorSupervisor import wow.doge.mygame.game.entities.PlayerController import wow.doge.mygame.game.entities.PlayerControllerTags import wow.doge.mygame.game.subsystems.input.GameInputHandler import wow.doge.mygame.game.subsystems.level.DefaultGameLevel import wow.doge.mygame.implicits._ import wow.doge.mygame.launcher.Launcher import wow.doge.mygame.launcher.Launcher.LauncherResult import wow.doge.mygame.math.ImVector3f import wow.doge.mygame.subsystems.events.EventsModule import wow.doge.mygame.subsystems.events.EventsModule.GameEventBus import wow.doge.mygame.subsystems.events.PlayerEvent import wow.doge.mygame.subsystems.events.TickEvent import wow.doge.mygame.subsystems.scriptsystem.ScriptInitMode import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource import wow.doge.mygame.utils.AkkaUtils import wow.doge.mygame.utils.GenericConsoleStream import wow.doge.mygame.utils.wrappers.jme.AppNode import wow.doge.mygame.utils.wrappers.jme.AssetManager import wow.doge.mygame.utils.wrappers.jme.PhysicsSpace import wow.doge.mygame.subsystems.events.EventBus.ObservableSubscription import wow.doge.mygame.subsystems.events.PlayerMovementEvent import monix.reactive.Observable import monix.eval.Coeval import wow.doge.mygame.utils.IOUtils import com.jme3.math.ColorRGBA class MainApp( logger: Logger[Task], jmeThread: monix.execution.Scheduler, schedulers: Schedulers, consoleStream: GenericConsoleStream[TextArea] )(implicit spawnProtocol: ActorRef[SpawnProtocol.Command], timeout: Timeout, scheduler: Scheduler ) { val scriptSystemInit = new ScriptSystemResource(os.pwd, ScriptInitMode.Eager).init val eventsModule = new EventsModule(scheduler, spawnProtocol) class TestClass( playerEventBus: GameEventBus[PlayerEvent], tickEventBus: GameEventBus[TickEvent] ) def gameInit: Resource[Task, Fiber[Throwable, Unit]] = wire[GameAppResource].resource.evalMap { case gameApp -> gameAppFib => for { playerEventBus <- eventsModule.playerEventBusTask mainEventBus <- eventsModule.mainEventBusTask tickEventBus <- eventsModule.tickEventBusTask obs <- playerEventBus.askL[Observable[PlayerMovementEvent]]( ObservableSubscription(_) ) _ <- IOUtils.toIO( obs .doOnNextF(pme => Coeval(pprint.log(s"Received event $pme")).void) .completedL .startAndForget ) inputManager <- gameApp.inputManager assetManager <- UIO.pure(gameApp.assetManager) stateManager <- gameApp.stateManager camera <- gameApp.camera rootNode <- UIO.pure(gameApp.rootNode) enqueueR <- UIO(gameApp.enqueue _) viewPort <- gameApp.viewPort physicsSpace <- UIO.pure(gameApp.physicsSpace) _ <- logger.info("before") // jfxUI <- gameApp.jfxUI gameAppActor <- gameApp.spawnGameActor( GameAppActor.Props(tickEventBus).behavior, "gameAppActor" ) _ <- gameAppActor !! GameAppActor.Start consoleTextArea <- Task(new TextArea { text = "hello \n" editable = false wrapText = true // maxHeight = 150 // maxWidth = 300 }) // _ <- Task(consoleStream := consoleTextArea) // _ <- Task(jfxUI += consoleTextArea) _ <- logger.info("after") _ <- logger.info("Initializing console stream") _ <- wire[MainAppDelegate] .init() .executeOn(gameApp.scheduler) } yield gameAppFib } // val x: Task[Unit] = for { // tickEventBus <- eventsModule.tickEventBusTask // playerEventBus <- eventsModule.playerEventBusTask // _ <- UIO(wire[TestClass]) // _ <- gameInit(tickEventBus).use(_.join) // } yield () val program = for { scriptSystem <- scriptSystemInit launchSignal <- Deferred[Task, Launcher.LauncherResult] launcher <- new Launcher.Props(schedulers, launchSignal).create launchResult <- launcher.init.use(_ => launchSignal.get) _ <- /** * User chose to quit */ if (launchResult === LauncherResult.Exit) logger.info("Exiting") /** * User chose launch. Wait for game window to close */ else gameInit.use(_.join) } yield () } /** * Class with all dependencies in one place for easy wiring */ class MainAppDelegate( gameApp: GameApp, loggerL: Logger[Task], playerEventBus: GameEventBus[PlayerEvent], tickEventBus: GameEventBus[TickEvent], inputManager: InputManager, assetManager: AssetManager, stateManager: AppStateManager, physicsSpace: PhysicsSpace[Task], camera: Camera, viewPort: ViewPort, enqueueR: Function1[() => Unit, Unit], rootNode: AppNode[Task] @@ GameAppTags.RootNode )(implicit spawnProtocol: ActorRef[SpawnProtocol.Command], timeout: Timeout, scheduler: Scheduler ) { def init( // appScheduler: monix.execution.Scheduler // consoleStream: GenericConsoleStream[TextArea] ) = for { _ <- loggerL.info("Initializing Systems") _ <- assetManager.registerLocator( os.rel / "assets" / "town.zip", classOf[ZipLocator] ) _ <- loggerL.info("test") // _ <- Task(consoleStream.println("text")) _ <- DefaultGameLevel(assetManager, viewPort) .flatMap(_.addToGame(rootNode, physicsSpace).hideErrors) .onErrorHandleWith(e => loggerL.error(e.toString)) _ <- createPlayerController() .onErrorHandleWith(e => loggerL.error(e.toString)) // .onErrorRestart(3) _ <- wire[GameInputHandler.Props].begin // .onErrorRestart(3) johnActor <- createTestNpc("John") .onErrorHandleWith(e => IO.raiseError(new Throwable(e.toString))) // _ <- johnActor !! NpcActorSupervisor.Move(ImVector3f(0, 0, 20)) // _ <- // johnActor // .tellL(NpcActorSupervisor.Move(ImVector3f(-30, 0, 10))) // .delayExecution(2.seconds) // _ <- // IOUtils // .toIO( // rootNode // .observableBreadthFirst() // .doOnNext(spat => IOUtils.toTask(loggerL.debug(spat.getName()))) // .completedL // ) // .executeOn(appScheduler) // .startAndForget } yield () def createPlayerController( // appScheduler: monix.execution.Scheduler ): IO[PlayerController.Error, ActorRef[PlayerActorSupervisor.Command]] = { val playerPos = ImVector3f.ZERO val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o" val playerPhysicsControl = PlayerController.Defaults.defaultPlayerPhysicsControl .taggedWith[PlayerControllerTags.PlayerTag] for { playerModel <- assetManager .loadModelAs[Node](modelPath) .map(_.withRotate(0, FastMath.PI, 0)) .mapError(PlayerController.CouldNotCreatePlayerModel) playerNode <- UIO( PlayerController.Defaults .defaultPlayerNode( playerPos, playerModel, playerPhysicsControl ) ) cameraPivotNode <- UIO( new Node(EntityIds.CameraPivot.value) .withControl(new FollowControl(playerNode)) .taggedWith[PlayerControllerTags.PlayerCameraPivotNode] ) camNode <- UIO( PlayerController.Defaults .defaultCamerNode(camera, playerPos) .taggedWith[PlayerControllerTags.PlayerCameraNode] ) playerActor <- wire[PlayerController.Props].create } yield playerActor } def createTestNpc( // appScheduler: monix.execution.Scheduler, npcName: String ) = { val initialPos = ImVector3f(50, 5, 0) val npcPhysicsControl = new BetterCharacterControl(1.5f, 6f, 1f) // (1f, 2.1f, 10f) .withJumpForce(ImVector3f(0, 5f, 0)) val npcActorTask = AkkaUtils.spawnActorL( NpcActorSupervisor .Props( new NpcMovementActor.Props( enqueueR, initialPos, // tickEventBus, npcName, npcPhysicsControl ).behavior, npcName, initialPos ) .behavior, s"${npcName}-npcActorSupervisor" ) for { materialDef <- assetManager.loadAssetAs[MaterialDef]( os.rel / "Common" / "MatDefs" / "Misc" / "Unshaded.j3md" ) material = new Material(materialDef) _ = material.setColor("Color", ColorRGBA.Blue) mesh = PlayerController.Defaults.defaultMesh.withMaterial(material) npcNode = PlayerController.Defaults.defaultNpcNode( mesh, initialPos, npcPhysicsControl, npcName ) npcActor <- npcActorTask.hideErrors _ <- (for { _ <- physicsSpace += npcPhysicsControl _ <- physicsSpace += npcNode _ <- rootNode += npcNode } yield ()).hideErrors } yield npcActor } } class FollowControl(playerNode: Node) extends AbstractControl { override def controlUpdate(tpf: Float): Unit = this.spatial.setLocalTranslation(playerNode.getLocalTranslation()) override def controlRender( rm: RenderManager, vp: ViewPort ): Unit = {} }