{-|

Module      : Netcode.IO
Description : High-level bindings to the netcode.io library.
Copyright   : (c) Pavel Krajcevski, 2020
License     : BSD-3
Maintainer  : krajcevski@gmail.com
Stability   : experimental
Portability : Portable

This module contains the high-level bindings on top of the module
"Bindings.Netcode.IO". These provide a cleaner interface to the
<https://github.com/networkprotocol/netcode.io netcode.io> C library and are
the recommended interface for application developers.

These bindings have some limitations. Namely, they are not as performant as
the "close to the metal" bindings provided in "Bindings.Netcode.IO". In the
event that you need more performance, that module is available for use.

The general architecture of a @netcode.io@ application is outlined in the C
library
<https://github.com/networkprotocol/netcode.io/blob/master/STANDARD.md#architecture documentation>. The jist is that we need three main entities:

 * A server to connect to
 * An authentication server to dispatch connection tokens
 * A client that wants to connect to a server

In this case, the client will request a connection token from the authentication
server. The authentication server will know a-priori what the available servers
are for the client to connect to. These servers (and other information) are
stored in an encrypted 'ConnectToken', based on the 64-bit unique client ID. The
authentication server will send a 'ConnectToken' to a client when that client
looks for servers to connect to.

Once a connection between server and client is established, they may exchange
packets of information. These packets are sent over UDP and therefore are not
guaranteed to arrive in order or even arrive at all. In order to create a
reliable information channel between client and server, it is recommended to
use this library in conjunction with the
<https://github.com/networkprotocol/reliable.io reliable.io> library.
-}

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
module Netcode.IO (
    -- * Initialization
      initialize
    , terminate

    -- * Addresses
    , Address
    , AddressMode(..)
    , addressMode
    , addressPort
    , addressValues
    , constructAddress
    , parseAddress
    , addressToString
    , addressEqual

    -- * Common callbacks
    , SendPacketOverride
    , ReceivePacketOverride

    -- * Packets
    , module Netcode.IO.Packet
    , module Netcode.IO.Client
    , module Netcode.IO.Server

    -- * Utilities
    , sleep

    , LogLevel(..), logLevel
) where
--------------------------------------------------------------------------------

import Control.Monad         (unless)
import Data.Data             (Data)
import Data.Typeable         (Typeable)
import Foreign.C.Types       (CDouble(..))
import GHC.Generics          (Generic)

import Bindings.Netcode.IO
import Netcode.IO.Address
import Netcode.IO.Callbacks
import Netcode.IO.Client
import Netcode.IO.Packet
import Netcode.IO.Server

--------------------------------------------------------------------------------

-- | Initializes the @netcode.io@ library runtime. This should be called before
-- any additional functions in this library. Throws an
-- t'Control.Exception.IOException' on failure.
initialize :: IO ()
initialize :: IO ()
initialize = do
    CInt
