packages feed

gbnet-hs-0.2.0.0: src/GBNet.hs

-- |
-- Module      : GBNet
-- Description : Game networking library with zero-copy Storable serialization
--
-- This is the main entry point for gbnet-hs. Import this module for
-- convenient access to the full API.
--
-- @
-- import GBNet
--
-- main = do
--   let addr = localhost 7777
--   Right (peer, sock) <- newPeer addr defaultNetworkConfig =<< getMonoTimeIO
--   netState <- newNetState sock addr
--   evalNetT (gameLoop peer) netState
-- @
--
-- For explicit imports, use the individual modules:
--
-- @
-- import GBNet.Class (MonadNetwork, MonadTime)
-- import GBNet.Net (NetT, runNetT, NetState)
-- import GBNet.Peer (NetPeer, peerTick, PeerEvent(..))
-- @
module GBNet
  ( -- * Effect Classes
    MonadTime (..),
    MonadNetwork (..),
    MonoTime (..),
    NetError (..),

    -- * Domain Types
    ChannelId (..),
    channelIdToInt,
    SequenceNum (..),
    MessageId (..),

    -- * Network Monad
    NetT,
    runNetT,
    evalNetT,
    execNetT,
    NetState,
    newNetState,

    -- * IO Backend
    initNetState,
    getMonoTimeIO,

    -- * Socket Address Utilities
    SockAddr (..),
    localhost,
    ipv4,
    anyAddr,
    localhost6,
    ipv6,
    anyAddr6,

    -- * Socket
    SocketError (..),
    UdpSocket,

    -- * Peer Networking
    NetPeer,
    PeerId (..),
    peerIdFromAddr,
    PeerEvent (..),
    ConnectionDirection (..),
    DisconnectReason (..),

    -- ** Peer Creation
    newPeer,
    newPeerState,

    -- ** Peer Operations (Polymorphic)
    peerTick,
    peerRecvAllM,
    peerSendAllM,
    peerShutdownM,

    -- ** Peer Operations (Pure)
    peerConnect,
    peerDisconnect,
    peerProcess,
    peerSend,
    peerBroadcast,

    -- ** Pure Processing Types
    PeerResult (..),
    IncomingPacket (..),
    RawPacket (..),

    -- ** Peer Queries
    peerCount,
    peerIsConnected,
    peerStats,
    peerLocalAddr,
    peerConnectedIds,
    peerConfig,

    -- * Connection
    ConnectionState (..),
    ConnectionError (..),
    ChannelError (..),

    -- * Configuration
    NetworkConfig (..),
    defaultNetworkConfig,
    ConfigError (..),
    validateConfig,
    SimulationConfig (..),
    defaultSimulationConfig,
    ChannelConfig (..),
    defaultChannelConfig,
    unreliableConfig,
    reliableOrderedConfig,
    reliableSequencedConfig,
    DeliveryMode (..),

    -- * Simulation
    NetworkSimulator,
    newNetworkSimulator,
    simulatorProcessSend,
    simulatorReceiveReady,
    simulatorPendingCount,
    simulatorConfig,

    -- * Testing
    TestNet,
    runTestNet,
    TestNetState (..),
    initialTestNetState,
    TestWorld (..),
    newTestWorld,
    runPeerInWorld,
    deliverPackets,
    worldAdvanceTime,

    -- * Serialization (Storable-based, zero-copy)
    serialize,
    deserialize,
    deriveStorable,

    -- * Encryption
    EncryptionKey (..),
    NonceCounter (..),
    CryptoError (..),
    encrypt,
    decrypt,

    -- * Statistics
    NetworkStats (..),
    CongestionLevel (..),

    -- * Replication: Delta Compression
    NetworkDelta (..),
    BaselineSeq,
    DeltaTracker,
    newDeltaTracker,
    deltaEncode,
    deltaOnAck,
    BaselineManager,
    newBaselineManager,
    pushBaseline,
    getBaseline,
    deltaDecode,

    -- * Replication: Interest Management
    InterestManager (..),
    RadiusInterest,
    newRadiusInterest,
    GridInterest,
    newGridInterest,
    filterRelevant,

    -- * Replication: Priority Accumulator
    PriorityAccumulator,
    newPriorityAccumulator,
    register,
    unregister,
    accumulate,
    drainTop,
    getPriority,

    -- * Replication: Snapshot Interpolation
    Interpolatable (..),
    SnapshotBuffer,
    newSnapshotBuffer,
    newSnapshotBufferWithConfig,
    pushSnapshot,
    sampleSnapshot,
    snapshotReady,
  )
