diff --git a/source/network/NetClient.cpp b/source/network/NetClient.cpp
index c4a416d8ff..cbdd197727 100644
--- a/source/network/NetClient.cpp
+++ b/source/network/NetClient.cpp
@@ -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 );
}
}
diff --git a/source/network/NetClient.h b/source/network/NetClient.h
index cb5499335c..2b9005a037 100644
--- a/source/network/NetClient.h
+++ b/source/network/NetClient.h
@@ -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 );
diff --git a/source/network/NetHost.cpp b/source/network/NetHost.cpp
new file mode 100644
index 0000000000..3e24bad7ba
--- /dev/null
+++ b/source/network/NetHost.cpp
@@ -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 .
+ */
+
+#include "precompiled.h"
+#include "NetHost.h"
+#include "NetSession.h"
+#include "NetMessage.h"
+
+#include "ps/CLogger.h"
+#include "simulation2/Simulation2.h"
+
+#include
+
+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 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;
+}
diff --git a/source/network/NetHost.h b/source/network/NetHost.h
new file mode 100644
index 0000000000..56655a0803
--- /dev/null
+++ b/source/network/NetHost.h
@@ -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 .
+ */
+
+#ifndef NETHOST_H
+#define NETHOST_H
+
+#include "fsm.h"
+
+#include "ps/CStr.h"
+
+#include
+
+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 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
diff --git a/source/network/NetLog.cpp b/source/network/NetLog.cpp
deleted file mode 100644
index 4012840cbc..0000000000
--- a/source/network/NetLog.cpp
+++ /dev/null
@@ -1,1126 +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 .
- */
-
-/**
- *-----------------------------------------------------------------------------
- * FILE : NetLog.cpp
- * PROJECT : 0 A.D.
- * DESCRIPTION : Network subsystem logging classes implementation
- *-----------------------------------------------------------------------------
- */
-
-// INCLUDES
-#include "precompiled.h"
-#include "NetLog.h"
-#include "ps/CConsole.h"
-#include "lib/utf8.h"
-
-#include
-#include
-#include
-
-//-----------------------------------------------------------------------------
-// Name: CNetLogEvent()
-// Desc: Constructor
-//-----------------------------------------------------------------------------
-CNetLogEvent::CNetLogEvent(
- LogLevel level,
- const CStr& message,
- const CStr& loggerName )
-{
- m_Level = level;
- m_Message = message;
- m_LoggerName = loggerName;
-}
-
-//-----------------------------------------------------------------------------
-// Name: ~CNetLogEvent()
-// Desc: Destructor
-//-----------------------------------------------------------------------------
-CNetLogEvent::~CNetLogEvent( void )
-{
-}
-
-//-----------------------------------------------------------------------------
-// Name: CNetLogSink()
-// Desc: Constructor
-//-----------------------------------------------------------------------------
-CNetLogSink::CNetLogSink( void )
-{
- m_Active = false;
-}
-
-//-----------------------------------------------------------------------------
-// Name: ~CNetLogSink()
-// Desc: Destructor
-//-----------------------------------------------------------------------------
-CNetLogSink::~CNetLogSink( void )
-{
-}
-
-//-----------------------------------------------------------------------------
-// Name: SetName()
-// Desc: Set the name for the sink
-//-----------------------------------------------------------------------------
-void CNetLogSink::SetName( const CStr& name )
-{
- m_Name = name;
-}
-
-//-----------------------------------------------------------------------------
-// Name: SetLevel()
-// Desc: Set the level for the sink
-//-----------------------------------------------------------------------------
-void CNetLogSink::SetLevel( LogLevel level )
-{
- m_Level = level;
-}
-
-//-----------------------------------------------------------------------------
-// Name: SetHeader()
-// Desc: Set new header text
-//-----------------------------------------------------------------------------
-void CNetLogSink::SetHeader( const CStr& header )
-{
- m_Header = header;
-}
-
-//-----------------------------------------------------------------------------
-// Name: SetFooter()
-// Desc: Set new footer text
-//-----------------------------------------------------------------------------
-void CNetLogSink::SetFooter( const CStr& footer )
-{
- m_Footer = footer;
-}
-
-//-----------------------------------------------------------------------------
-// Name: Activate()
-// Desc: Activates the sink
-//-----------------------------------------------------------------------------
-void CNetLogSink::Activate( void )
-{
- CScopeLock lock( m_Mutex );
-
- if ( !m_Active )
- {
- OnActivate();
-
- m_Active = true;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: Close()
-// Desc: Closes the sink
-//-----------------------------------------------------------------------------
-void CNetLogSink::Close( void )
-{
- CScopeLock lock( m_Mutex );
-
- OnClose();
-}
-
-//-----------------------------------------------------------------------------
-// Name: DoSink()
-// Desc: Perform event logging
-//-----------------------------------------------------------------------------
-void CNetLogSink::DoSink( const CNetLogEvent& event )
-{
- CScopeLock lock( m_Mutex );
-
- // Not activated? Nothing to log
- if ( !m_Active ) return;
-
- if ( TestEvent( event ) )
- {
- Sink( event );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: DoBulkSink()
-// Desc: Perform logging for a list of events
-//-----------------------------------------------------------------------------
-void CNetLogSink::DoBulkSink( const CNetLogEvent* pEvents, size_t eventCount )
-{
- size_t* pIndices = NULL;
- size_t indexCount = 0;
- size_t i;
-
- CScopeLock lock( m_Mutex );
-
- // Validate parameters
- if ( !pEvents ) return;
-
- // Not activated? Nothing to log
- if ( m_Closed ) return;
-
- // Allocate new array which will store the events that will be logged
- pIndices = new size_t[ eventCount ];
- if ( !pIndices )
- {
- throw std::bad_alloc();
- return;
- }
-
- // Filter each event and store the index for
- // those passing the filter test
- for ( i = 0; i < eventCount; i++ )
- {
- if ( TestEvent( pEvents[ i ] ) )
- {
- pIndices[ indexCount++ ] = i;
- }
- }
-
- // Log each event
- for ( i = 0; i < indexCount; i++ )
- {
- Sink( pEvents[ pIndices[ i ] ] );
- }
-
- delete [] pIndices;
-}
-
-//-----------------------------------------------------------------------------
-// Name: CNetLogSink()
-// Desc: Test if the event can be logged
-//-----------------------------------------------------------------------------
-bool CNetLogSink::TestEvent( const CNetLogEvent& event )
-{
- return ( event.GetLevel() >= m_Level );
-}
-
-//-----------------------------------------------------------------------------
-// Name: WriteHeader()
-// Desc: Writes a header
-//-----------------------------------------------------------------------------
-void CNetLogSink::WriteHeader( void )
-{
- if ( !m_Header.empty() )
- {
- Write( m_Header );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: WriteFooter()
-// Desc: Writes a footer
-//-----------------------------------------------------------------------------
-void CNetLogSink::WriteFooter( void )
-{
- if ( !m_Footer.empty() )
- {
- Write( m_Footer );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: OnActivate()
-// Desc: Called on activation
-//-----------------------------------------------------------------------------
-void CNetLogSink::OnActivate( void )
-{
- // Does nothing by default
-}
-
-//-----------------------------------------------------------------------------
-// Name: OnClose()
-// Desc: Called on sink closure
-//-----------------------------------------------------------------------------
-void CNetLogSink::OnClose( void )
-{
- // Does nothing by default
-}
-
-//-----------------------------------------------------------------------------
-// Name: CNetLogFileSink()
-// Desc: Constructor
-//-----------------------------------------------------------------------------
-CNetLogFileSink::CNetLogFileSink( void )
-{
- // Get string time
- CStr time;
- CNetLogger::GetStringTime( time );
-
- // Make relative path
- fs::wpath path(psLogDir()/L"net_log");
- path /= CStrW(time)+L".txt";
- m_FileName = path.string();
- m_Append = true;
-}
-
-//-----------------------------------------------------------------------------
-// Name: CNetLogFileSink()
-// Desc: Constructor
-//-----------------------------------------------------------------------------
-CNetLogFileSink::CNetLogFileSink( const fs::wpath& filename )
-{
- m_FileName = filename;
- m_Append = true;
-}
-
-//-----------------------------------------------------------------------------
-// Name: CNetLogFileSink()
-// Desc: Constructor
-//-----------------------------------------------------------------------------
-CNetLogFileSink::CNetLogFileSink( const fs::wpath& filename, bool append )
-{
- m_FileName = filename;
- m_Append = append;
-}
-
-//-----------------------------------------------------------------------------
-// Name: ~CNetLogFileSink()
-// Desc: Destructor
-//-----------------------------------------------------------------------------
-CNetLogFileSink::~CNetLogFileSink( void )
-{
-}
-
-//-----------------------------------------------------------------------------
-// Name: Activate()
-// Desc: Open the file which will be used for logging
-//-----------------------------------------------------------------------------
-void CNetLogFileSink::OnActivate( void )
-{
- OpenFile( m_FileName, m_Append );
-
- WriteHeader();
-}
-
-//-----------------------------------------------------------------------------
-// Name: OnClose()
-// Desc: Closes the file used for logging
-//-----------------------------------------------------------------------------
-void CNetLogFileSink::OnClose( void )
-{
- WriteFooter();
-
- CloseFile();
-}
-
-//-----------------------------------------------------------------------------
-// Name: Sink()
-// Desc: Log the event to file
-//-----------------------------------------------------------------------------
-void CNetLogFileSink::Sink( const CNetLogEvent& event )
-{
- Write( event.GetMessage() );
-}
-
-//-----------------------------------------------------------------------------
-// Name: Write()
-// Desc: Writes a message to log file
-//-----------------------------------------------------------------------------
-void CNetLogFileSink::Write( const CStr& message )
-{
- // File not opened?
- if ( !m_File.is_open() )
- {
- OpenFile( m_FileName, m_Append );
-
- // If still not opened, ignore message
- if ( !m_File.is_open() ) return;
- }
-
- // Write message
- if ( !message.empty() )
- {
- m_File << message;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: Write()
-// Desc: Writes a character to the file
-//-----------------------------------------------------------------------------
-void CNetLogFileSink::Write( char c )
-{
- // File not opened?
- if ( !m_File.is_open() )
- {
- OpenFile( m_FileName, m_Append );
-
- // If still not opened, ignore character
- if ( !m_File.is_open() ) return;
- }
-
- // Write character
- m_File << c;
-}
-
-//-----------------------------------------------------------------------------
-// Name: OpenFile()
-// Desc: Open the file where the logging will output
-//-----------------------------------------------------------------------------
-void CNetLogFileSink::OpenFile( const fs::wpath& fileName, bool append )
-{
- // Close any open file
- if ( m_File.is_open() ) m_File.close();
-
- // Open the file and log start
- m_File.open( utf8_from_wstring(fileName.string()).c_str(), append ? std::ios::app : std::ios::out );
- if ( !m_File.is_open() )
- {
- // throw std::ios_base::failure
- return;
- }
-
- m_FileName = fileName;
- m_Append = append;
-}
-
-//-----------------------------------------------------------------------------
-// Name: CloseFile()
-// Desc: Closes the opened file
-//-----------------------------------------------------------------------------
-void CNetLogFileSink::CloseFile( void )
-{
- if ( m_File.is_open() )
- {
- m_File.flush();
- m_File.close();
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: CNetLogConsoleSink()
-// Desc: Constructor
-//-----------------------------------------------------------------------------
-CNetLogConsoleSink::CNetLogConsoleSink( void )
-{
-}
-
-//-----------------------------------------------------------------------------
-// Name: ~CNetLogConsoleSink()
-// Desc: Destructor
-//-----------------------------------------------------------------------------
-CNetLogConsoleSink::~CNetLogConsoleSink( void )
-{
-}
-
-//-----------------------------------------------------------------------------
-// Name: Activate()
-// Desc: Activates the game console
-//-----------------------------------------------------------------------------
-void CNetLogConsoleSink::OnActivate( void )
-{
- WriteHeader();
-}
-
-//-----------------------------------------------------------------------------
-// Name: OnClose()
-// Desc: Toggles off game console
-//-----------------------------------------------------------------------------
-void CNetLogConsoleSink::OnClose( void )
-{
- WriteFooter();
-}
-
-//-----------------------------------------------------------------------------
-// Name: Sink()
-// Desc: Log the event to file
-//-----------------------------------------------------------------------------
-void CNetLogConsoleSink::Sink( const CNetLogEvent& event )
-{
- Write( event.GetMessage() );
-}
-
-//-----------------------------------------------------------------------------
-// Name: Write()
-// Desc: Writes a message to game console
-//-----------------------------------------------------------------------------
-void CNetLogConsoleSink::Write( const CStr& message )
-{
- // Do we have a valid console?
- if ( !g_Console ) return;
-
- // Write message
- if ( !message.empty() )
- {
- g_Console->InsertMessage( L"%ls", message.FromUTF8().c_str() );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: Write()
-// Desc: Writes a character to the file
-//-----------------------------------------------------------------------------
-void CNetLogConsoleSink::Write( char c )
-{
- // Do we have a valid console?
- if ( !g_Console ) return;
-
- // Write character
- Write( CStr( c ) );
-}
-
-//-----------------------------------------------------------------------------
-// Name: CNetLogger()
-// Desc: Constructor
-//-----------------------------------------------------------------------------
-CNetLogger::CNetLogger( const CStr& name )
-{
- m_Name = name;
- m_Level = LOG_LEVEL_ALL;
-}
-
-//-----------------------------------------------------------------------------
-// Name: ~CNetLogger()
-// Desc: Destructor
-//-----------------------------------------------------------------------------
-CNetLogger::~CNetLogger( void )
-{
-}
-
-//-----------------------------------------------------------------------------
-// Name: SetLevel()
-// Desc: Set logger level
-//-----------------------------------------------------------------------------
-void CNetLogger::SetLevel( LogLevel level )
-{
- m_Level = level;
-}
-
-//-----------------------------------------------------------------------------
-// Name: IsDebugEnabled()
-// Desc: Check if enabled for DEBUG level
-//-----------------------------------------------------------------------------
-bool CNetLogger::IsDebugEnabled( void ) const
-{
- return ( LOG_LEVEL_DEBUG >= m_Level );
-}
-
-//-----------------------------------------------------------------------------
-// Name: IsErrorEnabled()
-// Desc: Check if enabled for ERROR level
-//-----------------------------------------------------------------------------
-bool CNetLogger::IsErrorEnabled( void ) const
-{
- return ( LOG_LEVEL_ERROR >= m_Level );
-}
-
-//-----------------------------------------------------------------------------
-// Name: IsFatalEnabled()
-// Desc: Check if enabled for FATAL level
-//-----------------------------------------------------------------------------
-bool CNetLogger::IsFatalEnabled( void ) const
-{
- return ( LOG_LEVEL_FATAL >= m_Level );
-}
-
-//-----------------------------------------------------------------------------
-// Name: IsInfoEnabled()
-// Desc: Check if enabled for INFO level
-//-----------------------------------------------------------------------------
-bool CNetLogger::IsInfoEnabled( void ) const
-{
- return ( LOG_LEVEL_INFO >= m_Level );
-}
-
-//-----------------------------------------------------------------------------
-// Name: IsWarnEnabled()
-// Desc: Check if enabled for WARN level
-//-----------------------------------------------------------------------------
-bool CNetLogger::IsWarnEnabled( void ) const
-{
- return ( LOG_LEVEL_WARN >= m_Level );
-}
-
-//-----------------------------------------------------------------------------
-// Name: Debug()
-// Desc: Log a message with DEBUG level
-//-----------------------------------------------------------------------------
-void CNetLogger::Debug( const CStr& message )
-{
- if ( IsDebugEnabled() )
- {
- // Get timestamp as a string
- CStr timer;
- GetStringTimeStamp( timer );
-
- CStr eventMessage = "DEBUG";
- eventMessage += " - ";
- eventMessage += timer;
- eventMessage += " ";
- eventMessage += message;
- eventMessage += "\n";
-
- CNetLogEvent newEvent( LOG_LEVEL_DEBUG, eventMessage, m_Name );
-
- CallSinks( newEvent );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: Debug()
-// Desc: Log a formatted message with DEBUG level
-//-----------------------------------------------------------------------------
-void CNetLogger::DebugFormat( const char* pFormat, ... )
-{
- if ( IsDebugEnabled() )
- {
- char buffer[ 512 ] = { 0 };
- CStr timer;
- va_list args;
-
- // Get timestamp as a string
- GetStringTimeStamp( timer );
-
- // Get arguments as a string
- va_start ( args, pFormat );
- vsnprintf ( buffer, 512, pFormat, args );
- va_end ( args );
-
- // Format message (e.g. ERROR - Hello World)
- CStr eventMessage = "DEBUG";
- eventMessage += " - ";
- eventMessage += timer;
- eventMessage += " ";
- eventMessage += buffer;
- eventMessage += "\n";
-
- CNetLogEvent newEvent( LOG_LEVEL_DEBUG, eventMessage, m_Name );
-
- CallSinks( newEvent );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: Error()
-// Desc: Log a message with ERROR level
-//-----------------------------------------------------------------------------
-void CNetLogger::Error( const CStr& message )
-{
- if ( IsErrorEnabled() )
- {
- // Get timestamp as a string
- CStr timer;
- GetStringTimeStamp( timer );
-
- CStr eventMessage = "ERROR";
- eventMessage += " - ";
- eventMessage += timer;
- eventMessage += " ";
- eventMessage += message;
- eventMessage += "\n";
-
- CNetLogEvent newEvent( LOG_LEVEL_ERROR, eventMessage, m_Name );
-
- CallSinks( newEvent );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: Error()
-// Desc: Log a formatted message with ERROR level
-//-----------------------------------------------------------------------------
-void CNetLogger::ErrorFormat( const char* pFormat, ... )
-{
- if ( IsErrorEnabled() )
- {
- char buffer[ 512 ] = { 0 };
- CStr timer;
- va_list args;
-
- // Get timestamp as a string
- GetStringTimeStamp( timer );
-
- // Get arguments as a string
- va_start ( args, pFormat );
- vsnprintf ( buffer, 512, pFormat, args );
- va_end ( args );
-
- // Format message (e.g. ERROR - Hello World)
- CStr eventMessage = "ERROR";
- eventMessage += " - ";
- eventMessage += timer;
- eventMessage += " ";
- eventMessage += buffer;
- eventMessage += "\n";
-
- CNetLogEvent newEvent( LOG_LEVEL_ERROR, eventMessage, m_Name );
-
- CallSinks( newEvent );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: Fatal()
-// Desc: Log a message with FATAL level
-//-----------------------------------------------------------------------------
-void CNetLogger::Fatal( const CStr& message )
-{
- if ( IsFatalEnabled() )
- {
- // Get timestamp as a string
- CStr timer;
- GetStringTimeStamp( timer );
-
- CStr eventMessage = "FATAL";
- eventMessage += " - ";
- eventMessage += timer;
- eventMessage += " ";
- eventMessage += message;
- eventMessage += "\n";
-
- CNetLogEvent newEvent( LOG_LEVEL_FATAL, eventMessage, m_Name );
-
- CallSinks( newEvent );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: Fatal()
-// Desc: Log a formatted message with FATAL error
-//-----------------------------------------------------------------------------
-void CNetLogger::FatalFormat( const char* pFormat, ... )
-{
- if ( IsFatalEnabled() )
- {
- char buffer[ 512 ] = { 0 };
- CStr timer;
- va_list args;
-
- // Get timestamp as a string
- GetStringTimeStamp( timer );
-
- // Get arguments as a string
- va_start ( args, pFormat );
- vsnprintf ( buffer, 512, pFormat, args );
- va_end ( args );
-
- // Format message (e.g. ERROR - Hello World)
- CStr eventMessage = "FATAL";
- eventMessage += " - ";
- eventMessage += timer;
- eventMessage += " ";
- eventMessage += buffer;
- eventMessage += "\n";
-
- CNetLogEvent newEvent( LOG_LEVEL_FATAL, eventMessage, m_Name );
-
- CallSinks( newEvent );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: Info()
-// Desc: Log a message with INFO level
-//-----------------------------------------------------------------------------
-void CNetLogger::Info( const CStr& message )
-{
- if ( IsInfoEnabled() )
- {
- // Get timestamp as a string
- CStr timer;
- GetStringTimeStamp( timer );
-
- CStr eventMessage = "INFO";
- eventMessage += " - ";
- eventMessage += timer;
- eventMessage += " ";
- eventMessage += message;
- eventMessage += "\n";
-
- CNetLogEvent newEvent( LOG_LEVEL_INFO, eventMessage, m_Name );
-
- CallSinks( newEvent );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: Info()
-// Desc: Log a formatted message with INFO level
-//-----------------------------------------------------------------------------
-void CNetLogger::InfoFormat( const char* pFormat, ... )
-{
- if ( IsInfoEnabled() )
- {
- char buffer[ 512 ] = { 0 };
- CStr timer;
- va_list args;
-
- // Get timestamp as a string
- GetStringTimeStamp( timer );
-
- // Get arguments as a string
- va_start ( args, pFormat );
- vsnprintf ( buffer, 512, pFormat, args );
- va_end ( args );
-
- // Format message (e.g. ERROR - Hello World)
- CStr eventMessage = "INFO";
- eventMessage += " - ";
- eventMessage += timer;
- eventMessage += " ";
- eventMessage += buffer;
- eventMessage += "\n";
-
- CNetLogEvent newEvent( LOG_LEVEL_INFO, eventMessage, m_Name );
-
- CallSinks( newEvent );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: Warn()
-// Desc: Log a message with WARN level
-//-----------------------------------------------------------------------------
-void CNetLogger::Warn( const CStr& message )
-{
- if ( IsWarnEnabled() )
- {
- // Get timestamp as a string
- CStr timer;
- GetStringTimeStamp( timer );
-
- CStr eventMessage = "WARN";
- eventMessage += " - ";
- eventMessage += timer;
- eventMessage += " ";
- eventMessage += message;
- eventMessage += "\n";
-
- CNetLogEvent newEvent( LOG_LEVEL_WARN, eventMessage, m_Name );
-
- CallSinks( newEvent );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: Warn()
-// Desc: Log a formatted message with WARN level
-//-----------------------------------------------------------------------------
-void CNetLogger::WarnFormat( const char* pFormat, ... )
-{
- if ( IsWarnEnabled() )
- {
- char buffer[ 512 ] = { 0 };
- CStr timer;
- va_list args;
-
- // Get timestamp as a string
- GetStringTimeStamp( timer );
-
- // Get arguments as a string
- va_start ( args, pFormat );
- vsnprintf ( buffer, 512, pFormat, args );
- va_end ( args );
-
- // Format message (e.g. ERROR - Hello World)
- CStr eventMessage = "WARN";
- eventMessage += " - ";
- eventMessage += timer;
- eventMessage += " ";
- eventMessage += buffer;
- eventMessage += "\n";
-
- CNetLogEvent newEvent( LOG_LEVEL_WARN, eventMessage, m_Name );
-
- CallSinks( newEvent );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: AddSink()
-// Desc: Attaches a new sink
-//-----------------------------------------------------------------------------
-void CNetLogger::AddSink( CNetLogSink* pSink )
-{
- size_t i;
- CScopeLock lock( m_Mutex );
-
- assert( pSink );
-
- // Validate parameter
- if ( !pSink ) return;
-
- // Check if already exists
- for ( i = 0; i < GetSinkCount(); i++ )
- {
- CNetLogSink* pCurrSink = GetSink( i );
- if ( pCurrSink == pSink ) break;
- }
-
- // Already exists?
- if ( i >= GetSinkCount() )
- {
- // Activate new sink
- pSink->Activate();
-
- // Add new sink to list
- m_Sinks.push_back( pSink );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: RemoveSink()
-// Desc: Removes the sink from the list of attached sinks
-//-----------------------------------------------------------------------------
-CNetLogSink* CNetLogger::RemoveSink( CNetLogSink* pSink )
-{
- CScopeLock lock( m_Mutex );
-
- // Validate parameter
- if ( !pSink ) return NULL;
-
- // Lookup the sink object
- SinkList::iterator it = m_Sinks.begin();
- for ( ; it != m_Sinks.end(); it++ )
- {
- CNetLogSink* pCurrSink = *it;
- if ( pCurrSink == pSink )
- {
- m_Sinks.erase( it );
-
- return pCurrSink;
- }
- }
-
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// Name: RemoveSink()
-// Desc: Removes the named sink
-//-----------------------------------------------------------------------------
-CNetLogSink* CNetLogger::RemoveSink( const CStr& name )
-{
- CScopeLock lock( m_Mutex );
-
- // Lookup sink by name
- SinkList::iterator it = m_Sinks.begin();
- for ( ; it != m_Sinks.end(); it++ )
- {
- CNetLogSink* pCurrSink = *it;
- if ( !pCurrSink ) continue;
-
- if ( pCurrSink->GetName() == name )
- {
- m_Sinks.erase( it );
-
- return pCurrSink;
- }
- }
-
- // Sink not found
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// Name: RemoveAllSinks()
-// Desc: Remove all attached sinks
-//-----------------------------------------------------------------------------
-void CNetLogger::RemoveAllSinks( void )
-{
- CScopeLock lock( m_Mutex );
-
- for ( size_t i = 0; i < GetSinkCount(); i++ )
- delete m_Sinks[i];
- m_Sinks.clear();
-}
-
-//-----------------------------------------------------------------------------
-// Name: GetSinkCount()
-// Desc: Retrive the number of attached sinks
-//-----------------------------------------------------------------------------
-size_t CNetLogger::GetSinkCount( void )
-{
- return m_Sinks.size();
-}
-
-//-----------------------------------------------------------------------------
-// Name: GetSink()
-// Desc: Retrieves the sink by index
-//-----------------------------------------------------------------------------
-CNetLogSink* CNetLogger::GetSink( size_t index )
-{
- // Validate parameter
- if ( index > m_Sinks.size() ) return NULL;
-
- return m_Sinks[ index ];
-}
-
-//-----------------------------------------------------------------------------
-// Name: GetSink()
-// Desc: Retrieve the sink by name
-//-----------------------------------------------------------------------------
-CNetLogSink* CNetLogger::GetSink( const CStr& name )
-{
- for ( size_t i = 0; i < GetSinkCount(); i++ )
- {
- CNetLogSink* pCurrSink = GetSink( i );
- if ( !pCurrSink ) continue;
-
- if ( pCurrSink->GetName() == name )
- return pCurrSink;
- }
-
- // Sink not found
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// Name: CallSinks()
-// Desc:
-//-----------------------------------------------------------------------------
-void CNetLogger::CallSinks( const CNetLogEvent& event )
-{
- for ( size_t i = 0; i < GetSinkCount(); i++ )
- {
- CNetLogSink* pCurrSink = GetSink( i );
- if ( !pCurrSink ) continue;
-
- pCurrSink->DoSink( event );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Name: GetStringLocalTime()
-// Desc: Returns the local date time into the passed in string
-//-----------------------------------------------------------------------------
-void CNetLogger::GetStringDateTime( CStr &str )
-{
- char buffer[ 128 ] = { 0 };
- time_t tm;
- struct tm *now;
-
-#if OS_WIN
- // Set timezone
- _tzset();
-
- // Get time and convert to tm structure
- time( &tm );
- struct tm nowBuf;
- localtime_s( &nowBuf, &tm );
- now = &nowBuf;
-#else
- time ( &tm );
- now = localtime( &tm );
-#endif
-
- // Build custom time string
- strftime( buffer, 128, "%Y-%m-%d %H:%M:%S", now );
-
- str = buffer;
-}
-
-//-----------------------------------------------------------------------------
-// Name: GetStringTime()
-// Desc: Returns the local time into the passed string
-//-----------------------------------------------------------------------------
-void CNetLogger::GetStringTime( CStr& str )
-{
- char buffer[ 128 ] = { 0 };
- time_t tm;
- struct tm *now;
-
-#if OS_WIN
- // Set timezone
- _tzset();
-
- // Get time and convert to tm structure
- time( &tm );
- struct tm nowBuf;
- localtime_s( &nowBuf, &tm );
- now = &nowBuf;
-#else
- time ( &tm );
- now = localtime( &tm );
-#endif
-
- // Build custom time string
- strftime( buffer, 128, "%H%M%S", now );
-
- str = buffer;
-}
-
-//-----------------------------------------------------------------------------
-// Name: GetStringTimeStamp()
-// Desc: Returns the formatted current time into the passed string
-//-----------------------------------------------------------------------------
-void CNetLogger::GetStringTimeStamp( CStr& str )
-{
- char buffer[ 128 ] = { 0 };
- double timestamp = timer_Time();
- sprintf_s( buffer, ARRAY_SIZE(buffer), "[%3u.%03u]", ( unsigned )timestamp, ( ( unsigned )( timestamp * 1000 ) % 1000 ) );
- str = buffer;
-}
-
-// List of loggers under log manager
-LoggerList CNetLogManager::m_Loggers;
-
-//-----------------------------------------------------------------------------
-// Name: Shutdown()
-// Desc: Shuts down the log manager
-//-----------------------------------------------------------------------------
-void CNetLogManager::Shutdown( void )
-{
- // Remove all loggers
- LoggerList::iterator it = m_Loggers.begin();
- for ( ; it != m_Loggers.end(); it++ )
- {
- CNetLogger *pCurrLogger = *it;
- if ( !pCurrLogger ) continue;
-
- pCurrLogger->RemoveAllSinks();
-
- delete pCurrLogger;
- }
-
- m_Loggers.clear();
-}
-
-//-----------------------------------------------------------------------------
-// Name: GetLogger()
-// Desc: Retrieve or create a named logger
-//-----------------------------------------------------------------------------
-CNetLogger* CNetLogManager::GetLogger( const CStr& name )
-{
- LoggerList::const_iterator it = m_Loggers.begin();
- for ( ; it != m_Loggers.end(); it++ )
- {
- CNetLogger* pCurrLogger = *it;
- if ( !pCurrLogger ) continue;
-
- if ( pCurrLogger->GetName() == name )
- return pCurrLogger;
- }
-
- // Logger not found, create it
- CNetLogger* pNewLogger = new CNetLogger( name );
- if ( !pNewLogger ) return NULL;
-
- // Add new logger to list
- m_Loggers.push_back( pNewLogger );
-
- return pNewLogger;
-}
-
-//-----------------------------------------------------------------------------
-// Name: GetAllLoggers()
-// Desc: Return the list of loggers
-//-----------------------------------------------------------------------------
-const LoggerList& CNetLogManager::GetAllLoggers( void )
-{
- return m_Loggers;
-}
-
-
diff --git a/source/network/NetLog.h b/source/network/NetLog.h
deleted file mode 100644
index d2e957e3ee..0000000000
--- a/source/network/NetLog.h
+++ /dev/null
@@ -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 .
- */
-
-/**
- *-----------------------------------------------------------------------------
- * 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
-#include
-#include
-
-// 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
-
diff --git a/source/network/NetServer.cpp b/source/network/NetServer.cpp
index aae278cd4b..95e4a68756 100644
--- a/source/network/NetServer.cpp
+++ b/source/network/NetServer.cpp
@@ -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 );
}
diff --git a/source/network/NetServer.h b/source/network/NetServer.h
index 5bd6dbd12d..428a7a4404 100644
--- a/source/network/NetServer.h
+++ b/source/network/NetServer.h
@@ -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;
/*
diff --git a/source/network/NetSession.cpp b/source/network/NetSession.cpp
index ce2f5af95f..c519a3ba8d 100644
--- a/source/network/NetSession.cpp
+++ b/source/network/NetSession.cpp
@@ -15,477 +15,37 @@
* along with 0 A.D. If not, see .
*/
-/**
- *-----------------------------------------------------------------------------
- * 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::ScriptingInit( "NetSession" );
+ CJSObject::ScriptingInit("NetSession");
}
diff --git a/source/network/NetSession.h b/source/network/NetSession.h
index 00e6408d4a..d06d0108a2 100644
--- a/source/network/NetSession.h
+++ b/source/network/NetSession.h
@@ -15,170 +15,39 @@
* along with 0 A.D. If not, see .
*/
-/**
- *-----------------------------------------------------------------------------
- * 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
+#include "scripting/ScriptableObject.h"
-#include
-
-// 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 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
{
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
-
diff --git a/source/network/Network.h b/source/network/Network.h
index 87da0f4b10..d093f121b8 100644
--- a/source/network/Network.h
+++ b/source/network/Network.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)
{
}
diff --git a/source/network/fsm.h b/source/network/fsm.h
index 3162c5a13d..63a4b80f74 100644
--- a/source/network/fsm.h
+++ b/source/network/fsm.h
@@ -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;
diff --git a/source/network/tests/test_Net.h b/source/network/tests/test_Net.h
new file mode 100644
index 0000000000..a415786a50
--- /dev/null
+++ b/source/network/tests/test_Net.h
@@ -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 .
+ */
+
+#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
+ }
+};
diff --git a/source/ps/CLogger.h b/source/ps/CLogger.h
index 256b008001..0452659126 100644
--- a/source/ps/CLogger.h
+++ b/source/ps/CLogger.h
@@ -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
{
diff --git a/source/ps/ConfigDB.h b/source/ps/ConfigDB.h
index 52e79f498e..d129ce24d4 100644
--- a/source/ps/ConfigDB.h
+++ b/source/ps/ConfigDB.h
@@ -50,7 +50,6 @@
#ifndef INCLUDED_CONFIGDB
#define INCLUDED_CONFIGDB
-#include "Pyrogenesis.h"
#include "Parser.h"
#include "CStr.h"
#include "Singleton.h"
diff --git a/source/ps/GameAttributes.cpp b/source/ps/GameAttributes.cpp
index f35ed94726..eb24434e16 100644
--- a/source/ps/GameAttributes.cpp
+++ b/source/ps/GameAttributes.cpp
@@ -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),
diff --git a/source/ps/GameAttributes.h b/source/ps/GameAttributes.h
index a95828947e..27355e4ca4 100644
--- a/source/ps/GameAttributes.h
+++ b/source/ps/GameAttributes.h
@@ -133,8 +133,7 @@ namespace PlayerSlotArray_JS
}
class CGameAttributes:
- public CSynchedJSObject,
- public Singleton
+ public CSynchedJSObject
{
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
diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp
index c4dfd7e654..12ec7f3c92 100644
--- a/source/ps/GameSetup/GameSetup.cpp
+++ b/source/ps/GameSetup/GameSetup.cpp
@@ -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();
diff --git a/source/ps/Pyrogenesis.cpp b/source/ps/Pyrogenesis.cpp
index fc65bf07d8..f72154c2bc 100644
--- a/source/ps/Pyrogenesis.cpp
+++ b/source/ps/Pyrogenesis.cpp
@@ -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
diff --git a/source/ps/Pyrogenesis.h b/source/ps/Pyrogenesis.h
index e13cab0fc5..3bc0850e75 100644
--- a/source/ps/Pyrogenesis.h
+++ b/source/ps/Pyrogenesis.h
@@ -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);
diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp
index 3af0eb87bb..a57435a91e 100644
--- a/source/scripting/ScriptGlue.cpp
+++ b/source/scripting/ScriptGlue.cpp
@@ -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;
}
diff --git a/source/scripting/ScriptableObject.h b/source/scripting/ScriptableObject.h
index a9f8fbb9aa..c1347bbf74 100644
--- a/source/scripting/ScriptableObject.h
+++ b/source/scripting/ScriptableObject.h
@@ -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
diff --git a/source/scripting/ScriptingHost.cpp b/source/scripting/ScriptingHost.cpp
index 078cc38485..e872b1154c 100644
--- a/source/scripting/ScriptingHost.cpp
+++ b/source/scripting/ScriptingHost.cpp
@@ -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 )
{
diff --git a/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp
index a5b54c05e9..a5aa619498 100644
--- a/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp
+++ b/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp
@@ -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();