packages feed

HGamer3D-Network-0.5.0: HGamer3D/Network/NetworkBase.hs

{-# OPTIONS_HADDOCK hide #-}
-- This source file is part of HGamer3D
-- (A project to enable 3D game development in Haskell)
-- For the latest info, see http://www.hgamer3d.org
--
-- (c) 2011-2013 Peter Althainz
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.

-- Network/Internal/Base.hs

-- | Network functionality for HGamer3D, internal implementation, which exports also internal data structures. Public API is in module HGamer3D.Network.
module HGamer3D.Network.NetworkBase
where

import GHC.Ptr

import HGamer3D.Data.HG3DClass
import HGamer3D.Data.GameTime

import HGamer3D.Bindings.Enet.ClassEnet as EnetClass
import HGamer3D.Bindings.Enet.ClassEnetServer as EnetServer
import HGamer3D.Bindings.Enet.ClassEnetClient as EnetClient
import HGamer3D.Bindings.Enet.ClassEnetPacket as EnetPacket

-- | The network system
data NetworkSystem = NetworkSystem HG3DClass

-- | The network client
data NetworkClient = NetworkClient HG3DClass

-- | The network server
data NetworkServer = NetworkServer HG3DClass

-- |  A network packet
data NetworkPacket = NetworkPacket {
                clientname :: String,  -- ^ the name of the client, sending the message, can be used, to reply
                channel :: Int, -- ^ the channel on which the message has been sent
                message :: String -- ^ the actual message itself
                }


initNetwork = do
	    hg3dclass <- EnetClass.new
	    return (NetworkSystem hg3dclass)

freeNetwork (NetworkSystem hg3dclass) = EnetClass.delete hg3dclass

-- | creates a network client, a client can connect to servers, but not vice versa
networkClient :: IO NetworkClient
networkClient = do
    client <- EnetClass.createClient
    return (NetworkClient client)
    
-- | creates a network server, a server can accept connections from clients
networkServer :: Int  -- ^ the port on which the server listen for connections
                       -> IO NetworkServer
networkServer port = do
    server <- EnetClass.createServer port
    return (NetworkServer server)

-- | create a connection from a client to a server
connectClientToServer :: NetworkClient -- ^ the client, created by createNetworkClient
                         -> String  -- ^ the server address (regular IP addresses or NS names)
                         -> Int -- ^ the port of the server to connect to
                         -> IO Bool
connectClientToServer (NetworkClient client) serveraddress port = do
    ok <- EnetClient.connect client serveraddress port
    return ok
    
-- | disconnect a client from a server
disconnectClient :: NetworkClient -- ^ the client
                    -> IO Bool
disconnectClient (NetworkClient client) = do
    ok <- EnetClient.disconnect client
    return ok

-- | The network node. This TypeClass contain the methods for sending and receiving data.
class NetworkNode a where
    -- | the method to send a message
    sendNetworkMessage :: a  -- ^ the node itself
                              -> String -- ^ the clientname (only used, when a server send to one of his clients). Can be obtained from the first message send by the client, see above in the 'NetworkPacket' type.
                              -> Int -- ^ the channel on which to send the message
                              -> String -- ^ the message
                              -> IO ()
        
    -- | receive pending messages
    receiveNetworkMessages :: a -- ^ the node itself
                                  -> GameTime -- ^ the time, which the node waits for incoming messages. If zero only delivers pending messages.
                                  -> IO [NetworkPacket] -- ^ array of received network packages


_transformPackage :: HG3DClass -> IO NetworkPacket
_transformPackage p = do
    message <- EnetPacket.getData p
    channel <- EnetPacket.getChannel p
    clientname <- EnetPacket.getPeer p
    EnetPacket.delete p
    return $ NetworkPacket clientname channel message

_receiveClient client ms pkg = do
    EnetClient.serve client ms
    p <- EnetClient.getPacket client
    let (HG3DClass aptr bptr) = p
    if aptr /= nullPtr 
        then do
            p' <- _transformPackage p
            pkg' <- _receiveClient client ms (pkg ++ [p'])
            return pkg'
        else do
            return pkg 
    
_receiveServer server ms pkg = do
    EnetServer.serve server ms
    p <- EnetServer.getPacket server
    let (HG3DClass aptr bptr) = p
    if aptr /= nullPtr 
        then do
            p' <- _transformPackage p
            pkg' <- _receiveServer server ms (pkg ++ [p'])
            return pkg'
        else do
            return pkg 
    
instance NetworkNode NetworkClient where
    
    sendNetworkMessage (NetworkClient client) clientname channel message = do
        EnetClient.send client message channel
        return ()

    receiveNetworkMessages (NetworkClient client) gtime = do
        allPs <- _receiveClient client (msec gtime) []
        return allPs

instance NetworkNode NetworkServer where

    sendNetworkMessage (NetworkServer server) clientname channel message = do
        EnetServer.send server clientname message channel
        return ()

    receiveNetworkMessages (NetworkServer server) gtime = do
        allPs <- _receiveServer server (msec gtime) []
        return allPs


    

{-$Overview

The commuication model of this library is as follows. There are clients and servers. Clients can connect to servers but not the other way around. So each server can have multiple clients. Both are nodes. Nodes can send and receive messages. 

Upon connection the port is defined on which servers and clients communicate with each other.

In addition to the port, channels exists, to enable parallel streams of messages on different channels.

A client has a name, to identify him. This name is communicated in the first packet from the client to the server. The server needs the client name, to send a package to the specific client. The client does not need a name for the server, since there exists only one connection from the client to one server.

-}