where

import Data.Word (Word16, Word32, Word8)
import GBNet.Channel (ChannelConfig (..), ChannelError (..), DeliveryMode (..), defaultChannelConfig, reliableOrderedConfig, reliableSequencedConfig, unreliableConfig)
import GBNet.Class
import GBNet.Config (ConfigError (..), NetworkConfig (..), SimulationConfig (..), defaultNetworkConfig, defaultSimulationConfig, validateConfig)
import GBNet.Connection (ConnectionError (..), ConnectionState (..), DisconnectReason (..))
import GBNet.Crypto (CryptoError (..), EncryptionKey (..), NonceCounter (..), decrypt, encrypt)
import GBNet.Net
import GBNet.Net.IO (initNetState)
import GBNet.Peer
import GBNet.Replication.Delta (BaselineManager, BaselineSeq, DeltaTracker, NetworkDelta (..), deltaDecode, deltaEncode, deltaOnAck, getBaseline, newBaselineManager, newDeltaTracker, pushBaseline)
import GBNet.Replication.Interest (GridInterest, InterestManager (..), RadiusInterest, newGridInterest, newRadiusInterest)
import qualified GBNet.Replication.Interest as Interest
import GBNet.Replication.Interpolation (Interpolatable (..), SnapshotBuffer, newSnapshotBuffer, newSnapshotBufferWithConfig, pushSnapshot, sampleSnapshot, snapshotReady)
import GBNet.Replication.Priority (PriorityAccumulator, accumulate, drainTop, getPriority, newPriorityAccumulator, register, unregister)
import GBNet.Serialize (deserialize, serialize)
import GBNet.Serialize.TH (deriveStorable)
import GBNet.Simulator (NetworkSimulator, newNetworkSimulator, simulatorConfig, simulatorPendingCount, simulatorProcessSend, simulatorReceiveReady)
import GBNet.Socket (SocketError (..), UdpSocket)
import GBNet.Stats (CongestionLevel (..), NetworkStats (..))
import GBNet.TestNet
import GBNet.Types
import Network.Socket (SockAddr (..))
import qualified Network.Socket as NS

-- | Create a localhost address on the given port.
--
-- @
-- let addr = localhost 7777
-- @
localhost :: Word16 -> SockAddr
localhost port = SockAddrInet (fromIntegral port) (NS.tupleToHostAddress (127, 0, 0, 1))

-- | Create an IPv4 address from tuple and port.
--
-- @
-- let addr = ipv4 (192, 168, 1, 100) 7777
-- @
ipv4 :: (Word8, Word8, Word8, Word8) -> Word16 -> SockAddr
ipv4 (a, b, c, d) port =
  SockAddrInet (fromIntegral port) (NS.tupleToHostAddress (a, b, c, d))

-- | Bind to any interface on the given port.
--
-- @
-- let addr = anyAddr 7777
-- @
anyAddr :: Word16 -> SockAddr
anyAddr port = SockAddrInet (fromIntegral port) 0

-- | Filter entities to only those relevant to an observer.
--
-- @
-- let nearby = filterRelevant interest observerPos entities
-- @
filterRelevant ::
  (InterestManager a) =>
  a ->
  Interest.Position ->
  [(Interest.Position, b)] ->
  [b]
filterRelevant mgr observerPos =
  map snd . filter (\(entPos, _) -> Interest.relevant mgr entPos observerPos)

-- | Create an IPv6 localhost address (@::1@) on the given port.
--
-- @
-- let addr = localhost6 7777
-- @
localhost6 :: Word16 -> SockAddr
localhost6 port = SockAddrInet6 (fromIntegral port) 0 (0, 0, 0, 1) 0

-- | Create an IPv6 address from a 4-tuple of 32-bit words and a port.
--
-- @
-- let addr = ipv6 (0x20010db8, 0, 0, 1) 7777
-- @
ipv6 :: (Word32, Word32, Word32, Word32) -> Word16 -> SockAddr
ipv6 (a, b, c, d) port = SockAddrInet6 (fromIntegral port) 0 (a, b, c, d) 0

-- | Bind to any IPv6 interface (@::@) on the given port.
--
-- @
-- let addr = anyAddr6 7777
-- @
anyAddr6 :: Word16 -> SockAddr
anyAddr6 port = SockAddrInet6 (fromIntegral port) 0 (0, 0, 0, 0) 0

-- | Get the network configuration from a peer.
peerConfig :: NetPeer -> NetworkConfig
peerConfig = npConfig