{-# OPTIONS_GHC -fno-warn-orphans #-} module Game( mainWire , Game(..) ) where import Control.Wire import Data.Maybe import Data.Text (pack) import Linear import Prelude hiding (id, (.)) import qualified Data.HashMap.Strict as H import qualified Data.Sequence as S import Game.Bullet import Game.Core import Game.Data import Game.Player import Game.Shared import Game.GoreAndAsh import Game.GoreAndAsh.Actor import Game.GoreAndAsh.Logging import Game.GoreAndAsh.Network import Game.GoreAndAsh.Sync -- | Wire that returns next player color playerColors :: AppWire (Event a) (V3 Double) playerColors = dDispense [ V3 1 0 0 , V3 0 1 0 , V3 0 0 1 , V3 1 1 0 , V3 1 0 1 , V3 0 1 1 ] mainWire :: AppActor GameId a Game mainWire = makeFixedActor globalGameId $ stateWire initGame $ proc (_, g) -> do forceNF . processBullets . processPlayers -< g where -- | Game at start of the simulation initGame = Game { gameId = globalGameId , gamePlayers = H.empty , gamePlayerPeers = H.empty , gameBullets = H.empty , gameBulletColId = fromCounter (-1) , gamePlayerColId = fromCounter (-1) } -- | Handles process of players connection and disconnections processPlayers :: AppWire Game Game processPlayers = proc g -> do conEvent <- peersConnected -< () col <- playerColors -< conEvent let addEvent = fmap (spawnPlayer col) <$> conEvent disEvent <- peersDisconnected -< () remEvent <- filterJustLE -< fmap (despawnPlayer g) <$> disEvent traceEvent (const "New player connected") -< addEvent -- Player id is not ready yet :( traceEvent (\i -> "Player " <> (pack . show) i <> " disconnected") -< remEvent (ps, i) <- runActor $ remoteActorCollectionServer S.empty -< (g, addEvent, remEvent) returnA -< g { gamePlayers = mapFromSeq $ fmap playerId ps `S.zip` ps , gamePlayerPeers = mapFromSeq $ fmap playerPeer ps `S.zip` fmap playerId ps , gamePlayerColId = i } -- | Spawns new player from peer (creates new arrow) spawnPlayer :: V3 Double -> Peer -> AppActor PlayerId Game Player spawnPlayer c p = playerActor $ \i -> Player { playerId = i , playerPos = 0 , playerColor = c , playerRot = 0 , playerPeer = p , playerSpeed = 15 , playerSize = 1 } -- | Detects player id by peer for despawning despawnPlayer :: Game -> Peer -> Maybe PlayerId despawnPlayer Game{..} p = H.lookup p gamePlayerPeers -- | Handle bullets actors processBullets :: AppWire Game Game processBullets = proc g -> do addEvent <- mapE (fmap (bulletActor . newBullet)) . actorMessages globalGameId isGameSpawnBullet -< () remEvent <- mapE (fmap $ \(GameDeleteBullet i) -> i) . actorMessages globalGameId isGameDeleteBullet -< () (bs, i) <- runActor $ remoteActorCollectionServer S.empty -< (g, addEvent, remEvent) returnA -< g { gameBullets = mapFromSeq $ fmap bulletId bs `S.zip` bs , gameBulletColId = i } where newBullet (GameSpawnBullet pos vel owner) i = Bullet { bulletId = i , bulletPos = pos , bulletVel = vel , bulletOwner = owner } newBullet _ _ = error "newBullet: wrong message"