package wow.doge.mygame.game.subsystems.input import scala.concurrent.duration._ import akka.actor.typed.ActorRef import cats.effect.concurrent.Ref import com.jme3.input.InputManager import com.jme3.input.KeyInput import com.jme3.input.MouseInput import com.jme3.input.controls.KeyTrigger import com.jme3.input.controls.MouseAxisTrigger import monix.bio.UIO import monix.{eval => me} import wow.doge.mygame.implicits._ import wow.doge.mygame.subsystems.events.EventBus import wow.doge.mygame.subsystems.events.EventsModule.GameEventBus import wow.doge.mygame.subsystems.events.PlayerCameraEvent import wow.doge.mygame.subsystems.events.PlayerMovementEvent import wow.doge.mygame.utils.IOUtils._ object GameInputHandler { final class Props( inputManager: InputManager, playerMovementEventBus: GameEventBus[PlayerMovementEvent], playerCameraEventBus: GameEventBus[PlayerCameraEvent] // tickEventBus: GameEventBus[TickEvent] ) { def begin = for { _ <- UIO(setupMovementKeys(inputManager)) // _ <- UIO(setupAnalogMovementKeys) _ <- UIO(setupCameraKeys()) _ <- toIO( generateMovementInputEvents( inputManager, playerMovementEventBus ).completedL.startAndForget ) _ <- toIO( generateAnalogMovementEvents( inputManager, playerMovementEventBus ).completedL.startAndForget ) _ <- toIO( generateCameraEvents( inputManager, playerCameraEventBus ).completedL.startAndForget ) _ <- toIO( Ref.of[me.Task, Boolean](false).flatMap(value => cursorToggle(value)) ) } yield () def setupMovementKeys(inputManager: InputManager) = inputManager.withEnumMappings(PlayerMovementInput) { case PlayerMovementInput.WalkRight => Seq(new KeyTrigger(KeyInput.KEY_D)) case PlayerMovementInput.WalkLeft => Seq(new KeyTrigger(KeyInput.KEY_A)) case PlayerMovementInput.WalkForward => Seq(new KeyTrigger(KeyInput.KEY_W)) case PlayerMovementInput.WalkBackward => Seq(new KeyTrigger(KeyInput.KEY_S)) case PlayerMovementInput.Jump => Seq(new KeyTrigger(KeyInput.KEY_SPACE)) } def setupAnalogMovementKeys() = inputManager.withEnumMappings(PlayerAnalogMovementInput) { case PlayerAnalogMovementInput.TurnRight => Seq(new KeyTrigger(KeyInput.KEY_D)) case PlayerAnalogMovementInput.TurnLeft => Seq(new KeyTrigger(KeyInput.KEY_A)) } def setupCameraKeys() = inputManager.withEnumMappings(PlayerCameraInput) { case PlayerCameraInput.CameraRotateLeft => Seq( new KeyTrigger(KeyInput.KEY_LEFT), new MouseAxisTrigger(MouseInput.AXIS_X, false) ) case PlayerCameraInput.CameraRotateRight => Seq( new KeyTrigger(KeyInput.KEY_RIGHT), new MouseAxisTrigger(MouseInput.AXIS_X, true) ) case PlayerCameraInput.CameraRotateUp => Seq( new KeyTrigger(KeyInput.KEY_UP), new MouseAxisTrigger(MouseInput.AXIS_Y, false) ) case PlayerCameraInput.CameraRotateDown => Seq( new KeyTrigger(KeyInput.KEY_DOWN), new MouseAxisTrigger(MouseInput.AXIS_Y, true) ) } def cursorToggle(toggleRef: Ref[me.Task, Boolean]) = for { _ <- me.Task( inputManager.withMapping( MiscInput.ToggleCursor, new KeyTrigger(KeyInput.KEY_Z) ) ) _ <- inputManager .enumEntryObservableAction(MiscInput.ToggleCursor) .doOnNext(action => action.binding match { case MiscInput.ToggleCursor => if (action.value) for { value <- toggleRef.getAndUpdate(!_) _ <- me.Task(inputManager.setCursorVisible(value)) } yield () else me.Task.unit // case _ => me.Task.unit } ) .completedL .startAndForget } yield () } def generateMovementInputEvents( inputManager: InputManager, playerMovementEventBus: ActorRef[ EventBus.Command[PlayerMovementEvent] ] ) = { val name = "playerMovementInputEventsGenerator" inputManager .enumObservableAction(PlayerMovementInput) // .dump("O") .doOnNext { action => action.binding match { case PlayerMovementInput.WalkLeft => me.Task( playerMovementEventBus ! EventBus.Publish( PlayerMovementEvent.PlayerMovedLeft(pressed = action.value), name ) ) case PlayerMovementInput.WalkRight => me.Task( playerMovementEventBus ! EventBus.Publish( PlayerMovementEvent.PlayerMovedRight(pressed = action.value), name ) ) case PlayerMovementInput.WalkForward => me.Task( playerMovementEventBus ! EventBus.Publish( PlayerMovementEvent.PlayerMovedForward(pressed = action.value), name ) ) case PlayerMovementInput.WalkBackward => me.Task( playerMovementEventBus ! EventBus.Publish( PlayerMovementEvent.PlayerMovedBackward(pressed = action.value), name ) ) case PlayerMovementInput.Jump => if (action.value) { me.Task( playerMovementEventBus ! EventBus.Publish( PlayerMovementEvent.PlayerJumped, name ) ) } else me.Task.unit } } } def generateAnalogMovementEvents( inputManager: InputManager, playerMovementEventBus: ActorRef[ EventBus.Command[PlayerMovementEvent] ] ) = { // val name = "analogMovementEventsGenerator" inputManager .enumAnalogObservable(PlayerAnalogMovementInput) .sample(1.millis) // .doOnNext(analogEvent => // analogEvent.binding match { // case PlayerAnalogMovementInput.TurnRight => // me.Task( // playerMovementEventBus ! EventBus.Publish( // PlayerMovementEvent.PlayerTurnedRight, // name // ) // ) // case PlayerAnalogMovementInput.TurnLeft => // me.Task( // playerMovementEventBus ! EventBus.Publish( // PlayerMovementEvent.PlayerTurnedLeft, // name // ) // ) // } // ) } def generateCameraEvents( inputManager: InputManager, playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]] ) = { val name = "cameraMovementEventsGenerator" inputManager .enumAnalogObservable(PlayerCameraInput) .sample(1.millis) .doOnNext(analogEvent => analogEvent.binding match { case PlayerCameraInput.CameraRotateLeft => me.Task( playerCameraEventBus ! EventBus.Publish( PlayerCameraEvent.CameraLeft, name ) ) case PlayerCameraInput.CameraRotateRight => me.Task( playerCameraEventBus ! EventBus.Publish( PlayerCameraEvent.CameraRight, name ) ) case PlayerCameraInput.CameraRotateUp => me.Task( playerCameraEventBus ! EventBus.Publish( PlayerCameraEvent.CameraMovedUp, name ) ) case PlayerCameraInput.CameraRotateDown => me.Task( playerCameraEventBus ! EventBus.Publish( PlayerCameraEvent.CameraMovedDown, name ) ) } ) } }