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.
-}