# Various networking code cleanups.
Don't flush network queue after every message. Desingletonify CGameAttributes to allow testing. Make network server/client basically testable. Add very basic tests for network server/client. Fix FsmActionCtx memory leak. Split CNetHost into a separate file. Convert CNetHost, CNetSession to a more conventional coding style. Delete CNetLogger, since it's a lot of complexity and is barely used and is redundant with CLogger. Other minor simplifications. This was SVN commit r7623.
This commit is contained in:
parent
2c160e5bd8
commit
dfb10c8209
@ -25,20 +25,22 @@
|
||||
|
||||
// INCLUDES
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "NetClient.h"
|
||||
|
||||
#include "NetJsEvents.h"
|
||||
#include "Network.h"
|
||||
#include "NetServer.h"
|
||||
|
||||
#include "scripting/DOMEvent.h"
|
||||
#include "scripting/JSConversions.h"
|
||||
#include "scripting/ScriptableObject.h"
|
||||
#include "ps/CStr.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/CConsole.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/CStr.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/Globals.h"
|
||||
#include "ps/GameAttributes.h"
|
||||
#include "simulation/Simulation.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
|
||||
// DECLARATIONS
|
||||
@ -81,8 +83,8 @@ void CServerPlayer::ScriptingInit( void )
|
||||
// Name: CNetClient()
|
||||
// Desc: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CNetClient::CNetClient( CGame* pGame, CGameAttributes* pGameAttribs )
|
||||
: m_JsPlayers( &m_Players )
|
||||
CNetClient::CNetClient( ScriptInterface& scriptInterface, CGame* pGame, CGameAttributes* pGameAttribs )
|
||||
: CNetHost( scriptInterface ), m_JsPlayers( &m_Players )
|
||||
{
|
||||
m_ClientTurnManager = NULL;
|
||||
|
||||
@ -167,8 +169,7 @@ bool CNetClient::SetupSession( CNetSession* pSession )
|
||||
// Validate parameters
|
||||
if ( !pSession ) return false;
|
||||
|
||||
FsmActionCtx* pContext = new FsmActionCtx; // XXX: this gets leaked
|
||||
if ( !pContext ) return false;
|
||||
FsmActionCtx* pContext = pSession->GetFsmActionCtx();
|
||||
|
||||
pContext->pHost = this;
|
||||
pContext->pSession = pSession;
|
||||
@ -291,7 +292,7 @@ void CNetClient::OnConnectComplete( )
|
||||
{
|
||||
if ( m_OnConnectComplete.Defined() )
|
||||
{
|
||||
CConnectCompleteEvent connectComplete( ( CStrW )PS_OK, true );
|
||||
CConnectCompleteEvent connectComplete( "OK", true );
|
||||
m_OnConnectComplete.DispatchEvent( GetScript(), &connectComplete );
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
// INCLUDES
|
||||
#include "NetSession.h"
|
||||
#include "NetHost.h"
|
||||
#include "NetTurnManager.h"
|
||||
#include "ps/CStr.h"
|
||||
#include "scripting/ScriptObject.h"
|
||||
@ -80,7 +81,7 @@ class CNetClient: public CNetHost,
|
||||
|
||||
public:
|
||||
|
||||
CNetClient( CGame* pGame, CGameAttributes* pGameAttributes );
|
||||
CNetClient( ScriptInterface& scriptInterface, CGame* pGame, CGameAttributes* pGameAttributes );
|
||||
~CNetClient( void );
|
||||
|
||||
bool CreateSession ( void );
|
||||
|
467
source/network/NetHost.cpp
Normal file
467
source/network/NetHost.cpp
Normal file
@ -0,0 +1,467 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "NetHost.h"
|
||||
#include "NetSession.h"
|
||||
#include "NetMessage.h"
|
||||
|
||||
#include "ps/CLogger.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
|
||||
#include <enet/enet.h>
|
||||
|
||||
static const int ENET_DEFAULT_CHANNEL = 0;
|
||||
static const int CONNECT_TIMEOUT = 5000;
|
||||
static const int DISCONNECT_TIMEOUT = 1000;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: CNetHost()
|
||||
// Desc: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CNetHost::CNetHost(ScriptInterface& scriptInterface) :
|
||||
m_ScriptInterface(scriptInterface)
|
||||
{
|
||||
m_Host = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ~CNetHost()
|
||||
// Desc: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CNetHost::~CNetHost()
|
||||
{
|
||||
// Shutdown(); // TODO: should do something like this except don't call HandleDisconnect()
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Create()
|
||||
// Desc: Creates a client host
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::Create()
|
||||
{
|
||||
debug_assert(!m_Host);
|
||||
|
||||
// Create ENet host
|
||||
m_Host = enet_host_create(NULL, 1, 0, 0);
|
||||
if (!m_Host)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Create()
|
||||
// Desc: Creates a server host
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::Create(uint port, uint maxPeers)
|
||||
{
|
||||
ENetAddress addr;
|
||||
|
||||
// Bind to default host
|
||||
addr.host = ENET_HOST_ANY;
|
||||
addr.port = port;
|
||||
|
||||
// Create ENet server
|
||||
m_Host = enet_host_create(&addr, maxPeers, 0, 0);
|
||||
if (!m_Host)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Shutdown()
|
||||
// Desc: Shuts down network server and releases any resources
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNetHost::Shutdown()
|
||||
{
|
||||
// Disconnect and release each peer
|
||||
PeerSessionList::iterator it = m_PeerSessions.begin();
|
||||
for (; it != m_PeerSessions.end(); it++)
|
||||
{
|
||||
if (!it->pSession)
|
||||
continue;
|
||||
|
||||
Disconnect(it->pSession);
|
||||
|
||||
delete it->pSession;
|
||||
}
|
||||
|
||||
m_PeerSessions.clear();
|
||||
|
||||
// Destroy server
|
||||
if (m_Host)
|
||||
enet_host_destroy(m_Host);
|
||||
|
||||
m_Host = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Connect()
|
||||
// Desc: Connects to the specified remote host
|
||||
// Note: Only clients use this method for connection to server
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::Connect(const CStr& host, uint port)
|
||||
{
|
||||
debug_assert(m_Host);
|
||||
|
||||
// Bind to specified host
|
||||
ENetAddress addr;
|
||||
addr.port = port;
|
||||
if (enet_address_set_host(&addr, host.c_str()) < 0)
|
||||
return false;
|
||||
|
||||
// Initiate connection, allocate one channel
|
||||
ENetPeer* pPeer = enet_host_connect(m_Host, &addr, 1);
|
||||
if (!pPeer)
|
||||
return false;
|
||||
|
||||
// Wait a few seconds for the connection to succeed
|
||||
// TODO: we ought to poll asynchronously so we can update the GUI while waiting
|
||||
ENetEvent event;
|
||||
if (enet_host_service(m_Host, &event, CONNECT_TIMEOUT) > 0 && event.type == ENET_EVENT_TYPE_CONNECT)
|
||||
{
|
||||
// Connection succeeded
|
||||
CNetSession* pNewSession = new CNetSession(this, event.peer);
|
||||
|
||||
if (!SetupSession(pNewSession))
|
||||
{
|
||||
delete pNewSession;
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGMESSAGE(L"Net: Successfully connected to server %hs:%d", host.c_str(), port);
|
||||
|
||||
// Successfully handled?
|
||||
if (!HandleConnect(pNewSession))
|
||||
{
|
||||
delete pNewSession;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the only server session
|
||||
PeerSession item;
|
||||
item.pPeer = event.peer;
|
||||
item.pSession = pNewSession;
|
||||
m_PeerSessions.push_back(item);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LOGERROR(L"Net: Connection to server %hs:%d failed", host.c_str(), port);
|
||||
|
||||
// Timed out or a host was disconnected
|
||||
enet_peer_reset(pPeer);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ConnectAsync()
|
||||
// Desc: Connects to the specified remote host
|
||||
// Note: Only clients use this method for connection to server
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::ConnectAsync(const CStr& host, uint port)
|
||||
{
|
||||
debug_assert(m_Host);
|
||||
|
||||
// Bind to specified host
|
||||
ENetAddress addr;
|
||||
addr.port = port;
|
||||
if (enet_address_set_host(&addr, host.c_str()) < 0)
|
||||
return false;
|
||||
|
||||
// Initiate connection, allocate one channel
|
||||
ENetPeer* pPeer = enet_host_connect(m_Host, &addr, 1);
|
||||
if (!pPeer)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Disconnect()
|
||||
// Desc: Disconnects the specified session from the host
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::Disconnect(CNetSession* pSession)
|
||||
{
|
||||
// Validate parameters
|
||||
if (!pSession)
|
||||
return false;
|
||||
|
||||
debug_assert(m_Host);
|
||||
debug_assert(pSession->m_Peer);
|
||||
|
||||
// Disconnect peer
|
||||
enet_peer_disconnect(pSession->m_Peer, 0);
|
||||
|
||||
// Allow a few seconds for the disconnect to succeed
|
||||
ENetEvent event;
|
||||
while (enet_host_service(m_Host, &event, DISCONNECT_TIMEOUT) > 0)
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case ENET_EVENT_TYPE_RECEIVE:
|
||||
|
||||
// Drop any received packets
|
||||
enet_packet_destroy(event.packet);
|
||||
break;
|
||||
|
||||
case ENET_EVENT_TYPE_DISCONNECT:
|
||||
|
||||
// Disconnect received for peer
|
||||
if (!HandleDisconnect(pSession))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect attempt didn't succeed, force connection down
|
||||
enet_peer_reset(pSession->m_Peer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ProcessEvents()
|
||||
// Desc: Wait for events and shuttles packets between the host and its peers
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNetHost::Poll()
|
||||
{
|
||||
debug_assert(m_Host);
|
||||
|
||||
// Poll host for events
|
||||
ENetEvent event;
|
||||
while (enet_host_service(m_Host, &event, 0) > 0)
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case ENET_EVENT_TYPE_CONNECT:
|
||||
{
|
||||
// A new client has connected, handle it
|
||||
CNetSession* pSession = new CNetSession(this, event.peer);
|
||||
|
||||
// Setup new session
|
||||
if (!SetupSession(pSession))
|
||||
{
|
||||
delete pSession;
|
||||
break;
|
||||
}
|
||||
|
||||
LOGMESSAGE(L"Net: A new client connected from %x:%u", event.peer->address.host, event.peer->address.port);
|
||||
|
||||
// Successfully handled?
|
||||
if (!HandleConnect(pSession))
|
||||
{
|
||||
delete pSession;
|
||||
break;
|
||||
}
|
||||
|
||||
event.peer->data = pSession;
|
||||
|
||||
// Add new item to internal list
|
||||
PeerSession item;
|
||||
item.pPeer = event.peer;
|
||||
item.pSession = pSession;
|
||||
m_PeerSessions.push_back( item );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ENET_EVENT_TYPE_DISCONNECT:
|
||||
{
|
||||
// Client has disconnected, handle it
|
||||
PeerSessionList::iterator it = m_PeerSessions.begin();
|
||||
for (; it != m_PeerSessions.end(); it++)
|
||||
{
|
||||
// Is this our session?
|
||||
if (it->pPeer == event.peer)
|
||||
{
|
||||
LOGMESSAGE(L"Net: %p disconnected", event.peer->data);
|
||||
|
||||
// Successfully handled?
|
||||
if (HandleDisconnect(it->pSession))
|
||||
m_PeerSessions.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ENET_EVENT_TYPE_RECEIVE:
|
||||
{
|
||||
// A new data packet was received from client, handle message
|
||||
PeerSessionList::iterator it = m_PeerSessions.begin();
|
||||
for (; it != m_PeerSessions.end(); it++)
|
||||
{
|
||||
// Is this our session?
|
||||
if (it->pPeer == event.peer)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
// Create message from raw data
|
||||
CNetMessage* pNewMessage = CNetMessageFactory::CreateMessage(event.packet->data, event.packet->dataLength, m_ScriptInterface);
|
||||
if (pNewMessage)
|
||||
{
|
||||
LOGMESSAGE(L"Message %hs of size %lu was received from %p", pNewMessage->ToString().c_str(), (unsigned long)pNewMessage->GetSerializedLength(), event.peer->data);
|
||||
|
||||
ok = HandleMessageReceive(pNewMessage, it->pSession);
|
||||
|
||||
delete pNewMessage;
|
||||
}
|
||||
|
||||
// Done using the packet
|
||||
enet_packet_destroy(event.packet);
|
||||
|
||||
// TODO: what should we do if ok is false?
|
||||
// For now, just carry on as if nothing bad happened
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Broadcast()
|
||||
// Desc: Broadcast the specified message to connected clients
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNetHost::Broadcast(const CNetMessage* pMessage)
|
||||
{
|
||||
// Validate parameters
|
||||
if (!pMessage)
|
||||
return;
|
||||
|
||||
// Loop through the list of sessions and send the message to each
|
||||
for (uint i = 0; i < GetSessionCount(); i++)
|
||||
{
|
||||
CNetSession* pCurrSession = GetSession(i);
|
||||
if (!pCurrSession)
|
||||
continue;
|
||||
|
||||
SendMessage(pCurrSession, pMessage);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SendMessage()
|
||||
// Desc: Sends the specified message to peer
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::SendMessage(const CNetSession* pSession, const CNetMessage* pMessage)
|
||||
{
|
||||
// Validate parameters
|
||||
if (!pMessage || !pSession)
|
||||
return false;
|
||||
|
||||
debug_assert(pSession->m_Peer);
|
||||
debug_assert(m_Host);
|
||||
|
||||
size_t size = pMessage->GetSerializedLength();
|
||||
|
||||
debug_assert(size); // else we'll fail when accessing the 0th element
|
||||
|
||||
// Adjust buffer for message
|
||||
std::vector<u8> buffer;
|
||||
buffer.resize(size);
|
||||
|
||||
// Save message to internal buffer
|
||||
pMessage->Serialize(&buffer[0]);
|
||||
|
||||
// Create a reliable packet
|
||||
ENetPacket* pPacket = enet_packet_create(&buffer[0], size, ENET_PACKET_FLAG_RELIABLE);
|
||||
if (!pPacket)
|
||||
return false;
|
||||
|
||||
// Let ENet send the message to peer
|
||||
if (enet_peer_send(pSession->m_Peer, ENET_DEFAULT_CHANNEL, pPacket) < 0)
|
||||
{
|
||||
// ENet failed to send the packet
|
||||
LOGERROR(L"Net: Failed to send ENet packet to peer");
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMESSAGE(L"Net: Message %hs of size %lu was sent to %p",
|
||||
pMessage->ToString().c_str(), (unsigned long)size, pSession->m_Peer->data);
|
||||
}
|
||||
|
||||
// Don't call enet_host_flush - let it queue up all the packets
|
||||
// and send them during the next frame
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ReceiveMessage()
|
||||
// Desc: Receives a message from client if incoming packets are available
|
||||
//-----------------------------------------------------------------------------
|
||||
CNetMessage* CNetHost::ReceiveMessage(const CNetSession* pSession)
|
||||
{
|
||||
// Validate parameters
|
||||
if (!pSession)
|
||||
return NULL;
|
||||
|
||||
debug_assert(pSession->m_Peer);
|
||||
|
||||
// Let ENet receive a message from peer
|
||||
ENetPacket* pPacket = enet_peer_receive(pSession->m_Peer, ENET_DEFAULT_CHANNEL);
|
||||
if (!pPacket)
|
||||
return NULL;
|
||||
|
||||
// Create new message
|
||||
return CNetMessageFactory::CreateMessage(pPacket->data, pPacket->dataLength, m_ScriptInterface);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: HandleMessageReceive()
|
||||
// Desc: Allow application to handle message recive
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::HandleMessageReceive(CNetMessage* pMessage, CNetSession* pSession)
|
||||
{
|
||||
// Validate parameters
|
||||
if (!pSession || !pMessage)
|
||||
return false;
|
||||
|
||||
// Update FSM
|
||||
return pSession->Update(pMessage->GetType(), pMessage);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: GetSessionCount()
|
||||
// Desc: Returns the number of sessions the host manages
|
||||
//-----------------------------------------------------------------------------
|
||||
uint CNetHost::GetSessionCount() const
|
||||
{
|
||||
return (uint)m_PeerSessions.size();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: GetSession()
|
||||
// Desc: Rteurns the session for the index
|
||||
//-----------------------------------------------------------------------------
|
||||
CNetSession* CNetHost::GetSession(uint index)
|
||||
{
|
||||
// Validate parameter
|
||||
if (index >= GetSessionCount())
|
||||
return NULL;
|
||||
|
||||
return m_PeerSessions[index].pSession;
|
||||
}
|
147
source/network/NetHost.h
Normal file
147
source/network/NetHost.h
Normal file
@ -0,0 +1,147 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NETHOST_H
|
||||
#define NETHOST_H
|
||||
|
||||
#include "fsm.h"
|
||||
|
||||
#include "ps/CStr.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
typedef struct _ENetPeer ENetPeer;
|
||||
typedef struct _ENetHost ENetHost;
|
||||
class CNetSession;
|
||||
class CNetHost;
|
||||
class CNetMessage;
|
||||
class ScriptInterface;
|
||||
|
||||
struct PeerSession
|
||||
{
|
||||
ENetPeer* pPeer;
|
||||
CNetSession* pSession;
|
||||
};
|
||||
|
||||
typedef std::vector<PeerSession> PeerSessionList;
|
||||
|
||||
/**
|
||||
* Wrapper around ENet host concept
|
||||
*/
|
||||
class CNetHost
|
||||
{
|
||||
NONCOPYABLE(CNetHost);
|
||||
|
||||
public:
|
||||
|
||||
CNetHost(ScriptInterface& scriptInterface);
|
||||
virtual ~CNetHost();
|
||||
|
||||
bool Create();
|
||||
bool Create(uint port, uint maxPeers);
|
||||
void Shutdown();
|
||||
|
||||
/**
|
||||
* Indicates whether the host is currently a server
|
||||
*
|
||||
* @return Boolean indicating whether the host is a server
|
||||
*/
|
||||
virtual bool IsServer() const { return false; }
|
||||
|
||||
/**
|
||||
* Returns the number of sessions for the host
|
||||
*
|
||||
* @return The number of sessions
|
||||
*/
|
||||
uint GetSessionCount() const;
|
||||
|
||||
/**
|
||||
* Returns the session object for the specified index
|
||||
*
|
||||
* @param index Index for session
|
||||
* @return Session object for index or NULL if not found
|
||||
*/
|
||||
CNetSession* GetSession(uint index);
|
||||
|
||||
/**
|
||||
* Connects to foreign host synchronously
|
||||
*
|
||||
* @param host Foreign host name
|
||||
* @param port Port on which the foreign host listens
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
bool Connect(const CStr& host, uint port);
|
||||
|
||||
/**
|
||||
* Connects to foreign host asynchronously (i.e. without waiting for the connection
|
||||
* to succeed or to time out)
|
||||
*
|
||||
* @param host Foreign host name
|
||||
* @param port Port on which the foreign host listens
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
bool ConnectAsync(const CStr& host, uint port);
|
||||
|
||||
/**
|
||||
* Disconnects session from host
|
||||
*
|
||||
* @param pSession Session representing peer
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
bool Disconnect(CNetSession* pSession);
|
||||
|
||||
/**
|
||||
* Listens for incoming connections and dispatches host events
|
||||
*/
|
||||
void Poll();
|
||||
|
||||
/**
|
||||
* Broadcast the specified message to connected clients
|
||||
*
|
||||
* @param pMessage Message to broadcast
|
||||
*/
|
||||
void Broadcast(const CNetMessage* pMessage);
|
||||
|
||||
/**
|
||||
* Send the specified message to client
|
||||
*
|
||||
* @param pMessage The message to send
|
||||
*/
|
||||
bool SendMessage(const CNetSession* pSession, const CNetMessage* pMessage);
|
||||
|
||||
protected:
|
||||
|
||||
// Allow application to handle new client connect
|
||||
virtual bool SetupSession(CNetSession* pSession) = 0;
|
||||
virtual bool HandleConnect(CNetSession* pSession) = 0;
|
||||
virtual bool HandleDisconnect(CNetSession* pSession) = 0;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Receive a message from client if available
|
||||
*/
|
||||
CNetMessage* ReceiveMessage(const CNetSession* pSession);
|
||||
|
||||
bool HandleMessageReceive(CNetMessage* pMessage, CNetSession* pSession);
|
||||
|
||||
ScriptInterface& m_ScriptInterface;
|
||||
|
||||
ENetHost* m_Host; // Represents this host
|
||||
PeerSessionList m_PeerSessions; // Session list of connected peers
|
||||
};
|
||||
|
||||
#endif // NETHOST_H
|
File diff suppressed because it is too large
Load Diff
@ -1,678 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : NetLog.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Network subsystem logging classes declarations
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef NETLOG_H
|
||||
#define NETLOG_H
|
||||
|
||||
// INCLUDES
|
||||
#include "ps/Pyrogenesis.h"
|
||||
#include "ps/ThreadUtil.h"
|
||||
#include "ps/CStr.h"
|
||||
#include "lib/timer.h"
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
|
||||
// DECLARATIONS
|
||||
typedef enum
|
||||
{
|
||||
LOG_LEVEL_ALL = 0x0000, // Lowest level possible
|
||||
LOG_LEVEL_DEBUG = 0x0001, // Informational events for app debugging
|
||||
LOG_LEVEL_INFO = 0x0002, // Useful for highlighting app progress
|
||||
LOG_LEVEL_WARN = 0x0004, // Potentially dangerous situations
|
||||
LOG_LEVEL_ERROR = 0x0008, // Error events but the app can continue
|
||||
LOG_LEVEL_FATAL = 0x0010, // Very severe errors, the app aborts
|
||||
LOG_LEVEL_OFF = 0xFFFF, // The highest level possible
|
||||
} LogLevel;
|
||||
|
||||
class CNetLogger;
|
||||
class CNetLogSink;
|
||||
|
||||
typedef std::list< CNetLogger* > LoggerList;
|
||||
typedef std::vector< CNetLogSink* > SinkList;
|
||||
|
||||
/*
|
||||
CLASS : CNetLogEvent
|
||||
DESCRIPTION : CNetLogEvent represents an object passed between
|
||||
different network logging components when a decision
|
||||
for logging is made
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CNetLogEvent
|
||||
{
|
||||
public:
|
||||
|
||||
CNetLogEvent(
|
||||
LogLevel level,
|
||||
const CStr& message,
|
||||
const CStr& loggerName );
|
||||
~CNetLogEvent( void );
|
||||
|
||||
/**
|
||||
* Returns the level of the event
|
||||
*
|
||||
* @return Event level;
|
||||
*/
|
||||
inline LogLevel GetLevel( void ) const { return m_Level; }
|
||||
|
||||
/**
|
||||
* Returns the time of the event
|
||||
*
|
||||
* @return Event time
|
||||
*/
|
||||
inline TimerUnit GetTimeStamp( void ) const { return m_TimeStamp; }
|
||||
|
||||
/**
|
||||
* Returns the name of the logger which logged the event
|
||||
*
|
||||
* @return Logger name
|
||||
*/
|
||||
inline const CStr& GetLoggerName( void ) const { return m_LoggerName; }
|
||||
|
||||
/**
|
||||
* Returns the message used when the event was initialized
|
||||
*
|
||||
* @return Event message
|
||||
*/
|
||||
inline const CStr& GetMessage( void ) const { return m_Message; }
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CNetLogEvent( const CNetLogEvent& );
|
||||
CNetLogEvent& operator=( CNetLogEvent& );
|
||||
|
||||
LogLevel m_Level; // Current level
|
||||
CStr m_LoggerName; // Logger which processed the event
|
||||
CStr m_Message; // Application message for the event
|
||||
TimerUnit m_TimeStamp; // Event logging time
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CNetLogSink
|
||||
DESCRIPTION : CNetLogSink is the basic interface for events logging
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CNetLogSink
|
||||
{
|
||||
public:
|
||||
|
||||
CNetLogSink( );
|
||||
virtual ~CNetLogSink( );
|
||||
|
||||
/**
|
||||
* Set the name of the sink
|
||||
*
|
||||
* @param name New sink name
|
||||
*/
|
||||
void SetName( const CStr& name );
|
||||
|
||||
/**
|
||||
* Retrieves the name of the sink
|
||||
*
|
||||
* @return Sink name
|
||||
*/
|
||||
inline const CStr& GetName( void ) const { return m_Name; }
|
||||
|
||||
/**
|
||||
* Set the level of the sink
|
||||
*
|
||||
* @param level New sink level
|
||||
*/
|
||||
void SetLevel( LogLevel level );
|
||||
|
||||
/**
|
||||
* Retrieves the current level of the sink
|
||||
*
|
||||
* @return Sink current level
|
||||
*/
|
||||
inline LogLevel GetLevel( void ) const { return m_Level; }
|
||||
|
||||
/**
|
||||
* Retrieves the header text
|
||||
*
|
||||
* @return The header text
|
||||
*/
|
||||
inline const CStr& GetHeader( void ) const { return m_Header; }
|
||||
|
||||
/**
|
||||
* Set header text which will be logged before an event logging
|
||||
*
|
||||
* @param header New header text
|
||||
*/
|
||||
void SetHeader( const CStr& header );
|
||||
|
||||
/**
|
||||
* Retrieves the footer text
|
||||
*
|
||||
* @return The footer text
|
||||
*/
|
||||
inline const CStr& GetFooter( void ) const { return m_Footer; }
|
||||
|
||||
/**
|
||||
* Set footer text which will be logged after an event logging
|
||||
*
|
||||
* @param footer New footer text
|
||||
*/
|
||||
void SetFooter( const CStr& footer );
|
||||
|
||||
/**
|
||||
* Activates the sink
|
||||
*/
|
||||
void Activate( void );
|
||||
|
||||
/**
|
||||
* Closes the sink and release any resources
|
||||
*/
|
||||
void Close( void );
|
||||
|
||||
/**
|
||||
* Check if the level of the event is greater than or equal to sink level
|
||||
* and if it succeeds it performs the actual logging of the event.
|
||||
*
|
||||
* @param event Event to log
|
||||
*/
|
||||
void DoSink( const CNetLogEvent& event );
|
||||
|
||||
/**
|
||||
* For each event from the passed array, check if its level is greater than
|
||||
* or equal to sink level and performs the logging for it.
|
||||
*
|
||||
* @param pEvents List of events to log
|
||||
* @param eventCount The number of events in pEvents list
|
||||
*/
|
||||
void DoBulkSink( const CNetLogEvent* pEvents, size_t eventCount );
|
||||
|
||||
/**
|
||||
* Check if the sink can log the specified event
|
||||
*
|
||||
* @param event Event to check
|
||||
* @return true if the event can be logged,
|
||||
* false otherwise
|
||||
*/
|
||||
virtual bool TestEvent( const CNetLogEvent& event );
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Activates the sink object
|
||||
*/
|
||||
virtual void OnActivate( void );
|
||||
|
||||
/**
|
||||
* Writes a header into the sink
|
||||
*/
|
||||
virtual void WriteHeader( void );
|
||||
|
||||
/**
|
||||
* Writes a footer into the sink
|
||||
*/
|
||||
virtual void WriteFooter( void );
|
||||
|
||||
/**
|
||||
* Writes a string message to the logging output
|
||||
*
|
||||
* @param message The message to log
|
||||
*/
|
||||
virtual void Write( const CStr& message ) = 0;
|
||||
|
||||
/**
|
||||
* Writes a single character to the logging output
|
||||
*
|
||||
* @param c The character to log
|
||||
*/
|
||||
virtual void Write( char c ) = 0;
|
||||
|
||||
/**
|
||||
* This is called by Close method. It can be overriden by specialized sinks
|
||||
* if any resources needs to be released on close.
|
||||
*/
|
||||
virtual void OnClose( void );
|
||||
|
||||
/**
|
||||
* This method is called by DoSink and DoBulkSink and it must be
|
||||
* implemented by specialized sinks to perform actual logging
|
||||
*
|
||||
* @param event Event to log
|
||||
*/
|
||||
virtual void Sink( const CNetLogEvent& event ) = 0;
|
||||
|
||||
LogLevel m_Level; // Current level
|
||||
CMutex m_Mutex; // Multithreading synchronization object
|
||||
CStr m_Header; // Header text
|
||||
CStr m_Footer; // Footer text
|
||||
CStr m_Name; // Sink name
|
||||
bool m_Closed; // Indicates whether the sink is closed
|
||||
bool m_Active; // Indicates whether the sink is active
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CNetLogSink( const CNetLogSink& );
|
||||
CNetLogSink& operator=( const CNetLogSink& );
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CNetLogFileSink
|
||||
DESCRIPTION : Log network events to a file
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CNetLogFileSink : public CNetLogSink
|
||||
{
|
||||
public:
|
||||
|
||||
CNetLogFileSink( void );
|
||||
CNetLogFileSink( const fs::wpath& filename );
|
||||
CNetLogFileSink( const fs::wpath& filename, bool append );
|
||||
~CNetLogFileSink( void );
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Activates the sink object and opens the file specified in constructor
|
||||
*/
|
||||
virtual void OnActivate( void );
|
||||
|
||||
/**
|
||||
* Closes the log file
|
||||
*/
|
||||
virtual void OnClose( void );
|
||||
|
||||
/**
|
||||
* Writes the event to the log file if opened
|
||||
*
|
||||
* @param event Event to log
|
||||
*/
|
||||
virtual void Sink( const CNetLogEvent& event );
|
||||
|
||||
/**
|
||||
* Writes the message passed as parameter to file
|
||||
*
|
||||
* @param message The message to log
|
||||
*/
|
||||
virtual void Write( const CStr& message );
|
||||
|
||||
/**
|
||||
* Writes the character passed as parameter to file
|
||||
*
|
||||
* @param c The character to log
|
||||
*/
|
||||
virtual void Write( char c );
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CNetLogFileSink( const CNetLogFileSink& );
|
||||
CNetLogFileSink& operator=( const CNetLogFileSink& );
|
||||
|
||||
/**
|
||||
* Open the file where logging goes. The header text will be written each
|
||||
* time the file is opened. If append parameter is true, then the file may
|
||||
* contain the header many times.
|
||||
*
|
||||
* @param filename The path to the log file
|
||||
* @param append Indicates whether logging should append to
|
||||
* the file or truncate the file
|
||||
*/
|
||||
void OpenFile( const fs::wpath& fileName, bool append );
|
||||
|
||||
/**
|
||||
* Close the previously opened file. The footer text will be written each time
|
||||
* the file is closed. If the file was opened for appending, the footer might
|
||||
* appera many times.
|
||||
*/
|
||||
void CloseFile( void );
|
||||
|
||||
std::ofstream m_File; // The log file handle
|
||||
fs::wpath m_FileName; // The name of the log file
|
||||
bool m_Append; // Logging should append to file
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CNetLogConsoleSink
|
||||
DESCRIPTION : Log network events to the game console
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CNetLogConsoleSink : public CNetLogSink
|
||||
{
|
||||
public:
|
||||
|
||||
CNetLogConsoleSink( void );
|
||||
~CNetLogConsoleSink( void );
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Activates the sink object and the game console
|
||||
*/
|
||||
virtual void OnActivate( void );
|
||||
|
||||
/**
|
||||
* Toggle off game console
|
||||
*/
|
||||
virtual void OnClose( void );
|
||||
|
||||
/**
|
||||
* Writes the event to the game console if active
|
||||
*
|
||||
* @param event Event to log
|
||||
*/
|
||||
virtual void Sink( const CNetLogEvent& event );
|
||||
|
||||
/**
|
||||
* Writes the message passed as parameter to game console
|
||||
*
|
||||
* @param message The message to log
|
||||
*/
|
||||
virtual void Write( const CStr& message );
|
||||
|
||||
/**
|
||||
* Writes the character passed as parameter to game console
|
||||
*
|
||||
* @param c The character to log
|
||||
*/
|
||||
virtual void Write( char c );
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CNetLogConsoleSink( const CNetLogConsoleSink& );
|
||||
CNetLogConsoleSink& operator=( const CNetLogConsoleSink& );
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CNetLogger
|
||||
DESCRIPTION : CNetLogger serves for logging messages for network subsytem.
|
||||
It contains methods for logging at different levels.
|
||||
NOTES : CNetLogManager is used to obtain an instance of a logger.
|
||||
*/
|
||||
|
||||
class CNetLogger
|
||||
{
|
||||
public:
|
||||
|
||||
CNetLogger( const CStr& name );
|
||||
virtual ~CNetLogger( void );
|
||||
|
||||
bool IsDebugEnabled ( void ) const;
|
||||
bool IsInfoEnabled ( void ) const;
|
||||
bool IsWarnEnabled ( void ) const;
|
||||
bool IsErrorEnabled ( void ) const;
|
||||
bool IsFatalEnabled ( void ) const;
|
||||
|
||||
void Debug ( const CStr& message );
|
||||
void Warn ( const CStr& message );
|
||||
void Info ( const CStr& message );
|
||||
void Error ( const CStr& message );
|
||||
void Fatal ( const CStr& message );
|
||||
|
||||
void DebugFormat ( const char* pFormat, ... ) PRINTF_ARGS(2);
|
||||
void WarnFormat ( const char* pFormat, ... ) PRINTF_ARGS(2);
|
||||
void InfoFormat ( const char* pFormat, ... ) PRINTF_ARGS(2);
|
||||
void ErrorFormat ( const char* pFormat, ... ) PRINTF_ARGS(2);
|
||||
void FatalFormat ( const char* pFormat, ... ) PRINTF_ARGS(2);
|
||||
|
||||
/**
|
||||
* Retrieves the name of the logger
|
||||
*
|
||||
* @return Logger name
|
||||
*/
|
||||
const CStr& GetName( void ) const { return m_Name; }
|
||||
|
||||
/**
|
||||
* Retrieves the level of the logger
|
||||
*
|
||||
* @return Logger level
|
||||
*/
|
||||
LogLevel GetLevel( void ) const { return m_Level; }
|
||||
|
||||
/**
|
||||
* Set the level for the logger
|
||||
*
|
||||
* @param level New logger level
|
||||
*/
|
||||
void SetLevel( LogLevel level );
|
||||
|
||||
/**
|
||||
* Attaches a new sink to the list of sinks. The sink will be activated.
|
||||
*
|
||||
* @param pSink The sink to add
|
||||
*/
|
||||
void AddSink( CNetLogSink* pSink );
|
||||
|
||||
/**
|
||||
* Removes the specified sink from the list of attached sinks. The sink
|
||||
* will not be closed.
|
||||
*
|
||||
* @param pSink The sink to remove
|
||||
* @return The removed sink or NULL if not found
|
||||
*/
|
||||
CNetLogSink* RemoveSink( CNetLogSink* pSink );
|
||||
|
||||
/**
|
||||
* Remove the named sink passed as parameter. The sink will not be closed.
|
||||
*
|
||||
* @param name The name of sink to remove
|
||||
* @return The removed sink or NULL if not found
|
||||
*/
|
||||
CNetLogSink* RemoveSink( const CStr& name );
|
||||
|
||||
/**
|
||||
* Removes all attached sinks
|
||||
*
|
||||
*/
|
||||
void RemoveAllSinks( void );
|
||||
|
||||
/**
|
||||
* Retrieve the number of attached sinks
|
||||
*
|
||||
* @return The number of sink objects
|
||||
*/
|
||||
size_t GetSinkCount( void );
|
||||
|
||||
/**
|
||||
* Retrieves the sink by its index
|
||||
*
|
||||
* @param index The index of the sink
|
||||
* @return NULL if index is out of boundaries or
|
||||
* the sink at the specified index
|
||||
*/
|
||||
CNetLogSink* GetSink( size_t index );
|
||||
|
||||
/**
|
||||
* Retrieves a sink by its name
|
||||
*
|
||||
* @param name The name of the sink
|
||||
* @return NULL if the sink does not exists or
|
||||
* the sink with the specified name
|
||||
*/
|
||||
CNetLogSink* GetSink( const CStr& name );
|
||||
|
||||
/**
|
||||
* Helper function used to retrieve local date time in a string
|
||||
*/
|
||||
static void GetStringDateTime( CStr& str );
|
||||
|
||||
/**
|
||||
* Helper function used to retrieve local time in a string
|
||||
*/
|
||||
static void GetStringTime( CStr& str );
|
||||
|
||||
/**
|
||||
* Helper function used to retrieve the current timestamp in a string
|
||||
*/
|
||||
static void GetStringTimeStamp( CStr& str );
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CNetLogger( const CNetLogger& );
|
||||
CNetLogger& operator=( const CNetLogger& );
|
||||
|
||||
/**
|
||||
* Dispatch the event passed as parameter to all sinks
|
||||
*
|
||||
* @param event The event to log
|
||||
*/
|
||||
void CallSinks( const CNetLogEvent& event );
|
||||
|
||||
CMutex m_Mutex; // Multithread synchronization object
|
||||
SinkList m_Sinks; // Holds the list of sink objects
|
||||
LogLevel m_Level; // Logger level
|
||||
CStr m_Name; // Logger name
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CNetLogManager
|
||||
DESCRIPTION : CNetLogManager serves clients requesting log instances
|
||||
NOTES : The GetLogger method can be used to retrieve a log
|
||||
*/
|
||||
|
||||
class CNetLogManager
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Shutdown the log manager, closes all sinks in the loggers.
|
||||
*
|
||||
*/
|
||||
static void Shutdown( void );
|
||||
|
||||
/**
|
||||
* Retrieves a named logger. If the logger does not exist, it is created.
|
||||
*
|
||||
* @param name Logger name
|
||||
* @return A logger object
|
||||
*/
|
||||
static CNetLogger* GetLogger( const CStr& name );
|
||||
|
||||
/**
|
||||
* Return the list of all defined loggers.
|
||||
*
|
||||
* @return The list of all loggers
|
||||
*/
|
||||
static const LoggerList& GetAllLoggers( void );
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CNetLogManager( void );
|
||||
~CNetLogManager( void );
|
||||
CNetLogManager( const CNetLogManager& );
|
||||
CNetLogManager& operator=( const CNetLogManager& );
|
||||
|
||||
static LoggerList m_Loggers; // Holds the list of loggers
|
||||
};
|
||||
|
||||
// TODO: Replace with better access to log manager
|
||||
#define START_LOGGER( sinkName, sinkType )\
|
||||
CNetLogger *pLogger = CNetLogManager::GetLogger( "net.log" );\
|
||||
if ( pLogger )\
|
||||
{\
|
||||
CNetLogSink* pSink = pLogger->GetSink( sinkName );\
|
||||
if ( !pSink )\
|
||||
{\
|
||||
pSink = new sinkType();\
|
||||
if ( pSink )\
|
||||
{\
|
||||
CStr startTime;\
|
||||
CNetLogger::GetStringDateTime( startTime );\
|
||||
CStr header = "***************************************************\n";\
|
||||
header += "LOG STARTED: ";\
|
||||
header += startTime;\
|
||||
header += "\n";\
|
||||
header += "Timestamps are in seconds since engine startup\n";\
|
||||
pSink->SetHeader( header );\
|
||||
pSink->SetName( sinkName );\
|
||||
if ( strcmp(sinkName, "sink.console") == 0 )\
|
||||
pSink->SetLevel( LOG_LEVEL_ERROR );\
|
||||
else\
|
||||
pSink->SetLevel( LOG_LEVEL_INFO );\
|
||||
pLogger->AddSink( pSink );\
|
||||
}\
|
||||
}
|
||||
|
||||
#define END_LOGGER\
|
||||
}
|
||||
|
||||
#define NET_LOG( parameter )\
|
||||
{\
|
||||
START_LOGGER( "sink.file", CNetLogFileSink )\
|
||||
pLogger->Info( parameter );\
|
||||
END_LOGGER\
|
||||
}\
|
||||
{\
|
||||
START_LOGGER( "sink.console", CNetLogConsoleSink )\
|
||||
pLogger->Info( parameter );\
|
||||
END_LOGGER\
|
||||
}
|
||||
|
||||
#define NET_LOG2( format, parameter )\
|
||||
{\
|
||||
START_LOGGER( "sink.file", CNetLogFileSink )\
|
||||
pLogger->InfoFormat( format, parameter );\
|
||||
END_LOGGER\
|
||||
}\
|
||||
{\
|
||||
START_LOGGER( "sink.console", CNetLogConsoleSink )\
|
||||
pLogger->InfoFormat( format, parameter );\
|
||||
END_LOGGER\
|
||||
}
|
||||
|
||||
#define NET_LOG3( format, parameter1, parameter2 )\
|
||||
{\
|
||||
START_LOGGER( "sink.file", CNetLogFileSink )\
|
||||
pLogger->InfoFormat( format, parameter1, parameter2 );\
|
||||
END_LOGGER\
|
||||
}\
|
||||
{\
|
||||
START_LOGGER( "sink.console", CNetLogConsoleSink )\
|
||||
pLogger->InfoFormat( format, parameter1, parameter2 );\
|
||||
END_LOGGER\
|
||||
}
|
||||
|
||||
#define NET_LOG4( format, parameter1, parameter2, parameter3 )\
|
||||
{\
|
||||
START_LOGGER( "sink.file", CNetLogFileSink )\
|
||||
pLogger->InfoFormat( format, parameter1, parameter2, parameter3 );\
|
||||
END_LOGGER\
|
||||
}\
|
||||
{\
|
||||
START_LOGGER( "sink.console", CNetLogConsoleSink )\
|
||||
pLogger->InfoFormat( format, parameter1, parameter2, parameter3 );\
|
||||
END_LOGGER\
|
||||
}
|
||||
|
||||
#endif // NETLOG_H
|
||||
|
@ -25,12 +25,15 @@
|
||||
|
||||
// INCLUDES
|
||||
#include "precompiled.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/CConsole.h"
|
||||
#include "simulation/Simulation.h"
|
||||
|
||||
#include "NetServer.h"
|
||||
|
||||
#include "NetJsEvents.h"
|
||||
#include "NetSession.h"
|
||||
#include "NetServer.h"
|
||||
|
||||
#include "ps/CConsole.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/GameAttributes.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
|
||||
#define LOG_CATEGORY L"net"
|
||||
@ -42,8 +45,8 @@ CNetServer* g_NetServer = NULL;
|
||||
// Name: CNetServer()
|
||||
// Desc: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CNetServer::CNetServer( CGame *pGame, CGameAttributes *pGameAttributes )
|
||||
: m_JsSessions( &m_IDSessions )
|
||||
CNetServer::CNetServer( ScriptInterface& scriptInterface, CGame *pGame, CGameAttributes *pGameAttributes )
|
||||
: CNetHost( scriptInterface ), m_JsSessions( &m_IDSessions )
|
||||
{
|
||||
m_ServerTurnManager = NULL;
|
||||
|
||||
@ -125,8 +128,7 @@ bool CNetServer::SetupSession( CNetSession* pSession )
|
||||
// Validate parameters
|
||||
if ( !pSession ) return false;
|
||||
|
||||
FsmActionCtx* pContext = new FsmActionCtx;
|
||||
if ( !pContext ) return false;
|
||||
FsmActionCtx* pContext = pSession->GetFsmActionCtx();
|
||||
|
||||
pContext->pHost = this;
|
||||
pContext->pSession = pSession;
|
||||
@ -721,7 +723,7 @@ void CNetServer::AttributeUpdate(
|
||||
|
||||
CNetServer* pServer = ( CNetServer* )pData;
|
||||
|
||||
g_Console->InsertMessage( L"AttributeUpdate: %ls = \"%ls\"", name.c_str(), newValue.c_str() );
|
||||
LOGMESSAGE( L"AttributeUpdate: %ls = \"%ls\"", name.c_str(), newValue.c_str() );
|
||||
|
||||
CGameSetupMessage gameSetup;
|
||||
gameSetup.m_Values.resize( 1 );
|
||||
@ -745,7 +747,7 @@ void CNetServer::PlayerAttributeUpdate(
|
||||
|
||||
CNetServer* pServer = ( CNetServer* )pData;
|
||||
|
||||
g_Console->InsertMessage( L"PlayerAttributeUpdate(%ld): %ls = \"%ls\"", pPlayer->GetPlayerID(), name.c_str(), newValue.c_str() );
|
||||
LOGMESSAGE( L"PlayerAttributeUpdate(%ld): %ls = \"%ls\"", pPlayer->GetPlayerID(), name.c_str(), newValue.c_str() );
|
||||
|
||||
CPlayerConfigMessage* pNewMessage = new CPlayerConfigMessage;
|
||||
if ( !pNewMessage ) return;
|
||||
@ -778,7 +780,7 @@ void CNetServer::PlayerSlotAssignment(
|
||||
|
||||
pServer->BuildPlayerSlotAssignmentMessage( &assignPlayerSlot, pPlayerSlot );
|
||||
|
||||
g_Console->InsertMessage( L"Player Slot Assignment: %hs\n", assignPlayerSlot.ToString().c_str() );
|
||||
LOGMESSAGE( L"Player Slot Assignment: %hs\n", assignPlayerSlot.ToString().c_str() );
|
||||
|
||||
pServer->Broadcast( &assignPlayerSlot );
|
||||
}
|
||||
|
@ -28,10 +28,10 @@
|
||||
|
||||
// INCLUDES
|
||||
#include "Network.h"
|
||||
#include "NetHost.h"
|
||||
#include "NetSession.h"
|
||||
#include "NetTurnManager.h"
|
||||
#include "scripting/ScriptableObject.h"
|
||||
#include "ps/GameAttributes.h"
|
||||
#include "ps/scripting/JSMap.h"
|
||||
#include "ps/Player.h"
|
||||
#include "ps/Game.h"
|
||||
@ -50,6 +50,8 @@
|
||||
#define DEFAULT_WELCOME_MESSAGE L"Noname Server Welcome Message"
|
||||
#define DEFAULT_HOST_PORT 0x5073
|
||||
|
||||
class CGameAttributes;
|
||||
|
||||
enum NetServerState
|
||||
{
|
||||
// We haven't opened the port yet, we're just setting some stuff up.
|
||||
@ -102,7 +104,7 @@ class CNetServer : public CNetHost,
|
||||
NONCOPYABLE(CNetServer);
|
||||
public:
|
||||
|
||||
CNetServer( CGame* pGame, CGameAttributes* pGameAttributes );
|
||||
CNetServer( ScriptInterface& scriptInterface, CGame* pGame, CGameAttributes* pGameAttributes );
|
||||
virtual ~CNetServer( void );
|
||||
|
||||
bool Start ( JSContext *pContext, uintN argc, jsval *argv );
|
||||
@ -246,9 +248,10 @@ protected:
|
||||
public:
|
||||
CGame* m_Game; // Pointer to actual game
|
||||
|
||||
private:
|
||||
|
||||
protected:
|
||||
CGameAttributes* m_GameAttributes; // Stores game attributes
|
||||
|
||||
private:
|
||||
CJSMap< IDSessionMap > m_JsSessions;
|
||||
|
||||
/*
|
||||
|
@ -15,477 +15,37 @@
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : NetSession.cpp
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Network session class implementation
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// INCLUDES
|
||||
#include "precompiled.h"
|
||||
#include "NetSession.h"
|
||||
#include "NetLog.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
|
||||
// DECLARATIONS
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: CNetHost()
|
||||
// Desc: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CNetHost::CNetHost( void )
|
||||
{
|
||||
m_Host = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ~CNetHost()
|
||||
// Desc: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CNetHost::~CNetHost( void )
|
||||
{
|
||||
// Release host
|
||||
if ( m_Host ) enet_host_destroy( m_Host );
|
||||
|
||||
m_Host = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Create()
|
||||
// Desc: Creates a client host
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::Create( void )
|
||||
{
|
||||
// Create ENet host
|
||||
m_Host = enet_host_create( NULL, 1, 0, 0 );
|
||||
if ( !m_Host ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Create()
|
||||
// Desc: Creates a server host
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::Create( uint port, uint maxPeers )
|
||||
{
|
||||
ENetAddress addr;
|
||||
|
||||
// Bind to default host
|
||||
addr.host = ENET_HOST_ANY;
|
||||
addr.port = port;
|
||||
|
||||
// Create ENet server
|
||||
m_Host = enet_host_create( &addr, maxPeers, 0, 0 );
|
||||
if ( !m_Host ) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Shutdown()
|
||||
// Desc: Shuts down network server and releases any resources
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNetHost::Shutdown( void )
|
||||
{
|
||||
// Destroy server
|
||||
if ( m_Host ) enet_host_destroy( m_Host );
|
||||
|
||||
// Disconnect and release each peer
|
||||
PeerSessionList::iterator it = m_PeerSessions.begin();
|
||||
for ( ; it != m_PeerSessions.end(); it++ )
|
||||
{
|
||||
if ( !it->pSession ) continue;
|
||||
|
||||
Disconnect( it->pSession );
|
||||
|
||||
delete it->pSession;
|
||||
}
|
||||
|
||||
m_PeerSessions.clear();
|
||||
|
||||
m_Host = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Connect()
|
||||
// Desc: Connects to the specified remote host
|
||||
// Note: Only clients use this method for connection to server
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::Connect( const CStr& host, uint port )
|
||||
{
|
||||
ENetEvent event;
|
||||
ENetAddress addr;
|
||||
PeerSession item;
|
||||
|
||||
debug_assert( m_Host );
|
||||
|
||||
// Bind to specified host
|
||||
addr.port = port;
|
||||
if ( enet_address_set_host( &addr, host.c_str() ) < 0 ) return false;
|
||||
|
||||
// Initiate connection, allocate one channel
|
||||
ENetPeer* pPeer = enet_host_connect( m_Host, &addr, 1 );
|
||||
if ( !pPeer ) return false;
|
||||
|
||||
// Wait 3 seconds for the connection to succeed
|
||||
if ( enet_host_service( m_Host, &event, 5000 ) > 0 &&
|
||||
event.type == ENET_EVENT_TYPE_CONNECT )
|
||||
{
|
||||
// Connection succeeded
|
||||
CNetSession* pNewSession = new CNetSession( this, event.peer );
|
||||
if ( !pNewSession ) return false;
|
||||
|
||||
if ( !SetupSession( pNewSession ) ) return false;
|
||||
|
||||
NET_LOG3( "Successfully connected to server %s:%d succeeded", host.c_str(), port );
|
||||
|
||||
// Successfully handled?
|
||||
if ( !HandleConnect( pNewSession ) )
|
||||
{
|
||||
delete pNewSession;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the only server session
|
||||
item.pPeer = event.peer;
|
||||
item.pSession = pNewSession;
|
||||
m_PeerSessions.push_back( item );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NET_LOG3( "Connection to server %s:%d failed", host.c_str(), port );
|
||||
|
||||
// 3 seconds are up or a host was disconnected
|
||||
enet_peer_reset( pPeer );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Disconnect()
|
||||
// Desc: Disconnects the specified session from the host
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::Disconnect( CNetSession* pSession )
|
||||
{
|
||||
ENetEvent event;
|
||||
|
||||
// Validate parameters
|
||||
if ( !pSession ) return false;
|
||||
|
||||
debug_assert( m_Host );
|
||||
debug_assert( pSession->m_Peer );
|
||||
|
||||
// Disconnect peer
|
||||
enet_peer_disconnect( pSession->m_Peer, 0 );
|
||||
|
||||
// Allow up to 3 seconds for the disconnect to succeed
|
||||
while ( enet_host_service( m_Host, &event, 5000 ) > 0 )
|
||||
{
|
||||
switch ( event.type )
|
||||
{
|
||||
case ENET_EVENT_TYPE_RECEIVE:
|
||||
|
||||
// Drop any received packets
|
||||
enet_packet_destroy( event.packet );
|
||||
break;
|
||||
|
||||
case ENET_EVENT_TYPE_DISCONNECT:
|
||||
|
||||
// Disconnect received for peer
|
||||
if ( !HandleDisconnect( pSession ) ) return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect attempt didn't succeed, force connection down
|
||||
enet_peer_reset( pSession->m_Peer );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ProcessEvents()
|
||||
// Desc: Wait for events and shuttles packets between the host and its peers
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::Poll( void )
|
||||
{
|
||||
ENetEvent event;
|
||||
CNetSession* pSession = NULL;
|
||||
PeerSession item;
|
||||
PeerSessionList::iterator it;
|
||||
|
||||
debug_assert( m_Host );
|
||||
|
||||
// Poll host for events
|
||||
while ( enet_host_service( m_Host, &event, 0 ) > 0 )
|
||||
{
|
||||
// Handle occured event
|
||||
switch( event.type )
|
||||
{
|
||||
case ENET_EVENT_TYPE_CONNECT:
|
||||
|
||||
// A new client has connected, handle it
|
||||
pSession = new CNetSession( this, event.peer );
|
||||
if ( !pSession ) return false;
|
||||
|
||||
// Setup new session
|
||||
if ( !SetupSession( pSession ) ) return false;
|
||||
|
||||
NET_LOG3( "A new client connected from %x:%u", event.peer->address.host, event.peer->address.port );
|
||||
|
||||
// Successfully handled?
|
||||
if ( !HandleConnect( pSession ) ) return false;
|
||||
|
||||
event.peer->data = pSession;
|
||||
|
||||
// Add new item to internal list
|
||||
item.pPeer = event.peer;
|
||||
item.pSession = pSession;
|
||||
m_PeerSessions.push_back( item );
|
||||
|
||||
break;
|
||||
|
||||
case ENET_EVENT_TYPE_DISCONNECT:
|
||||
|
||||
// Client has disconnected, handle it
|
||||
it = m_PeerSessions.begin();;
|
||||
for ( ; it != m_PeerSessions.end(); it++ )
|
||||
{
|
||||
// Is this our session?
|
||||
if ( it->pPeer == event.peer )
|
||||
{
|
||||
NET_LOG2( "%p disconnected", event.peer->data );
|
||||
|
||||
// Successfully handled?
|
||||
if ( !HandleDisconnect( it->pSession ) ) return false;
|
||||
|
||||
m_PeerSessions.erase( it );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ENET_EVENT_TYPE_RECEIVE:
|
||||
|
||||
// A new data packet was received from client, handle message
|
||||
it = m_PeerSessions.begin();
|
||||
for ( ; it != m_PeerSessions.end(); it++ )
|
||||
{
|
||||
// Is this our session?
|
||||
if ( it->pPeer == event.peer )
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
// Create message from raw data
|
||||
CNetMessage* pNewMessage = CNetMessageFactory::CreateMessage( event.packet->data, event.packet->dataLength, g_Game->GetSimulation2()->GetScriptInterface() );
|
||||
if ( pNewMessage )
|
||||
{
|
||||
NET_LOG4( "Message %s of size %lu was received from %p", pNewMessage->ToString().c_str(), (unsigned long)pNewMessage->GetSerializedLength(), event.peer->data );
|
||||
|
||||
ok = HandleMessageReceive( pNewMessage, it->pSession );
|
||||
|
||||
delete pNewMessage;
|
||||
}
|
||||
|
||||
// Done using the packet
|
||||
enet_packet_destroy( event.packet );
|
||||
|
||||
if (! ok)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: Broadcast()
|
||||
// Desc: Broadcast the specified message to connected clients
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNetHost::Broadcast( const CNetMessage* pMessage )
|
||||
{
|
||||
// Validate parameters
|
||||
if ( !pMessage ) return;
|
||||
|
||||
// Loop through the list of sessions and send the message to each
|
||||
for ( uint i = 0; i < GetSessionCount(); i++ )
|
||||
{
|
||||
CNetSession* pCurrSession = GetSession( i );
|
||||
if ( !pCurrSession ) continue;
|
||||
|
||||
SendMessage( pCurrSession, pMessage );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SendMessage()
|
||||
// Desc: Sends the specified message to peer
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::SendMessage(
|
||||
const CNetSession* pSession,
|
||||
const CNetMessage* pMessage )
|
||||
{
|
||||
// Validate parameters
|
||||
if ( !pMessage || !pSession ) return false;
|
||||
|
||||
debug_assert( pSession->m_Peer );
|
||||
debug_assert( m_Host );
|
||||
|
||||
size_t size = pMessage->GetSerializedLength();
|
||||
debug_assert( size );
|
||||
|
||||
// Adjust buffer for message
|
||||
m_Buffer.resize( size );
|
||||
|
||||
// Save message to internal buffer
|
||||
pMessage->Serialize( &m_Buffer[0] );
|
||||
|
||||
// Create a reliable packet
|
||||
ENetPacket* pPacket = enet_packet_create( &m_Buffer[0], size, ENET_PACKET_FLAG_RELIABLE );
|
||||
if ( !pPacket ) return false;
|
||||
|
||||
// Let ENet send the message to peer
|
||||
if ( enet_peer_send( pSession->m_Peer, ENET_DEFAULT_CHANNEL, pPacket ) < 0 )
|
||||
{
|
||||
// ENet failed to send the packet
|
||||
NET_LOG( "Failed to send ENet packet to peer" );
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
NET_LOG4( "Message %s of size %lu was sent to %p",
|
||||
pMessage->ToString().c_str(), (unsigned long)size, pSession->m_Peer->data );
|
||||
}
|
||||
|
||||
enet_host_flush( m_Host );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ReceiveMessage()
|
||||
// Desc: Receives a message from client if incoming packets are available
|
||||
//-----------------------------------------------------------------------------
|
||||
CNetMessage* CNetHost::ReceiveMessage( const CNetSession* pSession )
|
||||
{
|
||||
// Validate parameters
|
||||
if ( !pSession ) return NULL;
|
||||
|
||||
debug_assert( pSession->m_Peer );
|
||||
|
||||
// Let ENet receive a message from peer
|
||||
ENetPacket* pPacket = enet_peer_receive( pSession->m_Peer, ENET_DEFAULT_CHANNEL );
|
||||
if ( !pPacket ) return NULL;
|
||||
|
||||
// Create new message
|
||||
return CNetMessageFactory::CreateMessage( pPacket->data, pPacket->dataLength, g_Game->GetSimulation2()->GetScriptInterface() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetupSession()
|
||||
// Desc: Setup new session upon creation
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::SetupSession( CNetSession* UNUSED(pSession) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: HandleConnect()
|
||||
// Desc: Allow application to handle client connect
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::HandleConnect( CNetSession* UNUSED(pSession) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: HandleDisconnect()
|
||||
// Desc: Allow application to handle client disconnect
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::HandleDisconnect( CNetSession* UNUSED(pSession) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: HandleMessageReceive()
|
||||
// Desc: Allow application to handle message recive
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNetHost::HandleMessageReceive(
|
||||
CNetMessage* pMessage,
|
||||
CNetSession* pSession )
|
||||
{
|
||||
// Validate parameters
|
||||
if ( !pSession || !pMessage ) return false;
|
||||
|
||||
// Update FSM
|
||||
return pSession->Update( pMessage->GetType(), pMessage );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: GetSessionCount()
|
||||
// Desc: Returns the number of sessions the host manages
|
||||
//-----------------------------------------------------------------------------
|
||||
uint CNetHost::GetSessionCount( void ) const
|
||||
{
|
||||
return ( uint )m_PeerSessions.size();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: GetSession()
|
||||
// Desc: Rteurns the session for the index
|
||||
//-----------------------------------------------------------------------------
|
||||
CNetSession* CNetHost::GetSession( uint index )
|
||||
{
|
||||
// Validate parameter
|
||||
if ( index >= GetSessionCount() ) return NULL;
|
||||
|
||||
return m_PeerSessions[ index ].pSession;
|
||||
};
|
||||
static const uint INVALID_SESSION = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: CNetSession()
|
||||
// Desc: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CNetSession::CNetSession( CNetHost* pHost, ENetPeer* pPeer )
|
||||
CNetSession::CNetSession(CNetHost* pHost, ENetPeer* pPeer)
|
||||
{
|
||||
m_Host = pHost;
|
||||
m_Peer = pPeer;
|
||||
m_ID = INVALID_SESSION;
|
||||
m_PlayerSlot = NULL;
|
||||
m_Host = pHost;
|
||||
m_Peer = pPeer;
|
||||
m_ID = INVALID_SESSION;
|
||||
m_PlayerSlot = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: ~CNetSession()
|
||||
// Desc: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CNetSession::~CNetSession( void )
|
||||
CNetSession::~CNetSession()
|
||||
{
|
||||
// Release any resources
|
||||
//if ( m_Host ) enet_host_destroy( m_Host );
|
||||
|
||||
//m_Host = NULL;
|
||||
m_Peer = NULL;
|
||||
m_Peer = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name: SetName()
|
||||
// Desc: Set a new name for the session
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNetSession::SetName( const CStr& name )
|
||||
void CNetSession::SetName(const CStr& name)
|
||||
{
|
||||
m_Name = name;
|
||||
}
|
||||
@ -494,7 +54,7 @@ void CNetSession::SetName( const CStr& name )
|
||||
// Name: SetID()
|
||||
// Desc: Set new ID for this session
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNetSession::SetID( uint ID )
|
||||
void CNetSession::SetID(uint ID)
|
||||
{
|
||||
m_ID = ID;
|
||||
}
|
||||
@ -503,7 +63,7 @@ void CNetSession::SetID( uint ID )
|
||||
// Name: SetPlayerSlot()
|
||||
// Desc: Set the player slot for this session
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNetSession::SetPlayerSlot( CPlayerSlot* pPlayerSlot )
|
||||
void CNetSession::SetPlayerSlot(CPlayerSlot* pPlayerSlot)
|
||||
{
|
||||
m_PlayerSlot = pPlayerSlot;
|
||||
}
|
||||
@ -512,10 +72,10 @@ void CNetSession::SetPlayerSlot( CPlayerSlot* pPlayerSlot )
|
||||
// Name: ScriptingInit()
|
||||
// Desc:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNetSession::ScriptingInit( void )
|
||||
void CNetSession::ScriptingInit()
|
||||
{
|
||||
AddProperty( L"id", &CNetSession::m_ID );
|
||||
AddProperty( L"name", &CNetSession::m_Name );
|
||||
AddProperty(L"id", &CNetSession::m_ID);
|
||||
AddProperty(L"name", &CNetSession::m_Name);
|
||||
|
||||
CJSObject<CNetSession>::ScriptingInit( "NetSession" );
|
||||
CJSObject<CNetSession>::ScriptingInit("NetSession");
|
||||
}
|
||||
|
@ -15,170 +15,39 @@
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
*-----------------------------------------------------------------------------
|
||||
* FILE : NetSession.h
|
||||
* PROJECT : 0 A.D.
|
||||
* DESCRIPTION : Network session class interface file
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef NETSESSION_H
|
||||
#define NETSESSION_H
|
||||
|
||||
// INCLUDES
|
||||
#include "Network.h"
|
||||
#include "ps/GameAttributes.h"
|
||||
#include "fsm.h"
|
||||
#include <enet/enet.h>
|
||||
#include "scripting/ScriptableObject.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
// DECLARATIONS
|
||||
#define INVALID_SESSION 0
|
||||
#define ENET_DEFAULT_CHANNEL 0
|
||||
|
||||
class CNetSession;
|
||||
class CPlayerSlot;
|
||||
class CNetHost;
|
||||
class CNetSession;
|
||||
typedef struct _ENetPeer ENetPeer;
|
||||
|
||||
typedef struct
|
||||
struct FsmActionCtx
|
||||
{
|
||||
ENetPeer* pPeer;
|
||||
CNetSession* pSession;
|
||||
|
||||
} PeerSession;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CNetHost* pHost;
|
||||
CNetSession* pSession;
|
||||
|
||||
} FsmActionCtx;
|
||||
|
||||
typedef std::vector< PeerSession > PeerSessionList;
|
||||
|
||||
/*
|
||||
CLASS : CNetHost
|
||||
DESCRIPTION : CNetHost is a wrapper around ENet host concept
|
||||
NOTES :
|
||||
*/
|
||||
|
||||
class CNetHost
|
||||
{
|
||||
NONCOPYABLE(CNetHost);
|
||||
|
||||
public:
|
||||
|
||||
CNetHost( void );
|
||||
virtual ~CNetHost( void );
|
||||
|
||||
bool Create( void );
|
||||
bool Create( uint port, uint maxPeers );
|
||||
void Shutdown( void );
|
||||
|
||||
/**
|
||||
* Indicates whether the host is currently a server
|
||||
*
|
||||
* @return Boolean indicating whether the host is a server
|
||||
*/
|
||||
virtual bool IsServer( void ) const { return false; }
|
||||
|
||||
/**
|
||||
* Returns the number of sessions for the host
|
||||
*
|
||||
* @return The number of sessions
|
||||
*/
|
||||
uint GetSessionCount( void ) const;
|
||||
|
||||
/**
|
||||
* Returns the session object for the specified index
|
||||
*
|
||||
* @param index Index for session
|
||||
* @return Session object for index or NULL if not found
|
||||
*/
|
||||
CNetSession* GetSession( uint index );
|
||||
|
||||
/**
|
||||
* Connects to foreign host
|
||||
*
|
||||
* @param host Foreign host name
|
||||
* @param port Port on which the foreign host listens
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
bool Connect( const CStr& host, uint port );
|
||||
|
||||
/**
|
||||
* Disconnects session from host
|
||||
*
|
||||
* @param pSession Session representing peer
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
bool Disconnect( CNetSession* pSession );
|
||||
|
||||
/**
|
||||
* Listens for incoming connections and dispatches host events
|
||||
*
|
||||
* @return true on exit, false dispatch failure
|
||||
*/
|
||||
//bool Run( void );
|
||||
bool Poll( void );
|
||||
|
||||
/**
|
||||
* Broadcast the specified message to connected clients
|
||||
*
|
||||
* @param pMessage Message to broadcast
|
||||
*/
|
||||
void Broadcast( const CNetMessage* pMessage );
|
||||
|
||||
/**
|
||||
* Send the specified message to client
|
||||
*
|
||||
* @param pMessage The message to send
|
||||
*/
|
||||
virtual bool SendMessage(
|
||||
const CNetSession* pSession,
|
||||
const CNetMessage* pMessage );
|
||||
|
||||
/**
|
||||
* Receive a message from client if available
|
||||
*
|
||||
*/
|
||||
virtual CNetMessage* ReceiveMessage( const CNetSession* pSession );
|
||||
|
||||
protected:
|
||||
|
||||
// Allow application to handle new client connect
|
||||
virtual bool SetupSession ( CNetSession* pSession );
|
||||
virtual bool HandleConnect ( CNetSession* pSession );
|
||||
virtual bool HandleDisconnect ( CNetSession* pSession );
|
||||
virtual bool HandleMessageReceive (
|
||||
CNetMessage* pMessage,
|
||||
CNetSession* pSession );
|
||||
private:
|
||||
|
||||
std::vector<u8> m_Buffer; // Serialize out messages buffer
|
||||
ENetHost* m_Host; // Represents this host
|
||||
PeerSessionList m_PeerSessions; // Session list of connected peers
|
||||
CNetHost* pHost;
|
||||
CNetSession* pSession;
|
||||
};
|
||||
|
||||
/*
|
||||
CLASS : CNetSession
|
||||
DESCRIPTION : CNetSession is a wrapper class around ENet peer concept
|
||||
which represents a peer from a network connection. A
|
||||
network session is spawned by CNetServer each time a
|
||||
client connects and destroyed when it disconnects. When a
|
||||
new message is received from a client, its representing
|
||||
session object's message handler is called for processing
|
||||
that message.
|
||||
CNetSession is also a state machine. All client requests
|
||||
are delegated to the current state. The current
|
||||
CNetSessionState object's methods will change the current
|
||||
state as appropriate.
|
||||
NOTES :
|
||||
*/
|
||||
/**
|
||||
* CNetSession is a wrapper class around the ENet peer concept
|
||||
* which represents a peer from a network connection. A
|
||||
* network session is spawned by CNetServer each time a
|
||||
* client connects and destroyed when it disconnects. When a
|
||||
* new message is received from a client, its representing
|
||||
* session object's message handler is called for processing
|
||||
* that message.
|
||||
* CNetSession is also a state machine. All client requests
|
||||
* are delegated to the current state. The current
|
||||
* CNetSessionState object's methods will change the current
|
||||
* state as appropriate.
|
||||
*/
|
||||
|
||||
class CNetSession : public CFsm,
|
||||
public CJSObject< CNetSession >
|
||||
public CJSObject<CNetSession>
|
||||
{
|
||||
NONCOPYABLE(CNetSession);
|
||||
|
||||
@ -186,51 +55,53 @@ class CNetSession : public CFsm,
|
||||
|
||||
public:
|
||||
|
||||
virtual ~CNetSession( void );
|
||||
virtual ~CNetSession();
|
||||
|
||||
/**
|
||||
* Retrieves the name of the session
|
||||
*
|
||||
* @return Session name
|
||||
*/
|
||||
const CStrW& GetName( void ) const { return m_Name; }
|
||||
const CStrW& GetName() const { return m_Name; }
|
||||
|
||||
/**
|
||||
* Set the new name for the session
|
||||
*
|
||||
* @param name The session new name
|
||||
*/
|
||||
void SetName( const CStr& name );
|
||||
void SetName(const CStr& name);
|
||||
|
||||
/**
|
||||
* Retrieves the ID of the session
|
||||
*
|
||||
* @return Session ID
|
||||
*/
|
||||
uint GetID( void ) const { return m_ID; }
|
||||
uint GetID() const { return m_ID; }
|
||||
|
||||
/**
|
||||
* Set the ID for this session
|
||||
*
|
||||
* @param New session ID
|
||||
*/
|
||||
void SetID( uint ID );
|
||||
void SetID(uint ID);
|
||||
|
||||
void SetPlayerSlot( CPlayerSlot* pPlayerSlot );
|
||||
CPlayerSlot* GetPlayerSlot( void ) { return m_PlayerSlot; }
|
||||
static void ScriptingInit( void );
|
||||
FsmActionCtx* GetFsmActionCtx() { return &m_FsmActionCtx; }
|
||||
|
||||
void SetPlayerSlot(CPlayerSlot* pPlayerSlot);
|
||||
CPlayerSlot* GetPlayerSlot() { return m_PlayerSlot; }
|
||||
static void ScriptingInit();
|
||||
|
||||
private:
|
||||
|
||||
// Only the hosts can create sessions
|
||||
CNetSession( CNetHost* pHost, ENetPeer* pPeer );
|
||||
CNetSession(CNetHost* pHost, ENetPeer* pPeer);
|
||||
|
||||
CNetHost* m_Host; // The associated local host
|
||||
ENetPeer* m_Peer; // Represents the peer host
|
||||
uint m_ID; // Session ID
|
||||
CStrW m_Name; // Session name
|
||||
CPlayerSlot* m_PlayerSlot;
|
||||
FsmActionCtx m_FsmActionCtx;
|
||||
};
|
||||
|
||||
#endif // NETSESSION_H
|
||||
|
||||
|
@ -24,14 +24,14 @@
|
||||
class CErrorMessage : public CNetMessage
|
||||
{
|
||||
public:
|
||||
PS_RESULT m_Error;
|
||||
const char* m_Error;
|
||||
|
||||
inline CErrorMessage() :
|
||||
CNetMessage(NMT_ERROR)
|
||||
CErrorMessage() :
|
||||
CNetMessage(NMT_ERROR), m_Error(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
inline CErrorMessage(PS_RESULT error) :
|
||||
CErrorMessage(const char* error) :
|
||||
CNetMessage(NMT_ERROR), m_Error(error)
|
||||
{
|
||||
}
|
||||
@ -41,7 +41,7 @@ public:
|
||||
|
||||
struct CCloseRequestMessage : public CNetMessage
|
||||
{
|
||||
inline CCloseRequestMessage() :
|
||||
CCloseRequestMessage() :
|
||||
CNetMessage(NMT_CLOSE_REQUEST)
|
||||
{
|
||||
}
|
||||
@ -51,7 +51,7 @@ struct CCloseRequestMessage : public CNetMessage
|
||||
|
||||
struct CConnectCompleteMessage : public CNetMessage
|
||||
{
|
||||
inline CConnectCompleteMessage() :
|
||||
CConnectCompleteMessage() :
|
||||
CNetMessage(NMT_CONNECT_COMPLETE)
|
||||
{
|
||||
}
|
||||
|
@ -56,13 +56,14 @@ typedef std::vector< CallbackFunction > CallbackList;
|
||||
/*
|
||||
CLASS : CFsmEvent
|
||||
DESCRIPTION : CFsmEvent class represents a signal in the state machine
|
||||
that a change has occured.
|
||||
that a change has occurred.
|
||||
NOTES : The CFsmEvent objects are under the control of CFsm so
|
||||
they are created and deleted via CFsm.
|
||||
*/
|
||||
|
||||
class CFsmEvent
|
||||
{
|
||||
NONCOPYABLE(CFsmEvent);
|
||||
public:
|
||||
|
||||
CFsmEvent( unsigned int type );
|
||||
@ -72,14 +73,7 @@ public:
|
||||
void* GetParamRef ( void ) { return m_Param; }
|
||||
void SetParamRef ( void* pParam );
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CFsmEvent( const CFsmEvent& );
|
||||
CFsmEvent& operator=( const CFsmEvent& );
|
||||
|
||||
unsigned int m_Type; // Event type
|
||||
void* m_Param; // Event paramater
|
||||
};
|
||||
@ -94,6 +88,7 @@ private:
|
||||
|
||||
class CFsmTransition
|
||||
{
|
||||
NONCOPYABLE(CFsmTransition);
|
||||
public:
|
||||
|
||||
CFsmTransition( unsigned int state );
|
||||
@ -115,14 +110,7 @@ public:
|
||||
bool ApplyConditions ( void ) const;
|
||||
bool RunActions ( void ) const;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CFsmTransition( const CFsmTransition& );
|
||||
CFsmTransition& operator=( const CFsmTransition& );
|
||||
|
||||
unsigned int m_CurrState; // Current state
|
||||
unsigned int m_NextState; // Next state
|
||||
CFsmEvent* m_Event; // Transition event
|
||||
@ -144,6 +132,7 @@ private:
|
||||
|
||||
class CFsm
|
||||
{
|
||||
NONCOPYABLE(CFsm);
|
||||
public:
|
||||
|
||||
CFsm( void );
|
||||
@ -188,14 +177,7 @@ public:
|
||||
bool IsValidEvent ( unsigned int eventType ) const;
|
||||
virtual bool IsDone ( void ) const;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
// Not implemented
|
||||
CFsm( const CFsm& );
|
||||
CFsm& operator=( const CFsm& );
|
||||
|
||||
void SetCurrState ( unsigned int state );
|
||||
bool IsFirstTime ( void ) const;
|
||||
|
||||
|
165
source/network/tests/test_Net.h
Normal file
165
source/network/tests/test_Net.h
Normal file
@ -0,0 +1,165 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include "lib/external_libraries/sdl.h"
|
||||
#include "network/NetServer.h"
|
||||
#include "network/NetClient.h"
|
||||
#include "ps/ConfigDB.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/GameAttributes.h"
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
|
||||
class TestNetServer : public CNetServer
|
||||
{
|
||||
public:
|
||||
TestNetServer(ScriptInterface& scriptInterface, CGameAttributes& gameAttributes) :
|
||||
CNetServer(scriptInterface, NULL, &gameAttributes), m_HasConnection(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool m_HasConnection;
|
||||
|
||||
protected:
|
||||
virtual void OnPlayerJoin(CNetSession* pSession)
|
||||
{
|
||||
debug_printf(L"# player joined\n");
|
||||
|
||||
for (size_t slot = 0; slot < m_GameAttributes->GetSlotCount(); ++slot)
|
||||
{
|
||||
if (m_GameAttributes->GetSlot(slot)->GetAssignment() == SLOT_OPEN)
|
||||
{
|
||||
debug_printf(L"# assigning slot %d\n", slot);
|
||||
m_GameAttributes->GetSlot(slot)->AssignToSession(pSession);
|
||||
m_HasConnection = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPlayerLeave(CNetSession* UNUSED(pSession))
|
||||
{
|
||||
debug_printf(L"# player left\n");
|
||||
}
|
||||
};
|
||||
|
||||
class TestNetClient : public CNetClient
|
||||
{
|
||||
public:
|
||||
TestNetClient(ScriptInterface& scriptInterface, CGameAttributes& gameAttributes) :
|
||||
CNetClient(scriptInterface, NULL, &gameAttributes), m_HasConnection(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool m_HasConnection;
|
||||
|
||||
protected:
|
||||
virtual void OnConnectComplete()
|
||||
{
|
||||
debug_printf(L"# connect complete\n");
|
||||
m_HasConnection = true;
|
||||
}
|
||||
|
||||
virtual void OnStartGame()
|
||||
{
|
||||
debug_printf(L"# start game\n");
|
||||
}
|
||||
};
|
||||
|
||||
class TestNetComms : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void setUp()
|
||||
{
|
||||
g_VFS = CreateVfs(20 * MiB);
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/L"mods/public", VFS_MOUNT_MUST_EXIST));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/L"_testcache"));
|
||||
CXeromyces::Startup();
|
||||
|
||||
new ScriptingHost;
|
||||
CGameAttributes::ScriptingInit();
|
||||
CNetServer::ScriptingInit();
|
||||
CNetClient::ScriptingInit();
|
||||
|
||||
new CConfigDB;
|
||||
}
|
||||
|
||||
void tearDown()
|
||||
{
|
||||
delete &g_ConfigDB;
|
||||
|
||||
CGameAttributes::ScriptingShutdown();
|
||||
CNetServer::ScriptingShutdown();
|
||||
CNetClient::ScriptingShutdown();
|
||||
delete &g_ScriptingHost;
|
||||
|
||||
CXeromyces::Terminate();
|
||||
g_VFS.reset();
|
||||
DeleteDirectory(DataDir()/L"_testcache");
|
||||
}
|
||||
|
||||
void connect(TestNetServer& server, TestNetClient& client)
|
||||
{
|
||||
TS_ASSERT(server.Start(NULL, 0, NULL));
|
||||
TS_ASSERT(client.Create());
|
||||
TS_ASSERT(client.ConnectAsync("127.0.0.1", DEFAULT_HOST_PORT));
|
||||
for (size_t i = 0; ; ++i)
|
||||
{
|
||||
debug_printf(L".");
|
||||
server.Poll();
|
||||
client.Poll();
|
||||
|
||||
if (server.m_HasConnection && client.m_HasConnection)
|
||||
break;
|
||||
|
||||
if (i > 20)
|
||||
{
|
||||
TS_FAIL("connection timeout");
|
||||
break;
|
||||
}
|
||||
|
||||
SDL_Delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
void test_basic_DISABLED()
|
||||
{
|
||||
ScriptInterface scriptInterface("Engine");
|
||||
|
||||
CGameAttributes gameAttributesServer;
|
||||
CGameAttributes gameAttributesClient;
|
||||
TestNetServer server(scriptInterface, gameAttributesServer);
|
||||
TestNetClient client(scriptInterface, gameAttributesClient);
|
||||
connect(server, client);
|
||||
client.CNetHost::Shutdown();
|
||||
server.CNetHost::Shutdown();
|
||||
}
|
||||
|
||||
void TODO_test_destructor()
|
||||
{
|
||||
ScriptInterface scriptInterface("Engine");
|
||||
|
||||
CGameAttributes gameAttributesServer;
|
||||
CGameAttributes gameAttributesClient;
|
||||
TestNetServer server(scriptInterface, gameAttributesServer);
|
||||
TestNetClient client(scriptInterface, gameAttributesClient);
|
||||
connect(server, client);
|
||||
// run in Valgrind; this shouldn't leak
|
||||
}
|
||||
};
|
@ -32,9 +32,9 @@ extern CLogger* g_Logger;
|
||||
// Should become LOG_MESSAGE but this can only be changed once the LOG function is removed
|
||||
// from all of the files. LOG_INFO, LOG_WARNING and LOG_ERROR are currently existing macros.
|
||||
|
||||
#define LOGMESSAGE (g_Logger->LogMessage)
|
||||
#define LOGWARNING (g_Logger->LogWarning)
|
||||
#define LOGERROR (g_Logger->LogError)
|
||||
#define LOGMESSAGE g_Logger->LogMessage
|
||||
#define LOGWARNING g_Logger->LogWarning
|
||||
#define LOGERROR g_Logger->LogError
|
||||
|
||||
class CLogger
|
||||
{
|
||||
|
@ -50,7 +50,6 @@
|
||||
#ifndef INCLUDED_CONFIGDB
|
||||
#define INCLUDED_CONFIGDB
|
||||
|
||||
#include "Pyrogenesis.h"
|
||||
#include "Parser.h"
|
||||
#include "CStr.h"
|
||||
#include "Singleton.h"
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "simulation/LOSManager.h"
|
||||
|
||||
CGameAttributes *g_GameAttributes;
|
||||
|
||||
CPlayerSlot::CPlayerSlot(size_t slotID, CPlayer *pPlayer):
|
||||
m_SlotID(slotID),
|
||||
|
@ -133,8 +133,7 @@ namespace PlayerSlotArray_JS
|
||||
}
|
||||
|
||||
class CGameAttributes:
|
||||
public CSynchedJSObject<CGameAttributes>,
|
||||
public Singleton<CGameAttributes>
|
||||
public CSynchedJSObject<CGameAttributes>
|
||||
{
|
||||
public:
|
||||
typedef void (UpdateCallback)(const CStrW& name, const CStrW& newValue, void *data);
|
||||
@ -210,6 +209,7 @@ public:
|
||||
|
||||
static void ScriptingInit();
|
||||
};
|
||||
#define g_GameAttributes CGameAttributes::GetSingleton()
|
||||
|
||||
extern CGameAttributes *g_GameAttributes;
|
||||
|
||||
#endif
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/Font.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/GameAttributes.h"
|
||||
#include "ps/Globals.h"
|
||||
#include "ps/Hotkey.h"
|
||||
#include "ps/Loader.h"
|
||||
@ -85,7 +86,6 @@
|
||||
|
||||
#include "sound/JSI_Sound.h"
|
||||
|
||||
#include "network/NetLog.h"
|
||||
#include "network/NetServer.h"
|
||||
#include "network/NetClient.h"
|
||||
|
||||
@ -584,7 +584,7 @@ void Shutdown(int flags)
|
||||
|
||||
if (! (flags & INIT_NO_SIM))
|
||||
{
|
||||
delete &g_GameAttributes;
|
||||
SAFE_DELETE(g_GameAttributes);
|
||||
}
|
||||
|
||||
// destroy actor related stuff
|
||||
@ -611,10 +611,6 @@ void Shutdown(int flags)
|
||||
delete &g_ConfigDB;
|
||||
TIMER_END(L"shutdown ConfigDB");
|
||||
|
||||
TIMER_BEGIN(L"shutdown CNetLogManager");
|
||||
CNetLogManager::Shutdown();
|
||||
TIMER_END(L"shutdown CNetLogManager");
|
||||
|
||||
// Really shut down the i18n system. Any future calls
|
||||
// to translate() will crash.
|
||||
TIMER_BEGIN(L"shutdown I18N");
|
||||
@ -809,10 +805,10 @@ void Init(const CmdLineArgs& args, int flags)
|
||||
|
||||
if (! (flags & INIT_NO_SIM))
|
||||
{
|
||||
new CGameAttributes;
|
||||
g_GameAttributes = new CGameAttributes;
|
||||
|
||||
// Register a few Game/Network JS globals
|
||||
g_ScriptingHost.SetGlobal("g_GameAttributes", OBJECT_TO_JSVAL(g_GameAttributes.GetScript()));
|
||||
g_ScriptingHost.SetGlobal("g_GameAttributes", OBJECT_TO_JSVAL(g_GameAttributes->GetScript()));
|
||||
}
|
||||
|
||||
InitInput();
|
||||
@ -838,17 +834,17 @@ class AutostartNetServer : public CNetServer
|
||||
{
|
||||
public:
|
||||
AutostartNetServer(CGame *pGame, CGameAttributes *pGameAttributes, int maxPlayers) :
|
||||
CNetServer(pGame, pGameAttributes), m_NumPlayers(1), m_MaxPlayers(maxPlayers)
|
||||
CNetServer(pGame->GetSimulation2()->GetScriptInterface(), pGame, pGameAttributes), m_NumPlayers(1), m_MaxPlayers(maxPlayers)
|
||||
{
|
||||
}
|
||||
protected:
|
||||
virtual void OnPlayerJoin(CNetSession* pSession)
|
||||
{
|
||||
for (size_t slot = 0; slot < g_GameAttributes.GetSlotCount(); ++slot)
|
||||
for (size_t slot = 0; slot < m_GameAttributes->GetSlotCount(); ++slot)
|
||||
{
|
||||
if (g_GameAttributes.GetSlot(slot)->GetAssignment() == SLOT_OPEN)
|
||||
if (m_GameAttributes->GetSlot(slot)->GetAssignment() == SLOT_OPEN)
|
||||
{
|
||||
g_GameAttributes.GetSlot(slot)->AssignToSession(pSession);
|
||||
m_GameAttributes->GetSlot(slot)->AssignToSession(pSession);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -880,7 +876,7 @@ class AutostartNetClient : public CNetClient
|
||||
{
|
||||
public:
|
||||
AutostartNetClient(CGame *pGame, CGameAttributes *pGameAttributes) :
|
||||
CNetClient(pGame, pGameAttributes)
|
||||
CNetClient(pGame->GetSimulation2()->GetScriptInterface(), pGame, pGameAttributes)
|
||||
{
|
||||
}
|
||||
protected:
|
||||
@ -912,11 +908,11 @@ static bool Autostart(const CmdLineArgs& args)
|
||||
|
||||
g_Game = new CGame();
|
||||
|
||||
g_GameAttributes.m_MapFile = autostartMap + ".pmp";
|
||||
g_GameAttributes->m_MapFile = autostartMap + ".pmp";
|
||||
|
||||
// Make the whole world visible
|
||||
g_GameAttributes.m_LOSSetting = LOS_SETTING_ALL_VISIBLE;
|
||||
g_GameAttributes.m_FogOfWar = false;
|
||||
g_GameAttributes->m_LOSSetting = LOS_SETTING_ALL_VISIBLE;
|
||||
g_GameAttributes->m_FogOfWar = false;
|
||||
|
||||
if (args.Has("autostart-host"))
|
||||
{
|
||||
@ -926,7 +922,7 @@ static bool Autostart(const CmdLineArgs& args)
|
||||
if (args.Has("autostart-players"))
|
||||
maxPlayers = args.Get("autostart-players").ToUInt();
|
||||
|
||||
g_NetServer = new AutostartNetServer(g_Game, &g_GameAttributes, maxPlayers);
|
||||
g_NetServer = new AutostartNetServer(g_Game, g_GameAttributes, maxPlayers);
|
||||
// TODO: player name, etc
|
||||
bool ok = g_NetServer->Start(NULL, 0, NULL);
|
||||
debug_assert(ok);
|
||||
@ -936,7 +932,7 @@ static bool Autostart(const CmdLineArgs& args)
|
||||
InitPs(true, L"page_loading.xml");
|
||||
|
||||
bool ok;
|
||||
g_NetClient = new AutostartNetClient(g_Game, &g_GameAttributes);
|
||||
g_NetClient = new AutostartNetClient(g_Game, g_GameAttributes);
|
||||
// TODO: player name, etc
|
||||
ok = g_NetClient->Create();
|
||||
debug_assert(ok);
|
||||
@ -946,9 +942,9 @@ static bool Autostart(const CmdLineArgs& args)
|
||||
else
|
||||
{
|
||||
for (int i = 1; i < 8; ++i)
|
||||
g_GameAttributes.GetSlot(i)->AssignLocal();
|
||||
g_GameAttributes->GetSlot(i)->AssignLocal();
|
||||
|
||||
PSRETURN ret = g_Game->StartGame(&g_GameAttributes);
|
||||
PSRETURN ret = g_Game->StartGame(g_GameAttributes);
|
||||
debug_assert(ret == PSRETURN_OK);
|
||||
LDR_NonprogressiveLoad();
|
||||
ret = g_Game->ReallyStartGame();
|
||||
|
@ -26,10 +26,6 @@
|
||||
#include "lib/path_util.h"
|
||||
#include "lib/svn_revision.h"
|
||||
|
||||
DEFINE_ERROR(PS_OK, "OK");
|
||||
DEFINE_ERROR(PS_FAIL, "Fail");
|
||||
|
||||
|
||||
static const wchar_t* translate_no_mem = L"(no mem)";
|
||||
|
||||
// overrides ah_translate. registered in GameSetup.cpp
|
||||
|
@ -24,19 +24,8 @@ Standard declarations which are included in all projects.
|
||||
#ifndef INCLUDED_PYROGENESIS
|
||||
#define INCLUDED_PYROGENESIS
|
||||
|
||||
typedef const char * PS_RESULT;
|
||||
|
||||
#define DEFINE_ERROR(x, y) PS_RESULT x=y
|
||||
#define DECLARE_ERROR(x) extern PS_RESULT x
|
||||
|
||||
DECLARE_ERROR(PS_OK);
|
||||
DECLARE_ERROR(PS_FAIL);
|
||||
|
||||
|
||||
|
||||
#define MICROLOG debug_wprintf_mem
|
||||
|
||||
|
||||
// overrides ah_translate. registered in GameSetup.cpp
|
||||
extern const wchar_t* psTranslate(const wchar_t* text);
|
||||
extern void psTranslateFree(const wchar_t* text);
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/CStr.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/GameAttributes.h"
|
||||
#include "ps/Globals.h" // g_frequencyFilter
|
||||
#include "ps/GameSetup/GameSetup.h"
|
||||
#include "ps/Hotkey.h"
|
||||
@ -57,6 +58,7 @@
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/SkyManager.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
|
||||
#define LOG_CATEGORY L"script"
|
||||
extern bool g_TerrainModified;
|
||||
@ -202,7 +204,7 @@ JSBool CreateServer(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rv
|
||||
if( !g_Game )
|
||||
g_Game = new CGame();
|
||||
if( !g_NetServer )
|
||||
g_NetServer = new CNetServer(g_Game, &g_GameAttributes);
|
||||
g_NetServer = new CNetServer(g_Game->GetSimulation2()->GetScriptInterface(), g_Game, g_GameAttributes);
|
||||
|
||||
*rval = OBJECT_TO_JSVAL(g_NetServer->GetScript());
|
||||
return( JS_TRUE );
|
||||
@ -219,7 +221,7 @@ JSBool CreateClient(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rv
|
||||
if( !g_Game )
|
||||
g_Game = new CGame();
|
||||
if( !g_NetClient )
|
||||
g_NetClient = new CNetClient(g_Game, &g_GameAttributes);
|
||||
g_NetClient = new CNetClient(g_Game->GetSimulation2()->GetScriptInterface(), g_Game, g_GameAttributes);
|
||||
|
||||
*rval = OBJECT_TO_JSVAL(g_NetClient->GetScript());
|
||||
return( JS_TRUE );
|
||||
@ -255,7 +257,7 @@ JSBool StartGame(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval)
|
||||
else if (!g_Game)
|
||||
{
|
||||
g_Game = new CGame();
|
||||
PSRETURN ret = g_Game->StartGame(&g_GameAttributes);
|
||||
PSRETURN ret = g_Game->StartGame(g_GameAttributes);
|
||||
if (ret != PSRETURN_OK)
|
||||
{
|
||||
// Failed to start the game - destroy it, and return false
|
||||
@ -291,7 +293,7 @@ JSBool GetGameMode(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rva
|
||||
{
|
||||
JSU_REQUIRE_NO_PARAMS();
|
||||
|
||||
*rval = ToJSVal( g_GameAttributes.GetGameMode() );
|
||||
*rval = ToJSVal( g_GameAttributes->GetGameMode() );
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -256,6 +256,7 @@ public:
|
||||
PropertyTable::iterator it;
|
||||
for( it = m_NativeProperties.begin(); it != m_NativeProperties.end(); it++ )
|
||||
delete( it->second );
|
||||
m_NativeProperties.clear();
|
||||
}
|
||||
|
||||
// JS Property access
|
||||
|
@ -334,6 +334,9 @@ void ScriptingHost::ErrorReporter(JSContext* UNUSED(cx), const char* pmessage, J
|
||||
void* ScriptingHost::jshook_script( JSContext* UNUSED(cx), JSStackFrame* UNUSED(fp),
|
||||
JSBool before, JSBool* UNUSED(ok), void* closure )
|
||||
{
|
||||
if (!CProfileManager::IsInitialised())
|
||||
return closure;
|
||||
|
||||
if( before )
|
||||
{
|
||||
g_Profiler.StartScript( "script invocation" );
|
||||
@ -346,6 +349,9 @@ void* ScriptingHost::jshook_script( JSContext* UNUSED(cx), JSStackFrame* UNUSED(
|
||||
|
||||
void* ScriptingHost::jshook_function( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* UNUSED(ok), void* closure )
|
||||
{
|
||||
if (!CProfileManager::IsInitialised())
|
||||
return closure;
|
||||
|
||||
JSFunction* fn = JS_GetFrameFunction( cx, fp );
|
||||
if( before )
|
||||
{
|
||||
|
@ -50,19 +50,19 @@ namespace
|
||||
|
||||
// Set attributes for the game:
|
||||
|
||||
g_GameAttributes.m_MapFile = map;
|
||||
g_GameAttributes->m_MapFile = map;
|
||||
// Make all players locally controlled
|
||||
for (int i = 1; i < 8; ++i)
|
||||
g_GameAttributes.GetSlot(i)->AssignLocal();
|
||||
g_GameAttributes->GetSlot(i)->AssignLocal();
|
||||
|
||||
// Make the whole world visible
|
||||
g_GameAttributes.m_LOSSetting = LOS_SETTING_ALL_VISIBLE;
|
||||
g_GameAttributes.m_FogOfWar = false;
|
||||
g_GameAttributes->m_LOSSetting = LOS_SETTING_ALL_VISIBLE;
|
||||
g_GameAttributes->m_FogOfWar = false;
|
||||
|
||||
// Don't use screenshot mode, because we want working AI for the
|
||||
// simulation-testing. Outside that simulation-testing, we avoid having
|
||||
// the units move into attack mode by never calling CEntity::update.
|
||||
g_GameAttributes.m_ScreenshotMode = false;
|
||||
g_GameAttributes->m_ScreenshotMode = false;
|
||||
|
||||
// Initialise the game:
|
||||
g_Game = new CGame();
|
||||
@ -86,7 +86,7 @@ namespace
|
||||
|
||||
void StartGame()
|
||||
{
|
||||
PSRETURN ret = g_Game->StartGame(&g_GameAttributes);
|
||||
PSRETURN ret = g_Game->StartGame(g_GameAttributes);
|
||||
debug_assert(ret == PSRETURN_OK);
|
||||
LDR_NonprogressiveLoad();
|
||||
ret = g_Game->ReallyStartGame();
|
||||
|
Loading…
Reference in New Issue
Block a user