result <- IO CInt
c'netcode_init
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (CInt
result CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
forall a. Num a => a
c'NETCODE_OK) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
      String -> IO ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Failed to initialize netcode.io. Result: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> CInt -> String
forall a. Show a => a -> String
show CInt
result
    () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- | Terminates the @netcode.io@ library runtime. This should be called only
-- after all other library functions terminate.
terminate :: IO ()
terminate :: IO ()
terminate = IO ()
c'netcode_term

-- | Specifies the logging behavior of @netcode.io@. Note, this logging behavior
-- is called from C calls to @printf@ and therefore might interfere with the
-- Haskell runtime (such as 'putStrLn').
data LogLevel = LogLevel'None
              | LogLevel'Info
              | LogLevel'Error
              | LogLevel'Debug
    deriving (LogLevel -> LogLevel -> Bool
(LogLevel -> LogLevel -> Bool)
-> (LogLevel -> LogLevel -> Bool) -> Eq LogLevel
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LogLevel -> LogLevel -> Bool
$c/= :: LogLevel -> LogLevel -> Bool
== :: LogLevel -> LogLevel -> Bool
$c== :: LogLevel -> LogLevel -> Bool
Eq, Eq LogLevel
Eq LogLevel
-> (LogLevel -> LogLevel -> Ordering)
-> (LogLevel -> LogLevel -> Bool)
-> (LogLevel -> LogLevel -> Bool)
-> (LogLevel -> LogLevel -> Bool)
-> (LogLevel -> LogLevel -> Bool)
-> (LogLevel -> LogLevel -> LogLevel)
-> (LogLevel -> LogLevel -> LogLevel)
-> Ord LogLevel
LogLevel -> LogLevel -> Bool
LogLevel -> LogLevel -> Ordering
LogLevel -> LogLevel -> LogLevel
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: LogLevel -> LogLevel -> LogLevel
$cmin :: LogLevel -> LogLevel -> LogLevel
max :: LogLevel -> LogLevel -> LogLevel
$cmax :: LogLevel -> LogLevel -> LogLevel
>= :: LogLevel -> LogLevel -> Bool
$c>= :: LogLevel -> LogLevel -> Bool
> :: LogLevel -> LogLevel -> Bool
$c> :: LogLevel -> LogLevel -> Bool
<= :: LogLevel -> LogLevel -> Bool
$c<= :: LogLevel -> LogLevel -> Bool
< :: LogLevel -> LogLevel -> Bool
$c< :: LogLevel -> LogLevel -> Bool
compare :: LogLevel -> LogLevel -> Ordering
$ccompare :: LogLevel -> LogLevel -> Ordering
$cp1Ord :: Eq LogLevel
Ord, Int -> LogLevel -> String -> String
[LogLevel] -> String -> String
LogLevel -> String
(Int -> LogLevel -> String -> String)
-> (LogLevel -> String)
-> ([LogLevel] -> String -> String)
-> Show LogLevel
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [LogLevel] -> String -> String
$cshowList :: [LogLevel] -> String -> String
show :: LogLevel -> String
$cshow :: LogLevel -> String
showsPrec :: Int -> LogLevel -> String -> String
$cshowsPrec :: Int -> LogLevel -> String -> String
Show, ReadPrec [LogLevel]
ReadPrec LogLevel
Int -> ReadS LogLevel
ReadS [LogLevel]
(Int -> ReadS LogLevel)
-> ReadS [LogLevel]
-> ReadPrec LogLevel
-> ReadPrec [LogLevel]
-> Read LogLevel
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [LogLevel]
$creadListPrec :: ReadPrec [LogLevel]
readPrec :: ReadPrec LogLevel
$creadPrec :: ReadPrec LogLevel
readList :: ReadS [LogLevel]
$creadList :: ReadS [LogLevel]
readsPrec :: Int -> ReadS LogLevel
$creadsPrec :: Int -> ReadS LogLevel
Read, LogLevel
LogLevel -> LogLevel -> Bounded LogLevel
forall a. a -> a -> Bounded a
maxBound :: LogLevel
$cmaxBound :: LogLevel
minBound :: LogLevel
$cminBound :: LogLevel
Bounded, Int -> LogLevel
LogLevel -> Int
LogLevel -> [LogLevel]
LogLevel -> LogLevel
LogLevel -> LogLevel -> [LogLevel]
LogLevel -> LogLevel -> LogLevel -> [LogLevel]
(LogLevel -> LogLevel)
-> (LogLevel -> LogLevel)
-> (Int -> LogLevel)
-> (LogLevel -> Int)
-> (LogLevel -> [LogLevel])
-> (LogLevel -> LogLevel -> [LogLevel])
-> (LogLevel -> LogLevel -> [LogLevel])
-> (LogLevel -> LogLevel -> LogLevel -> [LogLevel])
-> Enum LogLevel
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: LogLevel -> LogLevel -> LogLevel -> [LogLevel]
$cenumFromThenTo :: LogLevel -> LogLevel -> LogLevel -> [LogLevel]
enumFromTo :: LogLevel -> LogLevel -> [LogLevel]
$cenumFromTo :: LogLevel -> LogLevel -> [LogLevel]
enumFromThen :: LogLevel -> LogLevel -> [LogLevel]
$cenumFromThen :: LogLevel -> LogLevel -> [LogLevel]
enumFrom :: LogLevel -> [LogLevel]
$cenumFrom :: LogLevel -> [LogLevel]
fromEnum :: LogLevel -> Int
$cfromEnum :: LogLevel -> Int
toEnum :: Int -> LogLevel
$ctoEnum :: Int -> LogLevel
pred :: LogLevel -> LogLevel
$cpred :: LogLevel -> LogLevel
succ :: LogLevel -> LogLevel
$csucc :: LogLevel -> LogLevel
Enum, (forall x. LogLevel -> Rep LogLevel x)
-> (forall x. Rep LogLevel x -> LogLevel) -> Generic LogLevel
forall x. Rep LogLevel x -> LogLevel
forall x. LogLevel -> Rep LogLevel x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep LogLevel x -> LogLevel
$cfrom :: forall x. LogLevel -> Rep LogLevel x
Generic, Typeable LogLevel
DataType
Constr
Typeable LogLevel
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> LogLevel -> c LogLevel)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c LogLevel)
-> (LogLevel -> Constr)
-> (LogLevel -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c LogLevel))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c LogLevel))
-> ((forall b. Data b => b -> b) -> LogLevel -> LogLevel)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> LogLevel -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> LogLevel -> r)
-> (forall u. (forall d. Data d => d -> u) -> LogLevel -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> LogLevel -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> LogLevel -> m LogLevel)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> LogLevel -> m LogLevel)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> LogLevel -> m LogLevel)
-> Data LogLevel
LogLevel -> DataType
LogLevel -> Constr
(forall b. Data b => b -> b) -> LogLevel -> LogLevel
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> LogLevel -> c LogLevel
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c LogLevel
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> LogLevel -> u
forall u. (forall d. Data d => d -> u) -> LogLevel -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> LogLevel -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> LogLevel -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> LogLevel -> m LogLevel
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> LogLevel -> m LogLevel
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c LogLevel
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> LogLevel -> c LogLevel
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c LogLevel)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c LogLevel)
$cLogLevel'Debug :: Constr
$cLogLevel'Error :: Constr
$cLogLevel'Info :: Constr
$cLogLevel'None :: Constr
$tLogLevel :: DataType
gmapMo :: (forall d. Data d => d -> m d) -> LogLevel -> m LogLevel
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> LogLevel -> m LogLevel
gmapMp :: (forall d. Data d => d -> m d) -> LogLevel -> m LogLevel
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> LogLevel -> m LogLevel
gmapM :: (forall d. Data d => d -> m d) -> LogLevel -> m LogLevel
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> LogLevel -> m LogLevel
gmapQi :: Int -> (forall d. Data d => d -> u) -> LogLevel -> u
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> LogLevel -> u
gmapQ :: (forall d. Data d => d -> u) -> LogLevel -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> LogLevel -> [u]
gmapQr :: (r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> LogLevel -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> LogLevel -> r
gmapQl :: (r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> LogLevel -> r
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> LogLevel -> r
gmapT :: (forall b. Data b => b -> b) -> LogLevel -> LogLevel
$cgmapT :: (forall b. Data b => b -> b) -> LogLevel -> LogLevel
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c LogLevel)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c LogLevel)
dataCast1 :: (forall d. Data d => c (t d)) -> Maybe (c LogLevel)
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c LogLevel)
dataTypeOf :: LogLevel -> DataType
$cdataTypeOf :: LogLevel -> DataType
toConstr :: LogLevel -> Constr
$ctoConstr :: LogLevel -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c LogLevel
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c LogLevel
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> LogLevel -> c LogLevel
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> LogLevel -> c LogLevel
$cp1Data :: Typeable LogLevel
Data, Typeable)

-- | Set the @netcode.io@ 'LogLevel'. The default is 'LogLevel'None'.
logLevel :: LogLevel -> IO ()
logLevel :: LogLevel -> IO ()
logLevel LogLevel
LogLevel'None  = CInt -> IO ()
c'netcode_log_level CInt
forall a. Num a => a
c'NETCODE_LOG_LEVEL_NONE
logLevel LogLevel
LogLevel'Info  = CInt -> IO ()
c'netcode_log_level CInt
forall a. Num a => a
c'NETCODE_LOG_LEVEL_INFO
logLevel LogLevel
LogLevel'Error = CInt -> IO ()
c'netcode_log_level CInt
forall a. Num a => a
c'NETCODE_LOG_LEVEL_ERROR
logLevel LogLevel
LogLevel'Debug = CInt -> IO ()
c'netcode_log_level CInt
forall a. Num a => a
c'NETCODE_LOG_LEVEL_DEBUG

-- | Sleep the current thread. This is usually only used in example programs.
-- It's probably safer to use the built-in 'Control.Concurrent.threadDelay'.
sleep :: Double -> IO ()
sleep :: Double -> IO ()
sleep = CDouble -> IO ()
c'netcode_sleep (CDouble -> IO ()) -> (Double -> CDouble) -> Double -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> CDouble
CDouble