1
0
forked from 0ad/0ad

# Delete a lot of obsolete networking code.

Remove the -sim1 flag since it no longer works.

This was SVN commit r7554.
This commit is contained in:
Ykkrosh 2010-05-20 17:58:37 +00:00
parent 08e383235b
commit a78e6dbe26
31 changed files with 65 additions and 5570 deletions

View File

@ -195,6 +195,9 @@ void CMiniMap::FireWorldClickEvent(int button, int clicks)
Destination.y = CELL_SIZE * m_MapSize * ( (m_CachedActualSize.bottom - MousePos.y) /
m_CachedActualSize.GetHeight() );
UNUSED2(button);
UNUSED2(clicks);
/*
g_JSGameEvents.FireWorldClick(
button,
clicks,
@ -205,6 +208,7 @@ void CMiniMap::FireWorldClickEvent(int button, int clicks)
NULL,
(int)Destination.x,
(int)Destination.y);
*/
}
// render view rect : John M. Mena

View File

@ -57,7 +57,6 @@ that of Atlas depending on commandline parameters.
#include "ps/XML/Xeromyces.h"
#include "network/NetClient.h"
#include "network/NetServer.h"
//#include "network/SessionManager.h"
#include "network/NetSession.h"
#include "graphics/Camera.h"
#include "graphics/GameView.h"
@ -258,7 +257,6 @@ static void Frame()
MICROLOG(L"input");
PumpEvents();
PROFILE_END("input");
//g_SessionManager.Poll();
PROFILE_START("network poll");
if (g_NetServer)
@ -389,11 +387,6 @@ static void RunGameOrAtlas(int argc, const char* argv[])
// might run Atlas.
CXeromyces::Startup();
// allow switching to old simulation system, before any
// other init code makes use of it
if (args.Has("sim1"))
g_UseSimulation2 = false;
// run Atlas (if requested via args)
bool ran_atlas = ATLAS_RunIfOnCmdLine(args);
// Atlas handles the whole init/shutdown/etc sequence by itself;

View File

@ -47,17 +47,6 @@
CNetClient *g_NetClient = NULL;
class CClientTurnManager : public CTurnManager
{
public:
CClientTurnManager(CNetClient& client) : m_Client(client) { }
virtual void QueueLocalCommand(CNetMessage* pMessage);
virtual void NewTurn();
virtual bool NewTurnReady() { return m_Client.m_TurnPending; }
private:
CNetClient& m_Client;
};
//-----------------------------------------------------------------------------
// Name: CServerPlayer()
// Desc: Constructor
@ -95,19 +84,12 @@ void CServerPlayer::ScriptingInit( void )
CNetClient::CNetClient( CGame* pGame, CGameAttributes* pGameAttribs )
: m_JsPlayers( &m_Players )
{
m_TurnManager = new CClientTurnManager(*this);
m_ClientTurnManager = NULL;
m_pLocalPlayerSlot = NULL;
m_pGame = pGame;
m_pGameAttributes = pGameAttribs;
m_TurnPending = false;
//ONCE( ScriptingInit(); );
if (!g_UseSimulation2)
m_pGame->GetSimulation()->SetTurnManager(m_TurnManager);
g_ScriptingHost.SetGlobal("g_NetClient", OBJECT_TO_JSVAL(GetScript()));
}
@ -147,14 +129,11 @@ void CNetClient::ScriptingInit()
AddProperty(L"password", &CNetClient::m_Password);
AddProperty<CStr>(L"playerName", &CNetClient::m_Nickname);
//AddProperty(L"sessionId", &CNetClient::m_SessionID);
AddProperty(L"sessions", &CNetClient::m_JsPlayers);
CJSMap< PlayerMap >::ScriptingInit("NetClient_SessionMap");
CJSObject<CNetClient>::ScriptingInit("NetClient");
//CGameAttributes::ScriptingInit();
//CServerPlayer::ScriptingInit();
}
//-----------------------------------------------------------------------------
@ -211,18 +190,6 @@ bool CNetClient::SetupSession( CNetSession* pSession )
pSession->AddTransition( NCS_PREGAME, ( uint )NMT_GAME_START, NCS_INGAME, (void*)&OnStartGame_, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_CHAT, NCS_INGAME, (void*)&OnChat, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_GOTO, NCS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_PATROL, NCS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_ADD_WAYPOINT, NCS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_CONTACT_ACTION, NCS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_PRODUCE, NCS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_PLACE_OBJECT, NCS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_RUN, NCS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_SET_RALLY_POINT, NCS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_SET_STANCE, NCS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_NOTIFY_REQUEST, NCS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_FORMATION_GOTO, NCS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_FORMATION_CONTACT_ACTION, NCS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_SIMULATION_COMMAND, NCS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NCS_INGAME, ( uint )NMT_END_COMMAND_BATCH, NCS_INGAME, (void*)&OnInGame, pContext );
@ -425,15 +392,6 @@ bool CNetClient::OnPreGame( void* pContext, CFsmEvent* pEvent )
switch ( pEvent->GetType() )
{
//CHAIN(BaseHandler);
//CHAIN(ChatHandler);
// case NMT_GAME_START:
// pClient->StartGame();
// break;
case NMT_PLAYER_LEAVE:
{
CPlayerLeaveMessage* pMessage = ( CPlayerLeaveMessage* )pEvent->GetParamRef();
@ -531,38 +489,13 @@ bool CNetClient::OnInGame( void *pContext, CFsmEvent* pEvent )
return true;
}
if ( pMessage->GetType() >= NMT_COMMAND_FIRST && pMessage->GetType() < NMT_COMMAND_LAST )
{
pClient->QueueIncomingMessage( pMessage );
return true;
}
if ( pMessage->GetType() == NMT_END_COMMAND_BATCH )
{
CEndCommandBatchMessage* pMessage = ( CEndCommandBatchMessage* )pEvent->GetParamRef();
if ( !pMessage ) return false;
if (g_UseSimulation2)
{
CEndCommandBatchMessage* endMessage = static_cast<CEndCommandBatchMessage*> (pMessage);
pClient->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn);
}
pClient->m_TurnManager->SetTurnLength( 1, pMessage->m_TurnLength );
pClient->m_TurnPending = true;
// FIXME When the command batch has ended, we should start accepting
// commands for the next turn. This will be accomplished by calling
// NewTurn. *BUT* we shouldn't prematurely proceed game simulation
// since this will produce jerky playback (everything expects a sim
// turn to have a certain duration).
// We should make sure that any commands received after this message
// are queued in the next batch (#2 instead of #1). If we're already
// putting everything new in batch 2 - we should fast-forward a bit to
// catch up with the server.
CEndCommandBatchMessage* endMessage = static_cast<CEndCommandBatchMessage*> (pMessage);
pClient->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn);
}
}
@ -622,11 +555,8 @@ bool CNetClient::OnStartGame_( void* pContext, CFsmEvent* pEvent )
CNetClient* pClient = ( CNetClient* )( ( FsmActionCtx* )pContext )->pHost;
CNetSession* pSession = ( ( FsmActionCtx* )pContext )->pSession;
if (g_UseSimulation2)
{
pClient->m_ClientTurnManager = new CNetClientTurnManager(*pClient->m_pGame->GetSimulation2(), *pClient, pClient->GetLocalPlayer()->GetPlayerID(), pSession->GetID());
pClient->m_pGame->SetTurnManager(pClient->m_ClientTurnManager);
}
pClient->m_ClientTurnManager = new CNetClientTurnManager(*pClient->m_pGame->GetSimulation2(), *pClient, pClient->GetLocalPlayer()->GetPlayerID(), pSession->GetID());
pClient->m_pGame->SetTurnManager(pClient->m_ClientTurnManager);
pClient->OnStartGame();
@ -689,16 +619,6 @@ int CNetClient::StartGame( void )
if ( m_pGame->StartGame( m_pGameAttributes ) != PSRETURN_OK ) return -1;
if (!g_UseSimulation2)
{
// Send an end-of-batch message for turn 0 to signal that we're ready.
CEndCommandBatchMessage endBatch;
endBatch.m_TurnLength = 1000 / g_frequencyFilter->StableFrequency();
CNetSession* pSession = GetSession( 0 );
SendMessage( pSession, &endBatch );
}
return 0;
}
@ -710,47 +630,3 @@ CPlayer* CNetClient::GetLocalPlayer()
{
return m_pLocalPlayerSlot->GetPlayer();
}
//-----------------------------------------------------------------------------
// Name: NewTurn()
// Desc:
//-----------------------------------------------------------------------------
void CClientTurnManager::NewTurn()
{
CScopeLock lock(m_Client.m_Mutex);
RotateBatches();
ClearBatch(2);
m_Client.m_TurnPending = false;
//debug_printf(L"In NewTurn - sending ack\n");
CEndCommandBatchMessage* pMsg = new CEndCommandBatchMessage;
pMsg->m_TurnLength=1000/g_frequencyFilter->StableFrequency(); // JW: it'd probably be nicer to get the FPS as a parameter
CNetSession* pSession = m_Client.GetSession( 0 );
m_Client.SendMessage( pSession, pMsg );
}
//-----------------------------------------------------------------------------
// Name: QueueLocalCommand()
// Desc:
//-----------------------------------------------------------------------------
void CClientTurnManager::QueueLocalCommand( CNetMessage* pMessage )
{
if ( !pMessage ) return;
// Don't save these locally, since they'll be bounced by the server anyway
CNetSession* pSession = m_Client.GetSession( 0 );
m_Client.SendMessage( pSession, pMessage );
}
//-----------------------------------------------------------------------------
// Name: QueueIncomingMessage()
// Desc:
//-----------------------------------------------------------------------------
void CNetClient::QueueIncomingMessage( CNetMessage* pMessage )
{
CScopeLock lock( m_Mutex );
m_TurnManager->QueueMessage( 2, pMessage );
}

View File

@ -30,7 +30,6 @@
#include "NetSession.h"
#include "NetTurnManager.h"
#include "ps/CStr.h"
#include "simulation/TurnManager.h"
#include "simulation/ScriptObject.h"
#include "scripting/ScriptableObject.h"
#include "ps/scripting/JSMap.h"
@ -53,16 +52,12 @@ class CGame;
class CGameAttributes;
class CServerPlayer;
//typedef std::map< uint, CStr > PlayerMap;
typedef std::map< uint, CServerPlayer* > PlayerMap;
/*
CLASS : CServerPlayer
DESCRIPTION :
NOTES :
*/
class CServerPlayer : public CJSObject< CServerPlayer >
{
NONCOPYABLE(CServerPlayer);
public:
CServerPlayer( uint sessionID, const CStr& nickname );
@ -71,23 +66,13 @@ public:
static void ScriptingInit( void );
uint GetSessionID( void ) const { return m_SessionID; }
const CStr GetNickname( void ) const { return m_Nickname; }
protected:
private:
CServerPlayer( const CServerPlayer& );
CServerPlayer& operator=( const CServerPlayer& );
uint m_SessionID; // Player session ID
CStr m_Nickname; // Player nickname
};
/*
CLASS : CNetClient
DESCRIPTION :
NOTES :
*/
class CNetClient: public CNetHost,
public CJSObject<CNetClient>
{
@ -102,13 +87,6 @@ public:
void OnPlayer ( uint ID, const CStr& name );
void OnPlayerLeave ( uint ID );
/**
* Returns true indicating the host acts as a client
*
* @return Always true
*/
virtual bool IsClient( void ) const { return true; }
// Get a pointer to our player
CPlayer* GetLocalPlayer();
@ -116,20 +94,11 @@ public:
CStr m_Nickname;
CStr m_Password;
//int m_SessionID;
CPlayerSlot *m_pLocalPlayerSlot;
CGame *m_pGame;
CGameAttributes *m_pGameAttributes;
// Are we currently in a locally-yet-unsimulated turn?
// This is set to true when we receive a command batch and cleared in NewTurn().
// The server also ensures that it does not send a new turn until we ack one.
bool m_TurnPending;
// Mutex for accessing batches
CMutex m_Mutex;
// JS event scripts
CScriptObject m_OnStartGame;
CScriptObject m_OnChat;
@ -141,16 +110,12 @@ public:
static void ScriptingInit( void );
int StartGame( void );
CNetTurnManager* GetTurnManager() { debug_assert(m_ClientTurnManager); return m_ClientTurnManager; }
protected:
virtual bool SetupSession ( CNetSession* pSession );
virtual bool HandleConnect ( CNetSession* pSession );
virtual bool HandleDisconnect ( CNetSession *pSession );
void QueueIncomingMessage ( CNetMessage* pMessage );
virtual void OnConnectComplete ( void );
virtual void OnStartGame ( void );
@ -168,10 +133,8 @@ private:
bool SetupConnection( JSContext *cx, uintN argc, jsval *argv );
//CNetSession* m_Session; // Server session
PlayerMap m_Players; // List of online players
CTurnManager* m_TurnManager;
CNetClientTurnManager* m_ClientTurnManager;
};

View File

@ -25,8 +25,6 @@
// INCLUDES
#include "precompiled.h"
#include "simulation/Entity.h"
#include "ps/Vector2D.h"
#include "ps/CLogger.h"
#include "Network.h"
#include "NetMessage.h"
@ -38,9 +36,6 @@
#define ALLNETMSGS_IMPLEMENT
#include "NetMessages.h"
#include <stdio.h>
#include <map>
// DEFINES
#define LOG_CATEGORY L"net"
@ -113,45 +108,6 @@ const u8* CNetMessage::Deserialize( const u8* pStart, const u8* pEnd )
return pBuffer;
}
//-----------------------------------------------------------------------------
// Name: Deserialize()
// Desc: Constructs a CNetMessage object from the specified buffer parameter
// Note: It uses the registered desrializers to create the CNetMessage object
//-----------------------------------------------------------------------------
/*CNetMessage* CNetMessage::Deserialize(
NetMessageType type,
const u8* pBuffer,
uint bufferSize )
{
ONCE
(
SNetMessageDeserializer* pDeserializer = &g_DeserializerRegistrations[ 0 ];
for ( ; pDeserializer->Deserializer; pDeserializer++ )
{
g_DeserializerMap.insert( std::make_pair(
pDeserializer->Type,
pDeserializer->Deserializer ) );
}
);
MessageDeserializerMap::const_iterator it = g_DeserializerMap.find( type );
if ( it == g_DeserializerMap.end() )
{
LOG(WARNING, LOG_CATEGORY, L"Unknown message received on socket: type 0x%04x, length %u", type, length);
return NULL;
}
pfnNetMessageDeserializer pDeserializer = it->second;
if ( pDeserializer )
{
// Call deserializer
return ( pDeserializer )( pBuffer, bufferSize );
}
return NULL;
}*/
//-----------------------------------------------------------------------------
// Name: GetSerializedLength()
// Desc: Returns the size of the serialized message
@ -162,42 +118,6 @@ size_t CNetMessage::GetSerializedLength( void ) const
return 3;
}
//-----------------------------------------------------------------------------
// Name: operator ( ENetPacket* )()
// Desc: Cast to an ENetPacket structure
//-----------------------------------------------------------------------------
/*void CNetMessage::operator ENetPacket*( void )
{
// Did we already serialized the message?
if ( m_Packet )
{
// Dirty message?
if ( m_Dirty )
{
// Make room for the new message content
enet_packet_resize( m_Packet, GetSerializedLength() );
// Serialize into buffer
Serialize( m_Packet->data );
}
}
else
{
// Serialize message into temporary buffer
u8* pBuffer = new u8[ GetSerializedLength() ];
if ( !pBuffer ) return NULL;
Serialize( pBuffer );
// Create ENet packet for this message
m_Packet = enet_packet_create( pBuffer, GetSerializedLength(), ENET_PACKET_FLAG_RELIABLE );
delete [] pBuffer;
}
return m_Packet;
}*/
//-----------------------------------------------------------------------------
// Name: ToString()
// Desc: Returns a string representation for the message
@ -219,710 +139,6 @@ CStr CNetMessage::ToString( void ) const
return ret;
}
//-----------------------------------------------------------------------------
// Name: ScriptingInit()
// Desc:
//-----------------------------------------------------------------------------
void CNetMessage::ScriptingInit()
{
g_ScriptingHost.DefineConstant( "NMT_GOTO", NMT_GOTO );
g_ScriptingHost.DefineConstant( "NMT_RUN", NMT_RUN );
g_ScriptingHost.DefineConstant( "NMT_PATROL", NMT_PATROL );
g_ScriptingHost.DefineConstant( "NMT_ADD_WAYPOINT", NMT_ADD_WAYPOINT );
g_ScriptingHost.DefineConstant( "NMT_CONTACT_ACTION", NMT_CONTACT_ACTION );
g_ScriptingHost.DefineConstant( "NMT_PRODUCE", NMT_PRODUCE );
g_ScriptingHost.DefineConstant( "NMT_PLACE_OBJECT", NMT_PLACE_OBJECT );
g_ScriptingHost.DefineConstant( "NMT_REMOVE_OBJECT", NMT_REMOVE_OBJECT );
g_ScriptingHost.DefineConstant( "NMT_SET_RALLY_POINT", NMT_SET_RALLY_POINT );
g_ScriptingHost.DefineConstant( "NMT_SET_STANCE", NMT_SET_STANCE );
g_ScriptingHost.DefineConstant( "NMT_NOTIFY_REQUEST", NMT_NOTIFY_REQUEST );
g_ScriptingHost.DefineConstant( "NMT_FORMATION_GOTO", NMT_FORMATION_GOTO );
g_ScriptingHost.DefineConstant( "NMT_FORMATION_CONTACT_ACTION", NMT_FORMATION_CONTACT_ACTION );
}
//-----------------------------------------------------------------------------
// Name: CommandFromJSArgs()
// Desc:
//-----------------------------------------------------------------------------
CNetMessage* CNetMessage::CommandFromJSArgs(
const CEntityList &entities,
JSContext* pContext,
uintN argc,
jsval* argv,
bool isQueued )
{
uint idx = 0;
uint messageType;
// Validate parameters
if ( argv == 0 ) return NULL;
try
{
messageType = ToPrimitive< uint >( argv[ idx++ ] );
}
catch ( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( pContext, "Invalid order type" );
return NULL;
}
switch ( messageType )
{
case NMT_GOTO:
{
CGotoMessage* pMessage = new CGotoMessage;
if ( !pMessage ) return NULL;
pMessage->m_IsQueued = isQueued;
pMessage->m_Entities = entities;
try
{
if ( idx + 2 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_INT( argv[ idx ] ) ||
!JSVAL_IS_INT( argv[ idx + 1 ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_TargetX = ToPrimitive< int >( argv[ idx++ ] );
pMessage->m_TargetY = ToPrimitive< int >( argv[ idx++ ] );
}
catch ( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( pContext, "Invalid location" );
return NULL;
}
return pMessage;
}
case NMT_RUN:
{
CRunMessage* pMessage = new CRunMessage;
if ( !pMessage ) return NULL;
pMessage->m_IsQueued = isQueued;
pMessage->m_Entities = entities;
try
{
if ( idx + 2 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_INT( argv[ idx ] ) ||
!JSVAL_IS_INT( argv[ idx + 1 ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_TargetX = ToPrimitive< int >( argv[ idx++ ] );
pMessage->m_TargetY = ToPrimitive< int >( argv[ idx++ ] );
}
catch ( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( pContext, "Invalid location" );
return NULL;
}
return pMessage;
}
case NMT_PATROL:
{
CPatrolMessage* pMessage = new CPatrolMessage;
if ( pMessage ) return NULL;
pMessage->m_IsQueued = isQueued;
pMessage->m_Entities = entities;
try
{
if ( idx + 2 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_INT( argv[ idx ] ) ||
!JSVAL_IS_INT( argv[ idx + 1 ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_TargetX = ToPrimitive< int >( argv[ idx++ ] );
pMessage->m_TargetY = ToPrimitive< int >( argv[ idx++ ] );
}
catch ( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( pContext, "Invalid location" );
return NULL;
}
return pMessage;
}
case NMT_ADD_WAYPOINT:
{
CAddWaypointMessage* pMessage = new CAddWaypointMessage;
if ( !pMessage ) return NULL;
pMessage->m_IsQueued = isQueued;
pMessage->m_Entities = entities;
try
{
if ( idx + 2 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_INT( argv[ idx ] ) ||
!JSVAL_IS_INT( argv[ idx + 1 ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_TargetX = ToPrimitive< int >( argv[ idx++ ] );
pMessage->m_TargetY = ToPrimitive< int >( argv[ idx++ ] );
}
catch ( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( pContext, "Invalid location" );
return NULL;
}
return pMessage;
}
case NMT_SET_RALLY_POINT:
{
CSetRallyPointMessage* pMessage = new CSetRallyPointMessage;
if ( !pMessage ) return NULL;
pMessage->m_IsQueued = isQueued;
pMessage->m_Entities = entities;
try
{
if ( idx + 2 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_INT( argv[ idx ] ) ||
!JSVAL_IS_INT( argv[ idx + 1 ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_TargetX = ToPrimitive< int >( argv[ idx++ ] );
pMessage->m_TargetY = ToPrimitive< int >( argv[ idx++ ] );
}
catch ( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( pContext, "Invalid location" );
return NULL;
}
return pMessage;
}
case NMT_SET_STANCE:
{
CSetStanceMessage* pMessage = new CSetStanceMessage;
if ( !pMessage ) return NULL;
pMessage->m_IsQueued = isQueued;
pMessage->m_Entities = entities;
try
{
if ( idx + 1 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_STRING( argv[ idx ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_Stance = ToPrimitive< CStrW >( argv[ idx++ ] );
}
catch ( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( pContext, "Invalid location" );
return NULL;
}
return pMessage;
}
case NMT_FORMATION_GOTO:
{
CFormationGotoMessage* pMessage = new CFormationGotoMessage;
if ( !pMessage ) return NULL;
pMessage->m_IsQueued = isQueued;
pMessage->m_Entities = entities;
try
{
if ( idx + 2 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_INT( argv[ idx ] ) ||
!JSVAL_IS_INT( argv[ idx + 1 ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_TargetX = ToPrimitive< int >( argv[ idx++ ] );
pMessage->m_TargetY = ToPrimitive< int >( argv[ idx++ ] );
}
catch ( PSERROR_Scripting_ConversionFailed )
{
JS_ReportError( pContext, "Invalid location" );
return NULL;
}
return pMessage;
}
case NMT_CONTACT_ACTION:
{
CContactActionMessage* pMessage = new CContactActionMessage;
if ( !pMessage ) return NULL;
pMessage->m_IsQueued = isQueued;
pMessage->m_Entities = entities;
if ( idx + 3 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_OBJECT( argv[ idx ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
CEntity* pEntity = ToNative< CEntity >( argv[ idx++ ] );
if ( !pEntity )
{
JS_ReportError( pContext, "Invalid entity parameter" );
return NULL;
}
pMessage->m_Target = pEntity->me;
if ( !JSVAL_IS_INT( argv[ idx ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_Action = ToPrimitive< int >( argv[ idx++ ] );
if ( !JSVAL_IS_BOOLEAN( argv[ idx ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_Run = ToPrimitive< bool >( argv[ idx++ ] );
return pMessage;
}
case NMT_NOTIFY_REQUEST:
{
CNotifyRequestMessage* pMessage = new CNotifyRequestMessage;
if ( !pMessage ) return NULL;
pMessage->m_IsQueued = isQueued;
pMessage->m_Entities = entities;
if ( idx + 1 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_OBJECT( argv[ idx ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
CEntity* pEntity = ToNative< CEntity >( argv[ idx++ ] );
if ( !pEntity )
{
JS_ReportError( pContext, "Invalid entity parameter" );
return NULL;
}
pMessage->m_Target = pEntity->me;
return pMessage;
}
case NMT_FORMATION_CONTACT_ACTION:
{
CFormationContactActionMessage* pMessage = new CFormationContactActionMessage;
if ( !pMessage ) return NULL;
pMessage->m_IsQueued = isQueued;
pMessage->m_Entities = entities;
if ( idx + 1 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );\
return NULL;
}
if ( !JSVAL_IS_OBJECT( argv[ idx ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
CEntity* pEntity = ToNative< CEntity >( argv[ idx++ ] );
if ( !pEntity )
{
JS_ReportError( pContext, "Invalid entity parameter" );
return NULL;
}
pMessage->m_Target = pEntity->me;
return pMessage;
}
case NMT_PRODUCE:
{
CProduceMessage* pMessage = new CProduceMessage;
if ( !pMessage ) return NULL;
pMessage->m_IsQueued = isQueued;
pMessage->m_Entities = entities;
if ( idx + 1 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_INT( argv[ idx ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_Type = ToPrimitive< int >( argv[ idx++ ] );
if ( idx + 1 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_STRING( argv[ idx ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_Name = ToPrimitive< CStrW >( argv[ idx++ ] );
return pMessage;
}
case NMT_PLACE_OBJECT:
{
CPlaceObjectMessage* pMessage = new CPlaceObjectMessage;
if ( !pMessage ) return NULL;
pMessage->m_IsQueued = isQueued;
pMessage->m_Entities = entities;
if ( idx + 1 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_STRING( argv[ idx ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_Template = ToPrimitive< CStrW >( argv[ idx++ ] );
if ( idx + 1 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_INT( argv[ idx ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_X = ToPrimitive< int >( argv[ idx++ ] );
if ( idx + 1 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_INT( argv[ idx ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_Y = ToPrimitive< int >( argv[ idx++ ] );
if ( idx + 1 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_INT( argv[ idx ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_Z = ToPrimitive< int >( argv[ idx++ ] );
if ( idx + 1 > argc )
{
JS_ReportError( pContext, "Too few parameters!" );
return NULL;
}
if ( !JSVAL_IS_INT( argv[ idx ] ) )
{
JS_ReportError( pContext, "Parameter type error!" );
return NULL;
}
pMessage->m_Angle = ToPrimitive< int >( argv[ idx++ ] );
return pMessage;
}
case NMT_REMOVE_OBJECT:
{
CRemoveObjectMessage* pMessage = new CRemoveObjectMessage;
if ( !pMessage ) return NULL;
pMessage->m_IsQueued = isQueued;
pMessage->m_Entities = entities;
return pMessage;
}
default:
JS_ReportError( pContext, "Invalid order type" );
break;
}
return NULL;
}
//-----------------------------------------------------------------------------
// Name: CreatePositionMessage()
// Desc:
//-----------------------------------------------------------------------------
CNetMessage* CNetMessage::CreatePositionMessage(
const CEntityList& entities,
const int type,
CVector2D pos )
{
switch ( type )
{
case NMT_GOTO:
{
CGotoMessage *pMessage = new CGotoMessage;
if ( !pMessage ) return NULL;
pMessage->m_Entities = entities;
pMessage->m_TargetX = pos.x;
pMessage->m_TargetY = pos.y;
return pMessage;
}
case NMT_RUN:
{
CRunMessage *pMessage = new CRunMessage;
if ( !pMessage ) return NULL;
pMessage->m_Entities = entities;
pMessage->m_TargetX = pos.x;
pMessage->m_TargetY = pos.y;
return pMessage;
}
case NMT_PATROL:
{
CPatrolMessage *pMessage = new CPatrolMessage;
if ( !pMessage ) return NULL;
pMessage->m_Entities = entities;
pMessage->m_TargetX = pos.x;
pMessage->m_TargetY = pos.y;
return pMessage;
}
case NMT_ADD_WAYPOINT:
{
CAddWaypointMessage *pMessage = new CAddWaypointMessage;
if ( !pMessage ) return NULL;
pMessage->m_Entities = entities;
pMessage->m_TargetX = pos.x;
pMessage->m_TargetY = pos.y;
return pMessage;
}
case NMT_SET_RALLY_POINT:
{
CSetRallyPointMessage *pMessage = new CSetRallyPointMessage;
if ( !pMessage ) return NULL;
pMessage->m_Entities = entities;
pMessage->m_TargetX = pos.x;
pMessage->m_TargetY = pos.y;
return pMessage;
}
case NMT_FORMATION_GOTO:
{
CFormationGotoMessage *pMessage = new CFormationGotoMessage;
if ( !pMessage ) return NULL;
pMessage->m_Entities = entities;
pMessage->m_TargetX = pos.x;
pMessage->m_TargetY = pos.y;
return pMessage;
}
}
return NULL;
}
//-----------------------------------------------------------------------------
// Name: CreateEntityIntMessage()
// Desc:
//-----------------------------------------------------------------------------
CNetMessage* CNetMessage::CreateEntityIntMessage(
const CEntityList& entities,
const int type,
HEntity& target,
int action )
{
switch ( type )
{
case NMT_CONTACT_ACTION:
{
CContactActionMessage *pMessage = new CContactActionMessage;
if ( !pMessage ) return NULL;
pMessage->m_Entities = entities;
pMessage->m_Target = target;
pMessage->m_Action = action;
pMessage->m_Run = false;
return pMessage;
}
case NMT_NOTIFY_REQUEST:
{
CNotifyRequestMessage *pMessage = new CNotifyRequestMessage;
if ( !pMessage ) return NULL;
pMessage->m_Entities = entities;
pMessage->m_Target = target;
pMessage->m_Action = action;
return pMessage;
}
case NMT_FORMATION_CONTACT_ACTION:
{
CFormationContactActionMessage *pMessage = new CFormationContactActionMessage;
if ( !pMessage ) return NULL;
pMessage->m_Entities = entities;
pMessage->m_Target = target;
pMessage->m_Action = action;
return pMessage;
}
}
return NULL;
}
CNetMessage* CNetMessage::CreateProduceMessage( const CEntityList& entities, const int type, int proType, const CStrW& name )
{
switch ( type )
{
case NMT_PRODUCE:
{
CProduceMessage* pMessage = new CProduceMessage;
if ( !pMessage ) return NULL;
pMessage->m_Entities = entities;
pMessage->m_Type = proType;
pMessage->m_Name = name;
return pMessage;
}
}
return NULL;
}
//-----------------------------------------------------------------------------
// Name: CreateMessage()
// Desc: Creates the appropriate message based on the given data
@ -939,9 +155,6 @@ CNetMessage* CNetMessageFactory::CreateMessage(const void* pData,
// Figure out message type
header.Deserialize( ( const u8* )pData, ( const u8* )pData + dataSize );
// This is what we want
//pNewMessage = m_Pool.GetMessage( header.GetType() );
switch ( header.GetType() )
{
case NMT_GAME_SETUP:
@ -1000,58 +213,6 @@ CNetMessage* CNetMessageFactory::CreateMessage(const void* pData,
pNewMessage = new CChatMessage;
break;
case NMT_GOTO:
pNewMessage = new CGotoMessage;
break;
case NMT_PATROL:
pNewMessage = new CPatrolMessage;
break;
case NMT_ADD_WAYPOINT:
pNewMessage = new CAddWaypointMessage;
break;
case NMT_CONTACT_ACTION:
pNewMessage = new CContactActionMessage;
break;
case NMT_PRODUCE:
pNewMessage = new CProduceMessage;
break;
case NMT_PLACE_OBJECT:
pNewMessage = new CPlaceObjectMessage;
break;
case NMT_REMOVE_OBJECT:
pNewMessage = new CRemoveObjectMessage;
break;
case NMT_RUN:
pNewMessage = new CRunMessage;
break;
case NMT_SET_RALLY_POINT:
pNewMessage = new CSetRallyPointMessage;
break;
case NMT_SET_STANCE:
pNewMessage = new CSetStanceMessage;
break;
case NMT_NOTIFY_REQUEST:
pNewMessage = new CNotifyRequestMessage;
break;
case NMT_FORMATION_GOTO:
pNewMessage = new CFormationGotoMessage;
break;
case NMT_FORMATION_CONTACT_ACTION:
pNewMessage = new CFormationContactActionMessage;
break;
case NMT_SIMULATION_COMMAND:
pNewMessage = new CSimulationMessage(g_Game->GetSimulation2()->GetScriptInterface());
break;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* 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
@ -138,45 +138,6 @@ public:
private:
bool m_Dirty; // Message has been modified
NetMessageType m_Type; // Message type
public:
/**
* Register a selection of message types as JS constants.
* The constant's names will be the same as those of the enums
*/
static void ScriptingInit( void );
/*static CCommandMessage* CommandFromJSArgs(
const CEntityList &entities,
JSContext* cx,
uintN argc,
jsval* argv,
bool isQueued );*/
static CNetMessage* CommandFromJSArgs(
const CEntityList &entities,
JSContext* cx,
uintN argc,
jsval* argv,
bool isQueued );
static CNetMessage* CreatePositionMessage(
const CEntityList& entities,
const int type,
CVector2D pos );
static CNetMessage* CreateEntityIntMessage(
const CEntityList& entities,
const int type,
HEntity& target,
int action );
static CNetMessage* CreateProduceMessage(
const CEntityList& entities,
const int type,
int proType,
const CStrW& name );
};
/*
@ -197,8 +158,6 @@ public:
*/
static CNetMessage* CreateMessage( const void* pData, size_t dataSize );
protected:
private:
// Not implemented

View File

@ -66,22 +66,7 @@ enum NetMessageType
NMT_FILE_PROGRESS,
NMT_GAME_START,
NMT_END_COMMAND_BATCH, // In-game stage
NMT_GOTO,
NMT_COMMAND_FIRST = NMT_GOTO,
NMT_PATROL,
NMT_ADD_WAYPOINT,
NMT_CONTACT_ACTION,
NMT_PRODUCE,
NMT_PLACE_OBJECT,
NMT_REMOVE_OBJECT,
NMT_RUN,
NMT_SET_RALLY_POINT,
NMT_SET_STANCE,
NMT_NOTIFY_REQUEST,
NMT_FORMATION_GOTO,
NMT_FORMATION_CONTACT_ACTION,
NMT_SIMULATION_COMMAND,
NMT_COMMAND_LAST,
NMT_LAST // Last message in the list
};
@ -196,77 +181,6 @@ START_NMT_CLASS_(EndCommandBatch, NMT_END_COMMAND_BATCH)
NMT_FIELD_INT(m_TurnLength, u32, 2)
END_NMT_CLASS()
START_NMT_CLASS_(Command, NMT_INVALID)
NMT_FIELD(CEntityList, m_Entities)
NMT_FIELD_INT(m_IsQueued, u32, 1)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Goto, NMT_GOTO)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Run, NMT_RUN)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Patrol, NMT_PATROL)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, AddWaypoint, NMT_ADD_WAYPOINT)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, SetRallyPoint, NMT_SET_RALLY_POINT)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, SetStance, NMT_SET_STANCE)
NMT_FIELD(CStrW, m_Stance)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, ContactAction, NMT_CONTACT_ACTION)
NMT_FIELD(HEntity, m_Target)
NMT_FIELD_INT(m_Action, u32, 4)
NMT_FIELD_INT(m_Run, u32, 1)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, Produce, NMT_PRODUCE)
NMT_FIELD_INT(m_Type, u32, 4)
NMT_FIELD(CStrW, m_Name)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, PlaceObject, NMT_PLACE_OBJECT)
NMT_FIELD(CStrW, m_Template)
NMT_FIELD_INT(m_X, u32, 4)
NMT_FIELD_INT(m_Y, u32, 4)
NMT_FIELD_INT(m_Z, u32, 4)
NMT_FIELD_INT(m_Angle, u32, 4) // Orientation angle
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, RemoveObject, NMT_REMOVE_OBJECT)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, NotifyRequest, NMT_NOTIFY_REQUEST)
NMT_FIELD(HEntity, m_Target)
NMT_FIELD_INT(m_Action, u32, 4)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, FormationGoto, NMT_FORMATION_GOTO)
NMT_FIELD_INT(m_TargetX, u32, 2)
NMT_FIELD_INT(m_TargetY, u32, 2)
END_NMT_CLASS()
DERIVE_NMT_CLASS_(Command, FormationContactAction, NMT_FORMATION_CONTACT_ACTION)
NMT_FIELD(HEntity, m_Target)
NMT_FIELD_INT(m_Action, u32, 4)
END_NMT_CLASS()
END_NMTS()
#else

View File

@ -38,17 +38,6 @@
// DECLARATIONS
CNetServer* g_NetServer = NULL;
class CServerTurnManager : public CTurnManager
{
public:
CServerTurnManager(CNetServer& server) : m_Server(server) { }
virtual void QueueLocalCommand(CNetMessage* pMessage);
virtual void NewTurn();
virtual bool NewTurnReady();
private:
CNetServer& m_Server;
};
//-----------------------------------------------------------------------------
// Name: CNetServer()
// Desc: Constructor
@ -56,13 +45,11 @@ private:
CNetServer::CNetServer( CGame *pGame, CGameAttributes *pGameAttributes )
: m_JsSessions( &m_IDSessions )
{
m_TurnManager = new CServerTurnManager(*this);
m_ServerTurnManager = NULL;
m_Game = pGame;
m_GameAttributes = pGameAttributes;
m_MaxObservers = MAX_OBSERVERS;
//m_LastSessionID = 1;
m_Port = DEFAULT_HOST_PORT;
m_Name = DEFAULT_SERVER_NAME;
m_PlayerName = DEFAULT_PLAYER_NAME;
@ -73,16 +60,6 @@ CNetServer::CNetServer( CGame *pGame, CGameAttributes *pGameAttributes )
m_GameAttributes->SetPlayerUpdateCallback( PlayerAttributeUpdate, this );
m_GameAttributes->SetPlayerSlotAssignmentCallback( PlayerSlotAssignment, this );
if (!g_UseSimulation2)
m_Game->GetSimulation()->SetTurnManager(m_TurnManager);
// Set an incredibly long turn length for debugging
// (e.g. less command batch spam that way)
for ( uint i = 0; i < 3; i++ )
{
m_TurnManager->SetTurnLength( i, CTurnManager::DEFAULT_TURN_LENGTH );
}
g_ScriptingHost.SetGlobal( "g_NetServer", OBJECT_TO_JSVAL( GetScript() ) );
}
@ -117,8 +94,6 @@ void CNetServer::ScriptingInit( void )
AddProperty( L"onClientDisconnect", &CNetServer::m_OnClientDisconnect );
CJSObject< CNetServer >::ScriptingInit( "NetServer" );
//CGameAttributes::ScriptingInit();
}
//-----------------------------------------------------------------------------
@ -167,18 +142,6 @@ bool CNetServer::SetupSession( CNetSession* pSession )
pSession->AddTransition( NSS_PREGAME, ( uint )NMT_CHAT, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_ERROR, NSS_INGAME, (void*)&OnError, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_CHAT, NSS_INGAME, (void*)&OnChat, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_GOTO, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_PATROL, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_ADD_WAYPOINT, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_CONTACT_ACTION, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_PRODUCE, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_PLACE_OBJECT, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_RUN, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_SET_RALLY_POINT, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_SET_STANCE, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_NOTIFY_REQUEST, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_FORMATION_GOTO, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_FORMATION_CONTACT_ACTION, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_SIMULATION_COMMAND, NSS_INGAME, (void*)&OnInGame, pContext );
pSession->AddTransition( NSS_INGAME, ( uint )NMT_END_COMMAND_BATCH, NSS_INGAME, (void*)&OnInGame, pContext );
@ -345,15 +308,7 @@ void CNetServer::OnPlayerLeave( CNetSession* pSession )
// Validate parameters
if ( !pSession ) return;
CPlayer* pPlayer = NULL;
CPlayerSlot* pPlayerSlot = NULL;
CPlayerLeaveMessage playerLeave;
// Validate parameters
if ( !pSession ) return;
pPlayer = pSession->GetPlayer();
pPlayerSlot = pSession->GetPlayerSlot();
CPlayerSlot* pPlayerSlot = pSession->GetPlayerSlot();
switch ( m_State )
{
@ -371,7 +326,6 @@ void CNetServer::OnPlayerLeave( CNetSession* pSession )
// TODO Set everything up for re-connect and resume
if ( pPlayerSlot )
{
m_TurnManager->SetClientPipe( pPlayerSlot->GetSlotID(), NULL );
pPlayerSlot->AssignClosed();
}
break;
@ -383,8 +337,8 @@ void CNetServer::OnPlayerLeave( CNetSession* pSession )
}
// Inform other clients about client disconnection
CPlayerLeaveMessage playerLeave;
playerLeave.m_SessionID = pSession->GetID();
Broadcast( &playerLeave );
// Script object defined?
@ -416,18 +370,7 @@ bool CNetServer::OnError( void* pContext, CFsmEvent* pEvent )
CErrorMessage* pMessage = ( CErrorMessage* )pEvent->GetParamRef();
if ( pMessage )
{
if ( pMessage->m_State == SS_UNCONNECTED )
{
//if ( pSession->GetID() != -1)
// pServer->RemoveSession( pSession );
//delete pSession;
}
else
{
// Weird stuff...
LOG( CLogger::Warning, LOG_CATEGORY, L"NMT_ERROR: %hs", pMessage->ToString().c_str() );
}
LOG( CLogger::Warning, LOG_CATEGORY, L"NMT_ERROR: %hs", pMessage->ToString().c_str() );
}
return true;
@ -459,8 +402,7 @@ bool CNetServer::OnHandshake( void* pContext, CFsmEvent* pEvent )
CCloseRequestMessage closeRequest;
pServer->SendMessage( pSession, &closeRequest );
CErrorMessage error( PS_OK, SS_UNCONNECTED );
pSession->Update( ( uint )NMT_ERROR, &error );
// TODO: probably need to abort and disconnect the session somehow
}
else
{
@ -572,24 +514,10 @@ bool CNetServer::OnInGame( void* pContext, CFsmEvent* pEvent )
return true;
}
if ( pMessage->GetType() >= NMT_COMMAND_FIRST && pMessage->GetType() < NMT_COMMAND_LAST )
{
//pSession->m_pPlayer->ValidateCommand(pMsg);
pServer->QueueIncomingCommand( pMessage );
return true;
}
if ( pMessage->GetType() == NMT_END_COMMAND_BATCH )
{
if (g_UseSimulation2)
{
CEndCommandBatchMessage* endMessage = static_cast<CEndCommandBatchMessage*> (pMessage);
pServer->m_ServerTurnManager->NotifyFinishedClientCommands(pSession->GetID(), endMessage->m_Turn);
}
// TODO Update client timing information and recalculate turn length
pSession->SetReadyForTurn( true );
CEndCommandBatchMessage* endMessage = static_cast<CEndCommandBatchMessage*> (pMessage);
pServer->m_ServerTurnManager->NotifyFinishedClientCommands(pSession->GetID(), endMessage->m_Turn);
}
}
@ -642,107 +570,6 @@ CNetSession* CNetServer::GetSessionByID( uint sessionID )
return it->second;
}
//-----------------------------------------------------------------------------
// Name: AddSession()
// Desc: Adds a new session to the list of managed sessions
//-----------------------------------------------------------------------------
/*void CNetServer::AddSession( CNetSession* pSession )
{
// Validate parameter
if ( !pSession ) return;
// Setup new session
//SetupNewSession();
// Broadcase a new message informing about the newly connected client
CPlayerJoinMessage playerJoin;
playerJoin.m_Clients.resize( 1 );
playerJoin.m_Clients[ 0 ].m_SessionID = pSession->GetID();
playerJoin.m_Clients[ 0 ].m_Name = pSession->GetName();
Broadcast( playerJoin );
// Store new session
m_IDSessions[ pSession->GetID() ] = pSession;
}*/
//-----------------------------------------------------------------------------
// Name: RemoveSession()
// Desc: Removes the specified session from the list of sessions
//-----------------------------------------------------------------------------
/*CNetSession* CNetServer::RemoveSession( CNetSession* pSession )
{
CPlayer* pPlayer = NULL;
CPlayerSlot* pPlayerSlot = NULL;
CPlayerLeaveMessage playerLeave;
uint sessionID;
// Validate parameters
if ( !pSession ) return;
pPlayer = pSession->GetPlayer();
pPlayerSlot = pSession->GetPlayerSlot();
sessionID = pSession->GetID();
switch ( m_State )
{
case SERVER_STATE_PREGAME:
// Delete player's slot and sync client disconnection
if ( pPlayerSlot ) pPlayerSlot->AssignClosed();
break;
case SERVER_STATE_INGAME:
// Revert player entities to Gaia control and
// wait for client reconnection
// TODO Reassign entities to Gaia control
// TODO Set everything up for re-connect and resume
if ( pPlayerSlot )
{
SetClientPipe( pPlayerSlot->GetSlotID(), NULL );
pPlayerSlot->AssignClosed();
}
break;
case SERVER_STATE_POSTGAME:
// Synchronize disconnection
break;
}
// Inform other clients about client disconnection
playerLeave.m_SessionID = sessionID;
Broadcast( playerLeave );
// Free session slot from the list for later reuse
m_IDSessions[ sessionID ] = NULL;
// TODO Handle observers
}*/
//-----------------------------------------------------------------------------
// Name: RemoveAllSessions()
// Desc: Removes all sessions from the list
//-----------------------------------------------------------------------------
/*void CNetServer::RemoveAllSessions( void )
{
SessionList::iterator it = m_Sessions.begin();
for ( ; it != m_Sessions.end(); it++ )
{
CNetSession* pCurrSession = it->second;
if ( !pCurrSession ) continue;
RemoveSession( pCurrSession );
}
m_Sessions.clear();
}*/
//-----------------------------------------------------------------------------
// Name: SetPlayerPassword()
// Desc: Sets player new password
@ -765,13 +592,8 @@ int CNetServer::StartGame( void )
if ( m_Game->StartGame( m_GameAttributes ) != PSRETURN_OK ) return -1;
if (g_UseSimulation2)
{
m_ServerTurnManager = new CNetServerTurnManager(*m_Game->GetSimulation2(), *this, m_Game->GetLocalPlayer()->GetPlayerID(), SERVER_SESSIONID);
m_Game->SetTurnManager(m_ServerTurnManager);
}
m_TurnManager->Initialize( m_GameAttributes->GetSlotCount() );
m_ServerTurnManager = new CNetServerTurnManager(*m_Game->GetSimulation2(), *this, m_Game->GetLocalPlayer()->GetPlayerID(), SERVER_SESSIONID);
m_Game->SetTurnManager(m_ServerTurnManager);
for ( i = 0; i < m_GameAttributes->GetSlotCount(); i++ )
{
@ -780,28 +602,15 @@ int CNetServer::StartGame( void )
if ( pCurrSlot->GetAssignment() == SLOT_SESSION )
{
m_TurnManager->SetClientPipe( i, pCurrSlot->GetSession() );
if (g_UseSimulation2)
m_ServerTurnManager->InitialiseClient(pCurrSlot->GetSessionID());
m_ServerTurnManager->InitialiseClient(pCurrSlot->GetSessionID());
}
}
m_State = SERVER_STATE_INGAME;
for ( i = 0; i < GetSessionCount(); i++ )
{
CNetSession* pCurrSession = GetSession( i );
if ( !pCurrSession ) continue;
pCurrSession->StartGame();
}
CGameStartMessage gameStart;
Broadcast( &gameStart );
// This is the signal for everyone to start their simulations.
//SendBatch( 1 );
return 0;
}
@ -892,23 +701,6 @@ uint CNetServer::GetFreeSessionID( void ) const
// No need to be conservative with session IDs; just use a global counter.
static uint lastSessionID = CLIENT_MIN_SESSIONID;
return lastSessionID++;
/*
// Loop through the list of sessions and return the first
// ID for which the associated session is NULL. If no such
// free slot is found, return a new session ID which is higher
// than the last session ID from the list.
IDSessionMap::const_iterator it = m_IDSessions.begin();
for ( ; it != m_IDSessions.end(); it++ )
{
CNetSession* pCurrSession = it->second;
if ( !pCurrSession ) return it->first;
sessionID++;
}
return sessionID;
*/
}
//-----------------------------------------------------------------------------
@ -996,78 +788,6 @@ bool CNetServer::AllowObserver( CNetSession* UNUSED( pSession ) )
return m_Observers.size() < m_MaxObservers;
}
//-----------------------------------------------------------------------------
// Name: NewTurnReady()
// Desc:
//-----------------------------------------------------------------------------
bool CServerTurnManager::NewTurnReady()
{
// Check whether all sessions are ready for the next turn
for ( uint i = 0; i < m_Server.GetSessionCount(); i++ )
{
CNetSession* pCurrSession = m_Server.GetSession( i );
if ( !pCurrSession ) continue;
if ( !pCurrSession->IsReadyForTurn() )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Name: NewTurn()
// Desc:
//-----------------------------------------------------------------------------
void CServerTurnManager::NewTurn()
{
CScopeLock lock(m_Server.m_Mutex);
// Reset session ready for next turn flag
for ( uint i = 0; i < m_Server.GetSessionCount(); i++ )
{
CNetSession* pCurrSession = m_Server.GetSession( i );
if ( !pCurrSession ) continue;
pCurrSession->SetReadyForTurn( false );
}
RecordBatch( 2 );
RotateBatches();
ClearBatch( 2 );
IterateBatch( 1, CSimulation::GetMessageMask, m_Server.m_Game->GetSimulation() );
SendBatch( 1 );
//IterateBatch( 1, SendToObservers, this );
}
//-----------------------------------------------------------------------------
// Name: QueueLocalCommand()
// Desc:
//-----------------------------------------------------------------------------
void CServerTurnManager::QueueLocalCommand( CNetMessage *pMessage )
{
// Validate parameters
if ( !pMessage ) return;
//LOG( NORMAL, LOG_CATEGORY, L"CServerTurnManager::QueueLocalCommand(): %hs.", pMessage->ToString().c_str() );
QueueMessage( 2, pMessage );
}
//-----------------------------------------------------------------------------
// Name: QueueIncomingCommand()
// Desc:
//-----------------------------------------------------------------------------
void CNetServer::QueueIncomingCommand( CNetMessage* pMessage )
{
// Validate parameters
if ( !pMessage ) return;
//LOG( NORMAL, LOG_CATEGORY, L"CNetServer::QueueIncomingCommand(): %hs.", pMessage->ToString().c_str() );
m_TurnManager->QueueMessage( 2, pMessage );
}
//-----------------------------------------------------------------------------
// Name: OnChat()
// Desc:

View File

@ -30,7 +30,6 @@
#include "Network.h"
#include "NetSession.h"
#include "NetTurnManager.h"
#include "simulation/TurnManager.h"
#include "scripting/ScriptableObject.h"
#include "ps/GameAttributes.h"
#include "ps/scripting/JSMap.h"
@ -107,7 +106,6 @@ public:
virtual ~CNetServer( void );
bool Start ( JSContext *pContext, uintN argc, jsval *argv );
// void Shutdown ( void );
/**
* Returns true indicating the host acts as a server
@ -132,19 +130,6 @@ public:
*/
CNetSession* RemoveSession( CNetSession* pSession );
/**
* Removes all the sessions managed by the network server
*
*/
//void RemoveAllSessions( void );
/**
* Returns the number of session the server manages
*
* @return The number of sessions
*/
//uint GetSessionCount( void ) const;
/**
* Returns the session object for the specified ID
*
@ -154,8 +139,6 @@ public:
*/
CNetSession* GetSessionByID( uint sessionID );
CNetTurnManager* GetTurnManager() { debug_assert(m_ServerTurnManager); return m_ServerTurnManager; }
protected:
virtual bool SetupSession ( CNetSession* pSession );
@ -164,26 +147,6 @@ protected:
private:
//void ClientConnect ( ENetPeer* pPeer );
//void ClientDisconnect ( ENetPeer* pPeer );
//void ClientReceive ( ENetPeer* pPeer, ENetPacket* pPacket );
/**
* Returns the session associated with the specified ENet peer
*
* @param pPeer ENet peer
* @return The session object if found or NULL
*/
//CNetSession* GetSessionByPeer( const ENetPeer* pPeer );
/**
* Setup client game by sending the apropiate network messages. It also
* inform the client about the other connected clients as well as player
* slot assignment and attributes.
*
*/
//void SetupNewSession( CNetSession* pSession );
/**
* Loads the player properties into the specified message
*
@ -232,7 +195,6 @@ private:
* @param pProperty Pointer to game property
* @param pData Context pointer passed on iteration startup
*/
// IterateCB GameSetupMessageCallbak;
static void GameSetupMessageCallback(
const CStrW& name,
ISynchedJSProperty *pProperty,
@ -246,20 +208,9 @@ private:
uint GetFreeSessionID( void ) const;
IDSessionMap m_IDSessions; // List of connected ID and session pairs
//CScriptObject m_ScriptConnect; // Script client connect dispatch
//CScriptObject m_ScriptDisconnect; // Script client disconnect dispatch
//CScriptObject m_ScriptChat; // Script client chat dispatch
public:
/**
*
*
* @param addr Address where to bind
* @return PS_OK if bind successfully, error code otherwise
*/
//PS_RESULT Bind( const CSocketAddress& addr );
void SetPlayerPassword ( const CStr& password );
CStrW GetPlayerName ( void ) const { return m_PlayerName; }
NetServerState GetState ( void ) const { return m_State; }
@ -271,18 +222,6 @@ protected:
// Assign a session ID to the session. Do this just before calling AddSession
void AssignSessionID( CNetSession* pSession );
// Add the session. This will be called after the session passes the
// handshake and authentication stages. AssignSessionID should've been called
// on the session prior to calling this method.
//void AddSession( CNetServerSession* pSession );
// Remove the session from the server
//void RemoveSession( CNetServerSession* pSession );
// Queue a command coming in from the wire. The command has been validated
// by the caller.
void QueueIncomingCommand( CNetMessage* pMessage );
// Call the JS callback for incoming events
void OnPlayerChat ( const CStrW& from, const CStrW& message );
virtual void OnPlayerJoin ( CNetSession* pSession );
@ -297,12 +236,6 @@ protected:
static bool OnInGame ( void* pContext, CFsmEvent* pEvent );
static bool OnChat ( void* pContext, CFsmEvent* pEvent );
// OVERRIDES FROM CServerSocket
//virtual void OnAccept( const CSocketAddress& address );
// Will only be called from the Network Thread, by the OnAccept handler
//virtual CNetServerSession* CreateSession( CSocketInternal* pSocketInternal);
// Ask the server if the session is allowed to start observing.
//
// Returns:
@ -311,14 +244,11 @@ protected:
virtual bool AllowObserver( CNetSession* pSession );
public:
CMutex m_Mutex; // Synchronization object for batches
CGame* m_Game; // Pointer to actual game
private:
CGameAttributes* m_GameAttributes; // Stores game attributes
//int m_LastSessionID; // Stores the last session ID
//SessionMap m_Sessions; // Managed sessions
CJSMap< IDSessionMap > m_JsSessions;
/*
@ -332,7 +262,6 @@ private:
NetServerState m_State; // Holds server state
CStrW m_Name; // Server name
CStrW m_WelcomeMessage; // Nice welcome message
//CPlayer* m_Player; // Pointer to 'server' player
CStrW m_PlayerName; // Player name
CStrW m_PlayerPassword; // Player password
int m_Port; // The listening port
@ -340,15 +269,10 @@ private:
CScriptObject m_OnClientConnect;
CScriptObject m_OnClientDisconnect;
// static CGameAttributes::UpdateCallback AttributeUpdate;
// static CPlayer::UpdateCallback PlayerAttributeUpdate;
// static PlayerSlotAssignmentCB PlayerSlotAssignmentCallback;
static void AttributeUpdate ( const CStrW& name, const CStrW& newValue, void* pData);
static void PlayerAttributeUpdate ( const CStrW& name, const CStrW& value, CPlayer* pPlayer, void* pData );
static void PlayerSlotAssignment ( void* pData, CPlayerSlot* pPlayerSlot );
CTurnManager* m_TurnManager;
CNetServerTurnManager* m_ServerTurnManager;
};

View File

@ -25,9 +25,7 @@
// INCLUDES
#include "precompiled.h"
//#include "SessionManager.h"
#include "NetSession.h"
//#include "NetServer.h"
#include "NetLog.h"
// DECLARATIONS
@ -39,11 +37,6 @@
CNetHost::CNetHost( void )
{
m_Host = NULL;
m_Buffer = NULL;
m_BufferSize = 0;
// m_WorkerID = 0;
// m_StopWorker = NULL;
}
//-----------------------------------------------------------------------------
@ -54,16 +47,8 @@ CNetHost::~CNetHost( void )
{
// Release host
if ( m_Host ) enet_host_destroy( m_Host );
if ( m_Buffer ) delete [] m_Buffer;
// Release running semaphore
// if ( m_StopWorker ) sem_close( m_StopWorker );
m_Host = NULL;
m_Buffer = NULL;
m_BufferSize = 0;
// m_WorkerID = 0;
// m_StopWorker = NULL;
}
//-----------------------------------------------------------------------------
@ -107,10 +92,6 @@ void CNetHost::Shutdown( void )
// Destroy server
if ( m_Host ) enet_host_destroy( m_Host );
// Stop worker thread
// sem_post( m_StopWorker );
// if ( m_WorkerID ) pthread_join( m_WorkerID, NULL );
// Disconnect and release each peer
PeerSessionList::iterator it = m_PeerSessions.begin();
for ( ; it != m_PeerSessions.end(); it++ )
@ -125,7 +106,6 @@ void CNetHost::Shutdown( void )
m_PeerSessions.clear();
m_Host = NULL;
// m_WorkerID = 0;
}
//-----------------------------------------------------------------------------
@ -227,122 +207,6 @@ bool CNetHost::Disconnect( CNetSession* pSession )
return true;
}
//-----------------------------------------------------------------------------
// Name: Run()
// Desc:
//-----------------------------------------------------------------------------
/*bool CNetHost::Run( void )
{
debug_assert( m_Host );
// Host created?
if ( !m_Host ) return false;
// Already running?
if ( m_WorkerID != 0 ) return true;
// Create run semaphore
m_StopWorker = sem_open( "//WFG_HostWorkerRun", O_CREAT | O_EXCL, 0700, 0 );
if ( !m_StopWorker ) return false;
// Create worker thread
if ( pthread_create( &m_WorkerID, 0, &WorkerFunc, this ) < 0 ) return false;
return true;
}
//-----------------------------------------------------------------------------
// Name: WorkerFunc()
// Desc: Worker thread function
//-----------------------------------------------------------------------------
void* CNetHost::WorkerFunc( void* pData )
{
ENetEvent event;
CNetSession* pSession = NULL;
PeerSession item;
PeerSessionList::iterator it;
// Validate parameters
if ( !pData ) return NULL;
CNetHost* pHost = ( CNetHost* )pData;
// Poll host for events
while ( true )
{
// Decide whether to stop or not
if ( !sem_timedwait( pHost->m_StopWorker, NULL ) ) break;
int retval = enet_host_service( pHost->m_Host, &event, 100 );
// Any event?
if ( !retval ) continue;
// Any error?
if ( !retval ) break;
// Handle occured event
switch( event.type )
{
case ENET_EVENT_TYPE_CONNECT:
// A new client has connected, handle it
pSession = new CNetSession( pHost, event.peer );
if ( !pSession ) return NULL;
// Successfully handled?
if ( !pHost->HandleConnect( pSession ) ) return NULL;
// Add new item to internal list
item.pPeer = event.peer;
item.pSession = pSession;
pHost->m_PeerSessions.push_back( item );
break;
case ENET_EVENT_TYPE_DISCONNECT:
// Client has disconnected, handle it
it = pHost->m_PeerSessions.begin();;
for ( ; it != pHost->m_PeerSessions.end(); it++ )
{
// Is this our session?
if ( it->pPeer == event.peer )
{
// Successfully handled?
if ( !pHost->HandleDisconnect( it->pSession ) ) return NULL;
pHost->m_PeerSessions.erase( it );
}
}
break;
case ENET_EVENT_TYPE_RECEIVE:
// A new data packet was received from client, handle message
it = pHost->m_PeerSessions.begin();
for ( ; it != pHost->m_PeerSessions.end(); it++ )
{
// Is this our session?
if ( it->pPeer == event.peer )
{
// Create message from raw data
CNetMessage* pNewMessage = CNetMessageFactory::CreateMessage( event.packet->data, event.packet->dataLength );
if ( !pNewMessage ) return NULL;
// Successfully handled?
if ( !pHost->HandleMessageReceive( pNewMessage, it->pSession ) ) return NULL;
}
}
break;
}
}
return NULL;
}*/
//-----------------------------------------------------------------------------
// Name: ProcessEvents()
// Desc: Wait for events and shuttles packets between the host and its peers
@ -463,35 +327,6 @@ void CNetHost::Broadcast( const CNetMessage* pMessage )
}
}
//-----------------------------------------------------------------------------
// Name: ResizeBuffer()
// Desc: Resizes the internal buffer
//-----------------------------------------------------------------------------
void CNetHost::ResizeBuffer( size_t size )
{
// Already enough space?
if ( size <= m_BufferSize ) return;
// Allocate enough space for the new buffer
u8* pBuffer = new u8[ ALIGN_BLOCK( m_BufferSize + size ) ];
if ( !pBuffer ) return;
// Any old data?
if ( m_Buffer )
{
// Copy old data
memcpy( pBuffer, m_Buffer, m_BufferSize );
delete [] m_Buffer;
}
// Store new buffer
m_Buffer = pBuffer;
// Store new buffer size
m_BufferSize = ALIGN_BLOCK( m_BufferSize + size );
}
//-----------------------------------------------------------------------------
// Name: SendMessage()
// Desc: Sends the specified message to peer
@ -507,15 +342,16 @@ bool CNetHost::SendMessage(
debug_assert( m_Host );
size_t size = pMessage->GetSerializedLength();
debug_assert( size );
// Adjust buffer for message
ResizeBuffer( size );
m_Buffer.resize( size );
// Save message to internal buffer
pMessage->Serialize( m_Buffer );
pMessage->Serialize( &m_Buffer[0] );
// Create a reliable packet
ENetPacket* pPacket = enet_packet_create( m_Buffer, size, ENET_PACKET_FLAG_RELIABLE );
ENetPacket* pPacket = enet_packet_create( &m_Buffer[0], size, ENET_PACKET_FLAG_RELIABLE );
if ( !pPacket ) return false;
// Let ENet send the message to peer
@ -529,7 +365,7 @@ bool CNetHost::SendMessage(
else
{
NET_LOG4( "Message %s of size %lu was sent to %p",
pMessage->ToString().c_str(), (unsigned long)pMessage->GetSerializedLength(), pSession->m_Peer->data );
pMessage->ToString().c_str(), (unsigned long)size, pSession->m_Peer->data );
}
enet_host_flush( m_Host );
@ -625,17 +461,10 @@ CNetSession* CNetHost::GetSession( uint index )
//-----------------------------------------------------------------------------
CNetSession::CNetSession( CNetHost* pHost, ENetPeer* pPeer )
{
//ONCE( ScriptingInit(); );
m_Host = pHost;
m_Peer = pPeer;
m_ID = INVALID_SESSION;
m_Player = NULL;
m_PlayerSlot = NULL;
m_ReadyForTurn = false;
// Register the network session
//g_SessionManager.Register( this );
}
//-----------------------------------------------------------------------------
@ -649,9 +478,6 @@ CNetSession::~CNetSession( void )
//m_Host = NULL;
m_Peer = NULL;
// Unregister the network session
//g_SessionManager.Unregister( this );
}
//-----------------------------------------------------------------------------
@ -672,15 +498,6 @@ void CNetSession::SetID( uint ID )
m_ID = ID;
}
//-----------------------------------------------------------------------------
// Name: SetPlayer()
// Desc: Set the player for this session
//-----------------------------------------------------------------------------
void CNetSession::SetPlayer( CPlayer* pPlayer )
{
m_Player = pPlayer;
}
//-----------------------------------------------------------------------------
// Name: SetPlayerSlot()
// Desc: Set the player slot for this session
@ -690,39 +507,6 @@ void CNetSession::SetPlayerSlot( CPlayerSlot* pPlayerSlot )
m_PlayerSlot = pPlayerSlot;
}
//-----------------------------------------------------------------------------
// Name: StartGame()
// Desc: Called by server after informing all clients about starting the game
//-----------------------------------------------------------------------------
void CNetSession::StartGame( void )
{
}
//-----------------------------------------------------------------------------
// Name: Push()
// Desc: Sends a message through ENet
//-----------------------------------------------------------------------------
void CNetSession::Push( CNetMessage* pMessage )
{
// Validate parameters
if ( !pMessage ) return;
debug_assert( m_Host );
m_Host->SendMessage( this, pMessage );
}
//-----------------------------------------------------------------------------
// Name: TryPop()
// Desc: Receives a message through ENet
//-----------------------------------------------------------------------------
CNetMessage* CNetSession::TryPop( void )
{
debug_assert( m_Host );
return m_Host->ReceiveMessage( this );
}
//-----------------------------------------------------------------------------
// Name: ScriptingInit()
// Desc:
@ -731,194 +515,6 @@ void CNetSession::ScriptingInit( void )
{
AddProperty( L"id", &CNetSession::m_ID );
AddProperty( L"name", &CNetSession::m_Name );
AddMethod<bool, &CNetSession::JSI_Close>( "close", 0 );
CJSObject<CNetSession>::ScriptingInit( "NetSession" );
}
//-----------------------------------------------------------------------------
// Name: JSI_Close()
// Desc:
//-----------------------------------------------------------------------------
bool CNetSession::JSI_Close( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
return false;
}
//-----------------------------------------------------------------------------
// Name: HandleMessage()
// Desc:
//-----------------------------------------------------------------------------
//bool CNetSession::HandleMessage( CNetMessage* pMessage )
//{
// return true;
//}
/*
//-----------------------------------------------------------------------------
// Name: CNetServerSession()
// Desc: Constructor
//-----------------------------------------------------------------------------
CNetServerSession::CNetSession(
CNetServer* pServer,
NetMessageHandler* pHandler )
: CNetSession( pHandler )
{
m_Server = pServer;
m_Player = NULL;
m_PlayerSlot = NULL;
m_IsObserver = false;
//ONCE( ScriptingInit() );
}
//-----------------------------------------------------------------------------
// Name: CNetServerSession()
// Desc: Constructor
//-----------------------------------------------------------------------------
CNetServerSession::CNetSession(
CNetServer* pServer,
CSocketInternal* pSocketInternal,
NetMessageHandler* pHandler )
: CNetSession( pSocketInternal, pHandler )
{
m_Server = pServer;
m_Player = NULL;
m_PlayerSlot = NULL;
m_IsObserver = false;
//ONCE( ScriptingInit() );
}
//-----------------------------------------------------------------------------
// Name: ~CNetServerSession()
// Desc: Destructor
//-----------------------------------------------------------------------------
CNetServerSession::~CNetServerSession( void )
{
}
//-----------------------------------------------------------------------------
// Name: StartGame()
// Desc: Called by server after informing all clients about starting the game
//-----------------------------------------------------------------------------
void CNetServerSession::StartGame( void )
{
}
//-----------------------------------------------------------------------------
// Name: SetPlayer()
// Desc: Set the player for this session
//-----------------------------------------------------------------------------
void CNetServerSession::SetPlayer( CPlayer* pPlayer )
{
m_Player = pPlayer;
}
//-----------------------------------------------------------------------------
// Name: SetPlayerSlot()
// Desc: Set the player slot for this session
//-----------------------------------------------------------------------------
void CNetServerSession::SetPlayerSlot( CPlayerSlot* pPlayerSlot )
{
m_PlayerSlot = pPlayerSlot;
}
//-----------------------------------------------------------------------------
// Name: SetID()
// Desc: Set new session ID
//-----------------------------------------------------------------------------
void CNetServerSession::SetID( uint ID )
{
m_ID = ID;
}
//-----------------------------------------------------------------------------
// Name: BaseHandler()
// Desc:
//-----------------------------------------------------------------------------
bool CNetServerSession::BaseHandler(
CNetMessage* pMessage,
CNetSession* pSession )
{
debug_assert( pMessage );
debug_assert( pSession );
// Validate parameters
if ( !pMessage || !pSession ) return false;
CNetServerSession* pSrvSession = dynamic_cast< CNetSession* >( pSession );
if ( pSrvSession ) return false;
// Handler NMT_ERROR message only
if ( pMessage->GetType() != NMT_ERROR ) return false;
CNetErrorMessage* pErrMessage = dynamic_cast< CNetErrorMessage* >( pMessage );
if ( !pErrMessage ) return false;
if ( pErrMessage->GetState() == SERVER_STATE_DISCONNECTED )
{
if ( pSrvSession->m_ID != -1 )
{
pSrvSession->m_Server->RemoveSession( pSrvSession );
}
delete pSrvSession;
}
else
{
// Not disconnected? Weired...
LOG( WARNING, LOG_CATEGORY, L"CNetServerSession::BaseHandler() NMT_ERROR: %hs", pErrMessage->ToString().c_str() );
}
delete pMessage;
return true;
}
//-----------------------------------------------------------------------------
// Name: HandshakeHandler()
// Desc:
//-----------------------------------------------------------------------------
bool CNetServerSession::HandshakeHandler(
CNetMessage* pMessage,
CNetSession* pSession )
{
debug_assert( pMessage );
debug_assert( pSession );
debug_assert( m_Server );
// Validate parameters
if ( !pMessage || !pSession ) return false;
CNetServerSession* pSrvSession = dynamic_cast< CNetServerSession* >( pSession );
if ( !pSrvSession ) return false;
LOG( NORMAL, LOG_CATEGORY, L"CNetServerSession::HandshakeHandler() %hs", pMessage->ToString().c_str() );
// Call base handler if other message thant NMT_ClientHandshake
if ( pMessage->GetType() != NMT_ClientHandshake ) BaseHandler( pMessage, pSession );
CClientHandshake* pHandshakeMessage = dynamic_cast< CClientHandshake* >( pMessage );
if ( !pHandshakeMessage ) return false;
if ( pHandshakeMessage->m_ProtocolVersion != PS_PROTOCOL_VERSION )
{
pSrvSession->Push( new CCloseRequestMessage() );
BaseHandler( new CNetErrorMessage( PS_OK, SERVER_STATE_DISCONNECTED ), pSrvSession );
}
//??? (else)
CServerHandshakeResponse* pNewMessage = new CServerHandshakeResponse();
pNewMessage->m_UseProtocolVersion = PS_PROTOCOL_VERSION;
pNewMessage->m_Flags = 0;
pNewMessage->m_Message = pSrvSession->m_Server->m_WelcomeMessage;
pSrvSession->Push( pNewMessage );
pSrvSession->m_MessageHandler = AuthHandler;
delete pMessage;
return true;
}*/

View File

@ -29,7 +29,6 @@
// INCLUDES
#include "Network.h"
#include "ps/GameAttributes.h"
#include "ps/Player.h"
#include "fsm.h"
#include <enet/enet.h>
@ -66,6 +65,8 @@ typedef std::vector< PeerSession > PeerSessionList;
class CNetHost
{
NONCOPYABLE(CNetHost);
public:
CNetHost( void );
@ -82,13 +83,6 @@ public:
*/
virtual bool IsServer( void ) const { return false; }
/**
* Indicates whether the host is currently a client
*
* @return Boolean indicating whether the host is a client
*/
virtual bool IsClient( void ) const { return false; }
/**
* Returns the number of sessions for the host
*
@ -153,14 +147,6 @@ public:
protected:
/**
* Attempts to resize the internal buffer to the size indicated by the
* passed parameter.
*
* @param size The new size for the buffer
*/
void ResizeBuffer( size_t size );
// Allow application to handle new client connect
virtual bool SetupSession ( CNetSession* pSession );
virtual bool HandleConnect ( CNetSession* pSession );
@ -168,27 +154,11 @@ protected:
virtual bool HandleMessageReceive (
CNetMessage* pMessage,
CNetSession* pSession );
/**
* Worker thread function
*
* @pData Argument specified on thread creation
* @return NULL
*/
//static void* WorkerFunc( void* pData );
private:
// Not implemented
CNetHost( const CNetHost& );
CNetHost& operator=( const CNetHost& );
u8* m_Buffer; // Serialize out messages buffer
size_t m_BufferSize; // Output buffer size
std::vector<u8> m_Buffer; // Serialize out messages buffer
ENetHost* m_Host; // Represents this host
PeerSessionList m_PeerSessions; // Session list of connected peers
//pthread_t m_WorkerID; // Worker thread
//sem_t* m_StopWorker; // Worker thread stop semaphore
};
/*
@ -208,8 +178,7 @@ private:
*/
class CNetSession : public CFsm,
public CJSObject< CNetSession >,
public IMessagePipeEnd
public CJSObject< CNetSession >
{
NONCOPYABLE(CNetSession);
@ -247,44 +216,10 @@ public:
*/
void SetID( uint ID );
/**
* Allows both client and server to set a callback handler
*
* @param pCallbackHandler Callback handler
*/
//void SetCallbackHandler( ISessionCallback* pCallbackHandler );
/**
* Disconnects the client from remote host
*
*/
void Reset( void );
void SetPlayer( CPlayer* pPlayer );
CPlayer* GetPlayer( void ) { return m_Player; }
void SetPlayerSlot( CPlayerSlot* pPlayerSlot );
CPlayerSlot* GetPlayerSlot( void ) { return m_PlayerSlot; }
void StartGame( void );
virtual void Push( CNetMessage* pMessage );
virtual CNetMessage* TryPop( void );
bool IsReadyForTurn( void ) const { return m_ReadyForTurn; }
void SetReadyForTurn( bool newValue ) { m_ReadyForTurn = newValue; }
bool JSI_Close( JSContext *cx, uintN argc, jsval *argv );
static void ScriptingInit( void );
//bool HandleMessage( CNetMessage* pMessage );
protected:
/**
* Process the message passed as parameter
*
* @param message The message to process
* @return true if the message was handler
* successufully, false otherwise
*/
//bool ProcessMessage( const CNetMessage& message );
private:
// Only the hosts can create sessions
@ -294,61 +229,8 @@ private:
ENetPeer* m_Peer; // Represents the peer host
uint m_ID; // Session ID
CStrW m_Name; // Session name
CPlayer* m_Player;
CPlayerSlot* m_PlayerSlot;
bool m_ReadyForTurn; // Next turn ready flag
};
/*
CLASS : CNetServerSession
DESCRIPTION :
NOTES :
*/
/*class CNetServerSession : public CNetSession,
public CJSObject< CNetServerSession >
{
public:
bool IsObserver ( void ) const { return m_IsObserver; }
CPlayer* GetPlayer ( void ) const { return m_Player; }
CPlayerSlot* GetPlayerSlot ( void ) const { return m_PlayerSlot; }
void StartGame ( void );
void SetPlayer ( CPlayer* pPlayer );
void SetPlayerSlot ( CPlayerSlot* pPlayerSlot );
protected:
CNetServerSession(
CNetServer* pServer,
NetMessageHandler* pHandler = m_HandshakeHandler );
CNetServerSession(
CNetServer* pServer,
CSocketInternal* pSocketInternal,
NetMessageHandler* pHandler = m_HandshakeHandler );
virtual ~CNetServerSession( void );
private:
static void ScriptingInit ( void );
bool JSI_Close (
JSContext* pContext,
uintN argc,
jsval* argv );
CNetServer* m_Server;
CPlayer* m_Player;
CPlayerSlot* m_PlayerSlot;
bool m_IsObserver;
static bool HandshakeHandler( CNetMessage* pMessage, CNetSession* pSession );
static bool ObserverHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool BaseHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool AuthHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool PreGameHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool InGameHandler ( CNetMessage* pMessage, CNetSession* pSession );
static bool ChatHandler ( CNetMessage* pMessage, CNetSession* pSession );
};*/
#endif // NETSESSION_H

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* 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
@ -15,419 +15,20 @@
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "Network.h"
#include "Serialization.h"
#include "ps/CLogger.h"
#include "NetLog.h"
DEFINE_ERROR(CONFLICTING_OP_IN_PROGRESS, "A conflicting operation is already in progress");
#define LOG_CATEGORY L"net"
/**
* The SNetHeader will always be stored in host-order
*/
struct SNetHeader
CStr CErrorMessage::ToString() const
{
u8 m_MsgType;
u16 m_MsgLength;
inline const u8 *Deserialize(const u8 *pos)
{
Deserialize_int_1(pos, m_MsgType);
Deserialize_int_2(pos, m_MsgLength);
return pos;
}
inline u8 *Serialize(u8 *pos) const
{
Serialize_int_1(pos, m_MsgType);
Serialize_int_2(pos, m_MsgLength);
return pos;
}
};
#define HEADER_LENGTH 3
CMessagePipe::CMessagePipe()
{
m_Ends[0]=End(this, &m_Queues[0], &m_Queues[1]);
m_Ends[1]=End(this, &m_Queues[1], &m_Queues[0]);
// pthread_cond_init(&m_CondVar, NULL);
return CStr("NetErrorMessage: ") + m_Error;
}
void CMessagePipe::End::Push(CNetMessage *msg)
{
m_pOut->Lock();
m_pOut->push_back(msg);
m_pOut->Unlock();
/*pthread_mutex_lock(&m_pPipe->m_CondMutex);
pthread_cond_broadcast(&m_pPipe->m_CondVar);
pthread_mutex_unlock(&m_pPipe->m_CondMutex);*/
}
CNetMessage *CMessagePipe::End::TryPop()
{
CScopeLock lock(m_pIn->m_Mutex);
if (m_pIn->size())
{
CNetMessage *msg=m_pIn->front();
m_pIn->pop_front();
return msg;
}
return NULL;
}
/*void CMessagePipe::End::WaitPop(CNetMessage *msg)
{
while (!TryPop(msg))
{
pthread_mutex_lock(&m_pPipe->m_CondMutex);
pthread_cond_wait(&m_pPipe->m_CondVar, &m_pPipe->m_CondMutex);
pthread_mutex_unlock(&m_pPipe->m_CondMutex);
}
}*/
/*CStr CErrorMessage::GetString() const
{
static const char* const states[]={
"SS_UNCONNECTED",
"SS_CONNECT_STARTED",
"SS_CONNECTED",
"SS_CLOSED_LOCALLY"
};
return CStr("NetErrorMessage: ")+
m_Error+", Socket State "+states[m_State];
}
CStr CConnectCompleteMessage::GetString() const
CStr CConnectCompleteMessage::ToString() const
{
return CStr("ConnectCompleteMessage");
}
CStr CCloseRequestMessage::GetString() const
CStr CCloseRequestMessage::ToString() const
{
return CStr("CloseRequestMessage");
}*/
CStr CErrorMessage::ToString( void ) const
{
static const char* const states[]=
{
"SS_UNCONNECTED",
"SS_CONNECT_STARTED",
"SS_CONNECTED",
"SS_CLOSED_LOCALLY"
};
return CStr("NetErrorMessage: ")+
m_Error+", Socket State "+states[m_State];
}
CStr CConnectCompleteMessage::ToString( void ) const
{
return CStr( "ConnectCompleteMessage" );
}
CStr CCloseRequestMessage::ToString( void ) const
{
return CStr( "CloseRequestMessage" );
}
void CMessageSocket::Push(CNetMessage *msg)
{
NET_LOG2( "CMessageSocket::Push(): %s", msg->ToString().c_str() );
m_OutQ.Lock();
m_OutQ.push_back(msg);
m_OutQ.Unlock();
StartWriteNextMessage();
}
CNetMessage *CMessageSocket::TryPop()
{
CScopeLock lock(m_InQ.m_Mutex);
if (m_InQ.size())
{
CNetMessage *msg=m_InQ.front();
m_InQ.pop_front();
return msg;
}
return NULL;
}
void CMessageSocket::StartWriteNextMessage()
{
m_OutQ.Lock();
if (!m_IsWriting && m_OutQ.size())
{
CNetMessage *pMsg=NULL;
while (pMsg == NULL)
{
// This may happen when the last message of the queue is an invalid
// message type (non-network or socket command)
if (m_OutQ.size() == 0)
return;
// Pop next output message
pMsg=m_OutQ.front();
m_OutQ.pop_front();
m_IsWriting=true;
m_OutQ.Unlock();
if (pMsg->GetType() == NMT_CLOSE_REQUEST)
{
Close();
delete pMsg;
pMsg=NULL;
}
else if (pMsg->GetType() < 0)
{
LOG(CLogger::Warning, LOG_CATEGORY, L"CMessageSocket::StartWriteNextMessage(): Non-network message");
delete pMsg;
pMsg=NULL;
}
}
// Prepare the header
SNetHeader hdr;
hdr.m_MsgType=pMsg->GetType();
hdr.m_MsgLength=(u16)pMsg->GetSerializedLength();
// Allocate buffer space
if ((size_t)(hdr.m_MsgLength+HEADER_LENGTH) > m_WrBufferSize)
{
//m_WrBufferSize = BUFFER_SIZE(hdr.m_MsgLength+HEADER_LENGTH);
m_WrBufferSize = ALIGN_BLOCK(hdr.m_MsgLength+HEADER_LENGTH);
if (m_pWrBuffer)
m_pWrBuffer=(u8 *)realloc(m_pWrBuffer, m_WrBufferSize);
else
m_pWrBuffer=(u8 *)malloc(m_WrBufferSize);
}
// Fill in buffer
u8 *pos=m_pWrBuffer;
pos=hdr.Serialize(pos);
pMsg->Serialize(pos);
// Deallocate message
delete pMsg;
// Start Write Operation
//printf("CMessageSocket::StartWriteNextMessage(): Writing an MT %d, length %u (%u)\n", hdr.m_MsgType, hdr.m_MsgLength+HEADER_LENGTH, hdr.m_MsgLength);
PS_RESULT res=Write(m_pWrBuffer, hdr.m_MsgLength+HEADER_LENGTH);
if (res != PS_OK)
{
NET_LOG2( "CMessageSocket::StartWriteNextMessage(): %s", res );
// Queue Error Message
m_InQ.Lock();
m_InQ.push_back(new CErrorMessage(res, GetState()));
m_InQ.Unlock();
}
}
else
{
if (m_IsWriting)
{
NET_LOG( "CMessageSocket::StartWriteNextMessage(): Already writing" );
}
else
{
NET_LOG("CMessageSocket::StartWriteNextMessage(): Nothing to write");
}
m_OutQ.Unlock();
}
}
void CMessageSocket::WriteComplete(PS_RESULT ec)
{
NET_LOG2( "CMessageSocket::WriteComplete(): %s", ec );
if (ec == PS_OK)
{
if (m_IsWriting)
{
m_OutQ.Lock();
m_IsWriting=false;
m_OutQ.Unlock();
StartWriteNextMessage();
}
else
{
NET_LOG( "CMessageSocket::WriteComplete(): Was not writing" );
}
}
else
{
// Push an error message
m_InQ.push_back(new CErrorMessage(ec, GetState()));
}
}
void CMessageSocket::StartReadHeader()
{
if (m_RdBufferSize < HEADER_LENGTH)
{
//m_RdBufferSize=BUFFER_SIZE(HEADER_LENGTH);
m_RdBufferSize=ALIGN_BLOCK(HEADER_LENGTH);
if (m_pRdBuffer)
m_pRdBuffer=(u8 *)realloc(m_pRdBuffer, m_RdBufferSize);
else
m_pRdBuffer=(u8 *)malloc(m_RdBufferSize);
}
m_ReadingData=false;
printf("CMessageSocket::StartReadHeader(): Trying to read %u\n", HEADER_LENGTH);
PS_RESULT res=Read(m_pRdBuffer, HEADER_LENGTH);
if (res != PS_OK)
{
NET_LOG2( "CMessageSocket::StartReadHeader(): %s", res );
// Push an error message
CScopeLock scopeLock(m_InQ.m_Mutex);
m_InQ.push_back(new CErrorMessage(res, GetState()));
}
}
void CMessageSocket::StartReadMessage()
{
SNetHeader hdr;
hdr.Deserialize(m_pRdBuffer);
size_t reqBufSize=HEADER_LENGTH+hdr.m_MsgLength;
if (m_RdBufferSize < reqBufSize)
{
//m_RdBufferSize=BUFFER_SIZE(reqBufSize);
m_RdBufferSize=ALIGN_BLOCK(reqBufSize);
if (m_pRdBuffer)
m_pRdBuffer=(u8 *)realloc(m_pRdBuffer, m_RdBufferSize);
else
m_pRdBuffer=(u8 *)malloc(m_RdBufferSize);
}
m_ReadingData=true;
if (hdr.m_MsgLength == 0)
{
ReadComplete(PS_OK);
}
else
{
PS_RESULT res=Read(m_pRdBuffer+HEADER_LENGTH, hdr.m_MsgLength);
if (res != PS_OK)
{
NET_LOG2( "CMessageSocket::StartReadMessage(): %s", res );
// Queue an error message
CScopeLock scopeLock(m_InQ);
m_InQ.push_back(new CErrorMessage(res, GetState()));
}
}
}
void CMessageSocket::ReadComplete(PS_RESULT ec)
{
NET_LOG3( "CMessageSocket::ReadComplete(%ls): %s", m_ReadingData ? L"data":L"header", ec );
// Check if we were reading header or message
// If header:
if (!m_ReadingData)
{
StartReadMessage();
}
// If data:
else
{
SNetHeader hdr;
hdr.Deserialize(m_pRdBuffer);
//CNetMessage *pMsg=CNetMessage::DeserializeMessage((ENetMessageType)hdr.m_MsgType, m_pRdBuffer+HEADER_LENGTH, hdr.m_MsgLength);
CNetMessage *pMsg = CNetMessageFactory::CreateMessage( m_pRdBuffer+HEADER_LENGTH, hdr.m_MsgLength);
if (pMsg)
{
OnMessage(pMsg);
}
else
{
NET_LOG3( "CMessageSocket::ReadComplete(): Deserialization failed! (type %d, length %d)", hdr.m_MsgType, hdr.m_MsgLength );
NET_LOG( "Data: {" );
for (int i=HEADER_LENGTH;i<hdr.m_MsgLength+HEADER_LENGTH;i++)
{
NET_LOG3( "\t0x%x [%c]", m_pRdBuffer[i], isalnum(m_pRdBuffer[i])?m_pRdBuffer[i]:'.' );
}
NET_LOG( "};" );
}
StartReadHeader();
}
}
void CMessageSocket::OnMessage(CNetMessage *pMsg)
{
m_InQ.Lock();
m_InQ.push_back(pMsg);
NET_LOG2( "CMessageSocket::OnMessage(): %s", pMsg->ToString().c_str() );
NET_LOG2( "CMessageSocket::OnMessage(): Queue size now %lu", (unsigned long)m_InQ.size() );
m_InQ.Unlock();
}
void CMessageSocket::ConnectComplete(PS_RESULT ec)
{
if (ec == PS_OK)
{
StartReadHeader();
CScopeLock scopeLock(m_InQ);
m_InQ.push_back(new CConnectCompleteMessage());
}
else
{
CScopeLock scopeLock(m_InQ);
m_InQ.push_back(new CErrorMessage(ec, GetState()));
}
}
void CMessageSocket::OnClose(PS_RESULT errorCode)
{
CScopeLock scopeLock(m_InQ.m_Mutex);
m_InQ.push_back(new CErrorMessage(errorCode, GetState()));
}
CMessageSocket::CMessageSocket(CSocketInternal *pInt):
CStreamSocket(pInt),
m_IsWriting(false),
m_pWrBuffer(NULL),
m_WrBufferSize(0),
m_ReadingData(false),
m_pRdBuffer(NULL),
m_RdBufferSize(0)
{
StartReadHeader();
}
CMessageSocket::CMessageSocket():
m_IsWriting(false),
m_pWrBuffer(NULL),
m_WrBufferSize(0),
m_ReadingData(false),
m_pRdBuffer(NULL),
m_RdBufferSize(0)
{
}
CMessageSocket::~CMessageSocket()
{
if (m_pRdBuffer)
free(m_pRdBuffer);
if (m_pWrBuffer)
free(m_pWrBuffer);
}
PS_RESULT CMessageSocket::BeginConnect(const char *address, int port)
{
StartReadHeader();
return CStreamSocket::BeginConnect(address, port);
}
// End of Network.cpp

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* 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
@ -15,279 +15,48 @@
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
/*
Network.h
OVERVIEW
Contains the public interfaces to the networking code.
CMessageSocket is a socket that sends and receives messages from the
network. The global interface for sending and receiving messages is
an IMessagePipeEnd.
CMessagePipe also uses IMessagePipeEnd as its public interface, meaning that
a CMessageSocket can be invisibly replaced with a CMessagePipe. Thus, the
difference between MP and SP games is the source of pipe ends.
Code that just wants to send messages will most likely only be confronted
with the message pipe end interface.
EXAMPLES
To create a queue pair for IPC communication:
CMessagePipe pipe;
StartThread1(pipe[0]);
StartThread2(pipe[1]);
The argument type for StartThreadX would be "IMessagePipeEnd &".
NOTES ON THREAD SAFETY
All operations on an IMessagePipeEnd are fully thread-secure. Multiple access
to other interfaces of a CMessageSocket is not secure (but the IMessagePipeEnd
interface to a CMessageSocket is still fully thread secure)
MORE INFO
*/
#ifndef INCLUDED_NETWORK_NETWORK
#define INCLUDED_NETWORK_NETWORK
//--------------------------------------------------------
// Includes / Compiler directives
//--------------------------------------------------------
#include "ps/Pyrogenesis.h"
#include "ps/ThreadUtil.h"
#include "StreamSocket.h"
#include "NetMessage.h"
#include "lib/bits.h" // round_up
#include <deque>
#include <map>
//-------------------------------------------------
// Typedefs and Macros
//-------------------------------------------------
#define ALIGN_BLOCK( _n ) round_up(size_t(_n), size_t(4096))
typedef CLocker<std::deque <CNetMessage *> > CLockedMessageDeque;
//-------------------------------------------------
// Error Codes
//-------------------------------------------------
DECLARE_ERROR( CONFLICTING_OP_IN_PROGRESS );
//-------------------------------------------------
// Declarations
//-------------------------------------------------
class IMessagePipeEnd;
class CMessagePipe;
class CMessageSocket;
class IMessagePipeEnd
{
public:
virtual ~IMessagePipeEnd() {}
/**
* Push a message on the output queue. It will be freed when popped of the
* queue, not by the caller. The pointer must point to memory that can be
* safely freed by delete.
*/
virtual void Push(CNetMessage *msg)=0;
/**
* Try to pop a message from the input queue
*
* @return A pointer to the popped message, or NULL if the queue was empty
*/
virtual CNetMessage *TryPop()=0;
/**
* Wait for a message on the input queue
*
* Inputs
* pMsg: A pointer to a message struct to store the popped message
*
* Returns
* Void. The function returns successfully or blocks indefinitely.
*/
// virtual void WaitPop(CNetMessage *)=0;
};
/**
* A message pipe with two ends, communication flowing in both directions.
* The two ends are indexed with the [] operator or the GetEnd() method.
* Each end has two associated queues, one input and one output queue. The
* input queue of one End is the output queue of the other End and vice versa.
*/
class CMessagePipe
{
private:
friend struct End;
struct End: public IMessagePipeEnd
{
CMessagePipe *m_pPipe;
CLockedMessageDeque *m_pIn;
CLockedMessageDeque *m_pOut;
inline End()
{}
inline End(CMessagePipe *pPipe, CLockedMessageDeque *pIn, CLockedMessageDeque *pOut):
m_pPipe(pPipe), m_pIn(pIn), m_pOut(pOut)
{}
virtual ~End() {}
virtual void Push(CNetMessage *);
virtual CNetMessage *TryPop();
//virtual void WaitPop(CNetMessage *);
};
CLockedMessageDeque m_Queues[2];
End m_Ends[2];
// pthread_cond_t m_CondVar;
pthread_mutex_t m_CondMutex;
public:
CMessagePipe();
/**
* Return one of the two ends of the pipe
*/
inline IMessagePipeEnd &operator [] (int idx)
{
return GetEnd(idx);
}
/**
* Return one of the two ends of the pipe
*/
inline IMessagePipeEnd &GetEnd(int idx)
{
debug_assert(idx==1 || idx==0);
return m_Ends[idx];
}
};
class CServerSocket: public CSocketBase
{
protected:
/**
* The default implementation of this method accepts an incoming connection
* and calls OnAccept() with the accepted internal socket instance.
*
* NOTE: Subclasses should never overload this method, overload OnAccept()
* instead.
*/
virtual void OnRead();
virtual void OnWrite();
virtual void OnClose(PS_RESULT errorCode);
public:
virtual ~CServerSocket();
/**
* There is an incoming connection in the queue. Examine the SocketAddress
* and call Accept() or Reject() to accept or reject the incoming
* connection
*
* @see CSocketBase::Accept()
* @see CSocketBase::Reject()
*/
virtual void OnAccept(const CSocketAddress &)=0;
};
class CErrorMessage: public CNetMessage
class CErrorMessage : public CNetMessage
{
public:
PS_RESULT m_Error;
ESocketState m_State;
inline CErrorMessage():
inline CErrorMessage() :
CNetMessage(NMT_ERROR)
{}
{
}
inline CErrorMessage(PS_RESULT error, ESocketState state):
CNetMessage(NMT_ERROR),
m_Error(error),
m_State(state)
{}
inline CErrorMessage(PS_RESULT error) :
CNetMessage(NMT_ERROR), m_Error(error)
{
}
virtual CStr ToString() const;
};
struct CCloseRequestMessage: public CNetMessage
struct CCloseRequestMessage : public CNetMessage
{
inline CCloseRequestMessage(): CNetMessage(NMT_CLOSE_REQUEST)
{}
inline CCloseRequestMessage() :
CNetMessage(NMT_CLOSE_REQUEST)
{
}
virtual CStr ToString() const;
};
struct CConnectCompleteMessage: public CNetMessage
struct CConnectCompleteMessage : public CNetMessage
{
inline CConnectCompleteMessage(): CNetMessage(NMT_CONNECT_COMPLETE)
{}
inline CConnectCompleteMessage() :
CNetMessage(NMT_CONNECT_COMPLETE)
{
}
virtual CStr ToString() const;
};
/**
* Implements a Message Pipe over an Async IO stream socket.
*
* All methods that this class exposes are thread safe and may be called from
* any thread.
*/
class CMessageSocket: protected CStreamSocket, public IMessagePipeEnd
{
bool m_IsWriting;
u8 *m_pWrBuffer;
size_t m_WrBufferSize;
bool m_ReadingData;
u8 *m_pRdBuffer;
size_t m_RdBufferSize;
CLockedMessageDeque m_InQ; // Messages read from socket
CLockedMessageDeque m_OutQ;// Messages to write to socket
// pthread_cond_t m_InCond;
// pthread_cond_t m_OutCond;
void StartWriteNextMessage();
void StartReadHeader();
void StartReadMessage();
protected:
virtual void ReadComplete(PS_RESULT);
virtual void WriteComplete(PS_RESULT);
virtual void OnClose(PS_RESULT);
virtual void ConnectComplete(PS_RESULT);
virtual void OnMessage(CNetMessage *pMsg);
public:
CMessageSocket(CSocketInternal *pInt);
CMessageSocket();
virtual ~CMessageSocket();
virtual void Push(CNetMessage *);
virtual CNetMessage *TryPop();
/**
* See CStreamSocket::BeginConnect.
*/
PS_RESULT BeginConnect(const char *address, int port);
};
#endif

View File

@ -1,113 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_NETWORK_NETWORKINTERNAL
#define INCLUDED_NETWORK_NETWORKINTERNAL
#include <map>
#if !OS_WIN
#define Network_GetErrorString(_error, _buf, _buflen) strerror_r(_error, _buf, _buflen)
#define Network_LastError errno
#define closesocket(_fd) close(_fd)
#else // i.e. #if OS_WIN
#define Network_GetErrorString(_error, _buf, _buflen) \
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, _error+WSABASEERR, 0, _buf, _buflen, NULL)
#define Network_LastError (WSAGetLastError() - WSABASEERR)
// These are defined so that WSAGLE - WSABASEERR = E*
// i.e. the same error name can be used in winsock and posix
#define WSABASEERR 10000
#define MSG_SOCKET_READY WM_USER
#endif // #if OS_WIN
typedef int socket_t;
class CSocketInternal
{
public:
socket_t m_fd;
CSocketAddress m_RemoteAddr;
socket_t m_AcceptFd;
CSocketAddress m_AcceptAddr;
// Bitwise OR of all operations to listen for.
// See READ and WRITE
int m_Ops;
char *m_pConnectHost;
int m_ConnectPort;
u64 m_SentBytes;
u64 m_RecvBytes;
inline CSocketInternal():
m_fd(-1),
m_AcceptFd(-1),
m_Ops(0),
m_pConnectHost(NULL),
m_ConnectPort(-1),
m_SentBytes(0),
m_RecvBytes(0)
{
}
};
struct CSocketSetInternal
{
// Any access to the global variables should be protected using m_Mutex
pthread_mutex_t m_Mutex;
pthread_t m_Thread;
size_t m_NumSockets;
std::map <socket_t, CSocketBase * > m_HandleMap;
#if OS_WIN
HWND m_hWnd;
#else
// [0] is for use by RunWaitLoop, [1] for SendWaitLoopAbort and SendWaitLoopUpdate
int m_Pipe[2];
#endif
u64 m_GlobalSentBytes;
u64 m_GlobalRecvBytes;
public:
inline CSocketSetInternal()
{
#if OS_WIN
m_hWnd=NULL;
#else
m_Pipe[0]=-1;
m_Pipe[1]=-1;
#endif
pthread_mutex_init(&m_Mutex, NULL);
m_Thread=0;
m_NumSockets=0;
m_GlobalSentBytes=0;
m_GlobalRecvBytes=0;
}
};
#endif

View File

@ -1,48 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "Network.h"
#include "NetLog.h"
CServerSocket::~CServerSocket()
{
}
void CServerSocket::OnRead()
{
CSocketAddress remoteAddr;
PS_RESULT res=PreAccept(remoteAddr);
if (res==PS_OK)
{
OnAccept(remoteAddr);
}
else
{
// All errors are non-critical, so no need to do anything special besides
// not calling OnAccept [ shouldn't be, that is ;-) ]
NET_LOG2( "CServerSocket::OnRead(): PreAccept returned an error: %s", res );
}
}
void CServerSocket::OnWrite()
{}
void CServerSocket::OnClose(PS_RESULT UNUSED(errorCode))
{}

File diff suppressed because it is too large Load Diff

View File

@ -1,503 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_NETWORK_SOCKETBASE
#define INCLUDED_NETWORK_SOCKETBASE
//--------------------------------------------------------
// Includes / Compiler directives
//--------------------------------------------------------
#include "lib/posix/posix_sock.h"
#include "ps/Pyrogenesis.h"
#include <string.h>
#include "ps/CStr.h"
//-------------------------------------------------
// Error Codes
//-------------------------------------------------
DECLARE_ERROR( CONNECT_TIMEOUT );
DECLARE_ERROR( CONNECT_REFUSED );
DECLARE_ERROR( NO_SUCH_HOST );
DECLARE_ERROR( NO_ROUTE_TO_HOST );
DECLARE_ERROR( CONNECTION_BROKEN );
DECLARE_ERROR( WAIT_ABORTED );
DECLARE_ERROR( PORT_IN_USE );
DECLARE_ERROR( INVALID_PORT );
DECLARE_ERROR( WAIT_LOOP_FAIL );
DECLARE_ERROR( CONNECT_IN_PROGRESS );
DECLARE_ERROR( INVALID_PROTOCOL );
//-------------------------------------------------
// Declarations
//-------------------------------------------------
class CSocketInternal;
/**
* An enumeration of all supported protocols, and the special value UNSPEC,
* which represents an invalid address.
*/
// Modifiers Note: Each value in the enum should correspond to a sockaddr_*
// struct and a PF_* value
enum ESocketProtocol
{
// This should be a value that's invalid for most socket functions, so that
// you don't accidentally use an UNSPEC SocketAddress
// PF_UNSPEC does not work, since it is accepted by many implementations as
// a "default" protocol family - whatever that may be
UNSPEC=((sa_family_t)-1),
IPv4=PF_INET,
IPv6=PF_INET6,
/* More protocols */
};
/**
* A protocol-independent representation of a socket address. All protocols
* in the ESocketProtocol enum should have a corresponding member in this union.
*/
// Modifiers Note: Each member must contain a first field, compatible with the
// sin_family field of sockaddr_in. The field contains the ESocketProtocol value
// for the address, and it is returned by GetProtocol()
struct CSocketAddress
{
union
{
sa_family_t m_Family;
sockaddr_in m_IPv4;
sockaddr_in6 m_IPv6;
} m_Union;
inline ESocketProtocol GetProtocol() const
{
return (ESocketProtocol)m_Union.m_Family;
}
inline CSocketAddress()
{
memset(&m_Union, 0, sizeof(m_Union));
m_Union.m_Family=UNSPEC;
}
/**
* Create a wildcard address for the specified protocol with a specified
* port.
*
* @param port The port number, in local byte order
* @param proto The protocol to use; default IPv4
*/
explicit CSocketAddress(int port, ESocketProtocol proto=IPv4);
/**
* Create an address from a numerical IPv4 address and port, port in local
* byte order, IPv4 address as a byte array in written order. The Protocol
* of the resulting SocketAddress will be IPv4
*
* @param address An IPv4 address as a byte array (in written order)
* @param port A port number (0-65535) in local byte order.
*/
CSocketAddress(u8 address[4], int port);
/**
* Resolve the name using the system name resolution service (i.e. DNS) and
* store the resulting address. When multiple addresses are found, the
* first result is returned.
*
* Note that this call will block until the name resolution attempt is
* either completed successfully or timed out.
*
* @param name The name to resolve
* @param addr A reference to the variable to hold the address
*
* @return The result of the operation
* @retval PS_OK The hostname was successfully retrieved
* @retval NO_SUCH_HOST The hostname was not found
*/
static PS_RESULT Resolve(const char *name, int port, CSocketAddress &addr);
/**
* Returns the string representation of the address, i.e. the IP (v4 or v6)
* address. Note that the port is not included in the string (mostly due to
* the fact that the port representation differs wildly between address
* families, and that Resolve does not take port as part of the hostname)
*/
CStr GetString() const;
/**
* Returns the port number part of the address
*/
int GetPort() const;
/*
Create an address pointing to the loopback, with the specified port and
protocol. Use this with Bind to only listen on the loopback interface.
*/
static CSocketAddress Loopback(int port, ESocketProtocol proto=IPv4);
};
/**
* An enumeration of socket states
*
* @see CSocketBase::GetState()
*/
enum ESocketState
{
/**
* The socket is unconnected. Use GetError() to see if it is due to a
* failure, a clean close, or it was never connected.
*
* @see CSocketBase::GetError()
*/
SS_UNCONNECTED=0,
/**
* A connect attempt has started on a non-blocking socket. The error state
* will be CONNECTION_BROKEN.
*
* @see CSocketBase::OnWrite()
*/
SS_CONNECT_STARTED,
/**
* The socket is connected. The error state will be set to PS_OK.
*/
SS_CONNECTED,
/**
* The connection has been closed on this end, but the other end might have
* sent data that we haven't received yet. The error state will be set to
* PS_OK.
*/
SS_CLOSED_LOCALLY
};
/**
* Contains the basic socket I/O abstraction and event callback methods.
* A CSocketBase can only be instantiated as a subclass, none of the functions
* are meant to exist as anything other than helper functions for socket
* classes
*
* Any CSocket subclass that can be Accept:ed by a CServerSocket should
* provide a constructor that takes a CSocketInternal pointer, and hands it to
* the base class constructor.
*/
class CSocketBase
{
private:
CSocketInternal *m_pInternal;
ESocketState m_State;
PS_RESULT m_Error;
ESocketProtocol m_Proto;
bool m_NonBlocking;
/**
* Loop forever, waiting for events and calling the callbacks on sockets,
* according to their Op mask. This loop may be aborted by calling
* AbortWaitLoop.
*
* The global lock must be held when calling this function, and will be held
* upon return from it.
*/
static void RunWaitLoop();
/**
* The network thread entry point. Simply locks the global lock and calls
* RunWaitLoop.
*/
friend void *WaitLoopThreadMain(void *);
#if OS_WIN
/**
* Used by the winsock AsyncSelect windowproc
*/
friend void WaitLoop_SocketUpdateProc(int fd, int error, int eventmask);
#else
// These are utility functions for the unix select loop. Dox can be found in
// the source file.
static bool ConnectError(CSocketBase *);
static void SocketWritable(CSocketBase *);
static void SocketReadable(CSocketBase *);
#endif
/**
* Abort the call to RunWaitLoop(), if one is currently running.
*/
static void AbortWaitLoop();
/**
* Tell the running wait loop to abort. This is the platform-dependent
* implementation of AbortWaitLoop()
*/
static void SendWaitLoopAbort();
void SendWaitLoopUpdate();
protected:
/**
* Initialize a CSocketBase from a CSocketInternal pointer. Use in OnAccept
* callbacks to create an object of your subclass. This constructor should
* be overloaded by any subclass that may be Accept:ed.
*/
CSocketBase(CSocketInternal *pInt);
virtual ~CSocketBase();
/**
* Get the op mask for the socket.
*/
int GetOpMask();
/**
* Set the op mask for the socket, specifying which callbacks should be
* called by the WaitLoop. The initial op mask is zero, which means that
* this method must be called explicitly for any callbacks to be called.
* Note that before the call to BeginConnect or Bind, any call to this
* method is a no-op.
*
* It is safe to call this function while a RunWaitLoop is running.
*
* The wait loop guarantees that the callbacks specified in ops will be
* called when appropriate, but does not make the opposite guarantee for
* unset bits; i.e. any callback may be called even with a zero op mask.
*/
void SetOpMask(int ops);
public:
/**
* These values are bitwise or-ed to produce op masks
*/
enum Ops
{
/**
* Call OnRead() on a stream socket when there is data to read from the
* socket, or OnAccept() on a server socket when there are incoming
* connections pending
*/
READ=1,
// Call OnWrite() when there is space available in the socket's output
// buffer. Has no effect on server sockets.
WRITE=2
};
/**
* Constructs a CSocketBase. The OS socket object is not created by the
* constructor, but by the protected Initialize method, which is called by
* Connect and Bind.
*
* @see Connect
* @see Bind
*/
CSocketBase();
/**
* Forcibly shuts down the network wait loop. This should happen
* automatically as soon as all sockets are closed.
*/
static void Shutdown();
/**
* Returns the protocol set by Initialize. All SocketAddresses used with
* the socket must have the same SocketProtocol
*/
inline ESocketProtocol GetProtocol() const
{ return m_Proto; }
/**
* Destroy the OS socket. If the socket is not cleanly closed before, it
* will be forcefully closed by calling this method.
*/
void Destroy();
/**
* Close the socket. No more data can be sent over the socket, but any data
* pending from the remote host will still be received, and the OnRead
* callback called (if the socket's op mask has the READ bit set). Note
* that the socket isn't actually closed until the remote end calls
* Close on the corresponding remote socket, upon which the OnClose
* callback is called with a status code of PS_OK.
*/
void Close();
/**
* Create the OS socket for the specified protocol type.
*/
PS_RESULT Initialize(ESocketProtocol proto=IPv4);
/**
* Connect the socket to the specified address. The socket must be
* initialized for the protocol of the address.
*
* @param addr The address to connect to
* @see SocketAddress::Resolve
*/
PS_RESULT Connect(const CSocketAddress &addr);
/** @name Functions for Server Sockets */
//@{
/**
* Bind the socket to the specified address and start listening for
* incoming connections. You must initialize the socket for the correct
* SocketProtocol before calling Bind.
*
* @param addr The address to bind to
* @see SocketAddress::SocketAddress(int,SocketProtocol)
*/
PS_RESULT Bind(const CSocketAddress &addr);
/**
* Store the address of the next incoming connection in the SocketAddress
* pointed to by addr. You must then choose whether to accept or reject the
* connection by calling Accept or Reject
*
* @param addr A pointer to a SocketAddress
* @return PS_OK or an error code
*
* @see Accept(SocketAddress&)
* @see Reject()
*/
PS_RESULT PreAccept(CSocketAddress &addr);
/**
* Accept the next incoming connection. You must construct a suitable
* CSocketBase subclass using the passed CSocketInternal.
* May only be called after a successful PreAccept call
*/
CSocketInternal *Accept();
/**
* Reject the next incoming connection.
*
* May only be called after a successful PreAccept call
*/
void Reject();
//@}
/** @name Status and Options */
//@{
/**
* Set or reset non-blocking operation. When non-blocking, all socket
* operations will return immediately, having done none or parts of
* the operation. The default state for a socket is non-blocking
*
* @see CSocketBase::Read
* @see CSocketBase::Write
* @see CSocketBase::Connect
*/
void SetNonBlocking(bool nonBlocking=true);
/**
* Return the current non-blocking state of the socket.
*
* @see SetNonBlocking(bool)
*/
inline bool IsNonBlocking() const
{ return m_NonBlocking; }
/**
* Return the error state of the socket. This will be the same value that
* was returned by the IO function that failed.
*
* @see GetState()
*/
inline PS_RESULT GetErrorState() const
{ return m_Error; }
/**
* Return the connection state of the socket. If the connection status is
* "unconnected", use GetError() to see if it was disconnected due to an
* error, or cleanly closed.
*
* @see SocketState
* @see GetError()
*/
inline ESocketState GetState() const
{ return m_State; }
/**
* Disable Nagle's algorithm (enable no-delay working mode)
*/
void SetTcpNoDelay(bool tcpNoDelay=true);
/**
* Get the address of the remote end to which the socket is connected.
*
* @return A reference to the socket address
*/
const CSocketAddress &GetRemoteAddress();
//@}
/** @name Stream I/O */
//@{
/**
* Attempt to read data from the socket. Any data available without blocking
* will be returned. Note that a successful return does not mean that the
* whole buffer was filled.
*
* @param buf A pointer to the buffer where the data should be written
* @param len The amount of data that should be read.
* @param bytesRead The number of bytes read will be stored in the variable
* pointed to by bytesRead
*
* @retval PS_OK Some or all data was successfully read.
* @retval CONNECTION_BROKEN The socket is not connected or a server socket
*/
PS_RESULT Read(void *buf, size_t len, size_t *bytesRead);
/**
* Attempt to write data to the socket. All data that can be sent without
* blocking will be buffered.
*
* @param buf A pointer to the data that should be written
* @param len The length of the buffer.
* @param bytesWritten The number of bytes written will be stored in the
* variable pointed to by bytesWritten
*
* @retval PS_OK Some or all data was successfully read.
* @retval CONNECTION_BROKEN The socket is not connected or a server socket
*/
PS_RESULT Write(void *buf, size_t len, size_t *bytesWritten);
//@}
/** @name Callbacks */
//@{
/**
* Called by the Network Thread when data is available for reading. Use
* SetOpMask with the READ bit set to enable calling of this function.
*
* For server sockets, "data is available for reading" means "incoming
* connections are pending".
*/
virtual void OnRead()=0;
/**
* Called by the Network Thread when data can be written to the socket.
* Will only be called when the WRITE bit is set in the Op Mask of the
* socket.
*/
virtual void OnWrite()=0;
/**
* The socket has been closed. It is not certain that the error code
* provides meaningful diagnostics. CONNECTION_BROKEN is the generic catch-
* all for erroneous closures, PS_OK for clean closures.
*
* @param errorCode A result code describing the reason why the socket was
* closed
*/
virtual void OnClose(PS_RESULT errorCode)=0;
};
#endif

View File

@ -1,190 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "Network.h"
#include "StreamSocket.h"
#include "NetLog.h"
CStreamSocket::CStreamSocket()
{}
CStreamSocket::CStreamSocket(CSocketInternal *pInt):
CSocketBase(pInt)
{}
CStreamSocket::~CStreamSocket()
{
}
void *CStreamSocket_ConnectThread(void *data)
{
debug_SetThreadName("net_connect");
CStreamSocket *pSock=(CStreamSocket *)data;
PS_RESULT res=PS_OK;
CSocketAddress addr;
res=CSocketAddress::Resolve(pSock->m_pConnectHost, pSock->m_ConnectPort, addr);
NET_LOG4("CStreamSocket_ConnectThread: Resolve: %s -> %s [%s]", pSock->m_pConnectHost, addr.GetString().c_str(), res);
if (res == PS_OK)
{
pSock->Initialize();
// If we don't do this we'll get spurious callbacks called since our
// network thread will notice the socket getting connected (and
// potentially receiving data) while we might not yet have called the
// ConnectComplete callback
pSock->SetOpMask(0);
pSock->SetNonBlocking(false);
res=pSock->Connect(addr);
NET_LOG2("CStreamSocket_ConnectThread: Connect: %s", res);
}
if (res == PS_OK)
{
pSock->SetNonBlocking(true);
// This should call the right callbacks, so that you get the expected
// results if you call Read or Write before the connect actually is complete
pSock->SetOpMask((pSock->m_WriteContext.m_Valid?CSocketBase::WRITE:0)|CSocketBase::READ);
}
pSock->ConnectComplete(res);
free(pSock->m_pConnectHost);
pSock->m_pConnectHost=NULL;
return NULL;
}
PS_RESULT CStreamSocket::BeginConnect(const char *hostname, int port)
{
m_pConnectHost=strdup(hostname);
m_ConnectPort=port;
// Start thread
pthread_t thread;
pthread_create(&thread, NULL, &CStreamSocket_ConnectThread, this);
return PS_OK;
}
PS_RESULT CStreamSocket::Read(void *buf, size_t len)
{
// Check socket status
if (GetState() != SS_CONNECTED)
return GetErrorState();
// Check for running read operation
if (m_ReadContext.m_Valid)
return CONFLICTING_OP_IN_PROGRESS;
// Fill in read_cb
m_ReadContext.m_Valid=true;
m_ReadContext.m_pBuffer=buf;
m_ReadContext.m_Length=len;
m_ReadContext.m_Completed=0;
SetOpMask(GetOpMask()|READ);
return PS_OK;
}
PS_RESULT CStreamSocket::Write(void *buf, size_t len)
{
// Check status
if (GetState() != SS_CONNECTED)
return GetErrorState();
// Check running Write operation
if (m_WriteContext.m_Valid)
return CONFLICTING_OP_IN_PROGRESS;
// Fill in read_cb
m_WriteContext.m_pBuffer=buf;
m_WriteContext.m_Length=len;
m_WriteContext.m_Completed=0;
m_WriteContext.m_Valid=true;
SetOpMask(GetOpMask()|WRITE);
return PS_OK;
}
#define MakeDefaultCallback(_nm) void CStreamSocket::_nm(PS_RESULT error) \
{ NET_LOG2("CStreamSocket::"#_nm"(): %s", error); }
MakeDefaultCallback(OnClose)
MakeDefaultCallback(ConnectComplete)
MakeDefaultCallback(ReadComplete)
MakeDefaultCallback(WriteComplete)
void CStreamSocket::OnWrite()
{
if (!m_WriteContext.m_Valid)
{
SetOpMask(GetOpMask() & (~WRITE));
return;
}
size_t bytes=0;
PS_RESULT res=CSocketBase::Write(
((char *)m_WriteContext.m_pBuffer)+m_WriteContext.m_Completed,
m_WriteContext.m_Length-m_WriteContext.m_Completed,
&bytes);
if (res != PS_OK)
{
WriteComplete(res);
return;
}
NET_LOG2("CStreamSocket::OnWrite(): %lu bytes", (unsigned long)bytes);
m_WriteContext.m_Completed+=bytes;
if (m_WriteContext.m_Completed == m_WriteContext.m_Length)
{
m_WriteContext.m_Valid=false;
WriteComplete(PS_OK);
}
}
void CStreamSocket::OnRead()
{
if (!m_ReadContext.m_Valid)
{
NET_LOG("CStreamSocket::OnRead(): No Read request in progress");
return;
}
size_t bytes=0;
PS_RESULT res=CSocketBase::Read(
((u8 *)m_ReadContext.m_pBuffer)+m_ReadContext.m_Completed,
m_ReadContext.m_Length-m_ReadContext.m_Completed,
&bytes);
NET_LOG4("CStreamSocket::OnRead(): %s, %lu bytes read of %lu",
res, (unsigned long)bytes,
(unsigned long)(m_ReadContext.m_Length-m_ReadContext.m_Completed));
if (res != PS_OK)
{
ReadComplete(res);
return;
}
m_ReadContext.m_Completed+=bytes;
if (m_ReadContext.m_Completed == m_ReadContext.m_Length)
{
m_ReadContext.m_Valid=false;
ReadComplete(PS_OK);
}
}

View File

@ -1,139 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_NETWORK_STREAMSOCKET
#define INCLUDED_NETWORK_STREAMSOCKET
#include "ps/Pyrogenesis.h"
#include "Network.h"
#include "SocketBase.h"
/**
* A class implementing Async I/O on top of the non-blocking event-driven
* CSocketBase
*/
class CStreamSocket: public CSocketBase
{
CMutex m_Mutex;
char *m_pConnectHost;
int m_ConnectPort;
struct SOperationContext
{
bool m_Valid;
void *m_pBuffer;
size_t m_Length;
size_t m_Completed;
inline SOperationContext():
m_Valid(false)
{}
};
SOperationContext m_ReadContext;
SOperationContext m_WriteContext;
protected:
friend void *CStreamSocket_ConnectThread(void *);
CStreamSocket(CSocketInternal *pInt);
/**
* Set the required socket options on the socket.
*/
void SetSocketOptions();
/**
* The destructor will disconnect the socket and free any OS resources.
*/
virtual ~CStreamSocket();
virtual void OnRead();
virtual void OnWrite();
public:
CStreamSocket();
/**
* The Lock function locks a mutex stored in the CStreamSocket object. None
* of the CStreamSocket methods actually use the mutex, it is just there as
* a convenience for the user.
*/
void Lock();
/**
* The Unlock function unlocks a mutex stored in the CStreamSocket object.
* None of the CSocket methods actually use the mutex, it is just there as a
* convenience for the user.
*/
void Unlock();
/**
* Begin a connect operation to the specified host and port. The connect
* operation and name resolution is performed in the background and the
* ConnectComplete callback is called when the connect is complete/failed
*
* Note that a PS_OK return only means that the connect operation has been
* initiated, not that it is successful.
*
* @param hostname A hostname or an IP address of the remote host
* @param port The TCP port number in host byte order
*
* @return PS_OK - The connect has been initiated
*/
PS_RESULT BeginConnect(const char *hostname, int port);
/**
* Start a read operation. The function call will return immediately and
* complete the I/O in the background. OnRead() will be called when it is
* complete. Until the Read is complete, the buffer should not be touched.
* There can only be one read operation in progress at one time.
*
* Inputs
* buf A pointer to the buffer where the data should be written
* len The length of the buffer. The amount of data the function should
* try to read.
*
* Returns
* PS_OK Some or all data was successfully read.
* CONFLICTING_OP_IN_PROGRESS Another Read operation is alread in progress
* CONNECTION_BROKEN The socket is not connected or a server socket
*/
PS_RESULT Read(void *buf, size_t len);
/**
* Start a Write operation. The function call will return immediately and
* the I/O complete in the background. OnWrite() will be called when i has
* completed. Until the Write is complete, the buffer shouldn't be touched.
* There can only be one write operation in progress at one time.
*
* @param buf A pointer to the buffer of data to write
* @param len The length of the buffer.
*
* Returns
* PS_OK Some or all data was successfully read.
* CONFLICTING_OP_IN_PROGRESS Another Write operation is in progress
* CONNECTION_BROKEN The socket is not connected or a server socket
*/
PS_RESULT Write(void *buf, size_t len);
// The default implementation of these methods are no-ops
virtual void ConnectComplete(PS_RESULT errorCode);
virtual void ReadComplete(PS_RESULT errorCode);
virtual void WriteComplete(PS_RESULT errorCode);
virtual void OnClose(PS_RESULT errorCode);
};
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* 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
@ -19,7 +19,6 @@
#define INCLUDED_NETWORK_STRINGCONVERTERS
#include "ps/CStr.h"
#include "simulation/EntityHandles.h"
template <typename _T>
CStr NetMessageStringConvert(const _T &arg);
@ -31,10 +30,4 @@ inline CStr NetMessageStringConvert(const _T &arg)
return CStr(arg);
}
template <>
inline CStr NetMessageStringConvert(const HEntity &arg)
{
return arg.operator CStr8();
}
#endif

View File

@ -1,24 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "GameRecord.h"
void CGameRecord::WriteMessage(CNetMessage* UNUSED(pMsg))
{
}

View File

@ -1,46 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_GAMERECORD
#define INCLUDED_GAMERECORD
#include "CStr.h"
class CNetMessage;
class CTurnManager;
class CGameRecord
{
bool m_IsRecording;
CTurnManager *m_pTurnManager;
public:
void Load(const CStr& filename);
void Record(const CStr& filename);
bool IsRecording();
/*
NOTE: The message will not be deleted by this method. Ownership remains
the caller's.
*/
void WriteMessage(CNetMessage *pMsg);
CTurnManager *GetPlaybackTurnManager();
};
#endif

View File

@ -452,7 +452,6 @@ static void RegisterJavascriptInterfaces()
PlayerCollection::Init( "PlayerCollection" );
// network
CNetMessage::ScriptingInit();
CNetClient::ScriptingInit();
CNetServer::ScriptingInit();
CNetSession::ScriptingInit();
@ -778,11 +777,6 @@ void Shutdown(int flags)
delete &g_ConfigDB;
TIMER_END(L"shutdown ConfigDB");
// Shut down the network loop
TIMER_BEGIN(L"shutdown CSocketBase");
CSocketBase::Shutdown();
TIMER_END(L"shutdown CSocketBase");
TIMER_BEGIN(L"shutdown CNetLogManager");
CNetLogManager::Shutdown();
TIMER_END(L"shutdown CNetLogManager");

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* 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
@ -522,138 +522,6 @@ CVector3D CSelectedEntities::GetGroupPosition( i8 groupid )
void CSelectedEntities::Update()
{
static std::vector<HEntity> lastSelection;
// Drop out immediately if we're in some special interaction mode
if (customSelectionMode)
return;
if( !( m_selected == lastSelection ) )
{
g_JSGameEvents.FireSelectionChanged( m_selectionChanged );
lastSelection = m_selected;
}
if( m_selectionChanged || g_Mouseover.m_targetChanged )
{
// Can't order anything off the map
if( !g_Game->GetWorld()->GetTerrain()->IsOnMap( g_Mouseover.m_worldposition ) )
{
m_defaultCommand = -1;
m_secondaryCommand = -1;
return;
}
// Quick count to see which is the modal default order.
const int numCommands=NMT_COMMAND_LAST - NMT_COMMAND_FIRST;
int defaultPoll[numCommands];
std::map<CStrW, int, CStrW_hash_compare> defaultCursor[numCommands];
std::map<int, int> defaultAction[numCommands];
int secondaryPoll[numCommands];
std::map<CStrW, int, CStrW_hash_compare> secondaryCursor[numCommands];
std::map<int, int> secondaryAction[numCommands];
int t, vote, secvote;
for( t = 0; t < numCommands; t++ )
{
defaultPoll[t] = 0;
secondaryPoll[t] = 0;
}
std::vector<HEntity>::iterator it;
for( it = m_selected.begin(); it < m_selected.end(); it++ )
{
CEventTargetChanged evt( g_Mouseover.m_target );
(*it)->DispatchEvent( &evt );
vote = evt.m_defaultOrder - NMT_COMMAND_FIRST;
secvote = evt.m_secondaryOrder - NMT_COMMAND_FIRST;
if( ( vote >= 0 ) && ( vote < numCommands ) )
{
defaultPoll[vote]++;
defaultCursor[vote][evt.m_defaultCursor]++;
defaultAction[vote][evt.m_defaultAction]++;
}
if( ( secvote >= 0 ) && ( secvote < numCommands ) )
{
secondaryPoll[secvote]++;
secondaryCursor[secvote][evt.m_secondaryCursor]++;
secondaryAction[secvote][evt.m_secondaryAction]++;
}
}
// Don't count GOTO as a majority action unless everything else has 0 votes.
defaultPoll[NMT_GOTO - NMT_COMMAND_FIRST] = 0;
vote = -1;
secvote = -1;
for( t = 0; t < numCommands; t++ )
{
if( ( vote == -1 ) || ( defaultPoll[t] > defaultPoll[vote] ) )
vote = t;
if( ( secvote == -1 ) || ( secondaryPoll[t] > secondaryPoll[secvote] ) )
secvote = t;
}
std::map<CStrW, int, CStrW_hash_compare>::iterator itv;
std::map<int, int>::iterator iti;
m_defaultCommand = vote + NMT_COMMAND_FIRST;
m_secondaryCommand = secvote + NMT_COMMAND_FIRST;
// Now find the most appropriate cursor
t = 0;
for( itv = defaultCursor[vote].begin(); itv != defaultCursor[vote].end(); itv++ )
{
if( itv->second > t )
{
t = itv->second;
g_CursorName = itv->first;
}
}
/*
TODO: provide secondary cursor name?
t = 0;
for( itv = secondaryCursor[secvote].begin(); itv != secondaryCursor[secvote].end(); itv++ )
{
if( itv->second > t )
{
t = itv->second;
g_CursorName = itv->first;
}
}*/
// Find the most appropriate action parameter too
t = 0;
for( iti = defaultAction[vote].begin(); iti != defaultAction[vote].end(); iti++ )
{
if( iti->second > t )
{
t = iti->second;
m_defaultAction = iti->first;
}
}
t = 0;
for( iti = secondaryAction[secvote].begin(); iti != secondaryAction[secvote].end(); iti++ )
{
if( iti->second > t )
{
t = iti->second;
m_secondaryAction = iti->first;
}
}
m_selectionChanged = false;
g_Mouseover.m_targetChanged = false;
}
if( ( m_group_highlight != -1 ) && GetGroupCount( m_group_highlight ) )
g_Game->GetView()->SetCameraTarget( GetGroupPosition( m_group_highlight ) );
}
void CMouseoverEntities::Update( float timestep )
@ -1434,6 +1302,7 @@ void CBuildingPlacer::MouseReleased()
if( m_valid )
{
/*
// issue a place object command across the network
CPlaceObjectMessage *msg = new CPlaceObjectMessage();
msg->m_IsQueued = hotkeys[HOTKEY_ORDER_QUEUE];
@ -1444,6 +1313,7 @@ void CBuildingPlacer::MouseReleased()
msg->m_Z = (u32) (clickPos.Z * 1000);
msg->m_Angle = (u32) (m_angle * 1000);
g_Game->GetSimulation()->QueueLocalCommand(msg);
*/
}
if( hotkeys[HOTKEY_ORDER_QUEUE] )

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* 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
@ -204,111 +204,6 @@ JSBool GetPlayerUnitCount( JSContext* cx, JSObject*, uintN argc, jsval* argv, js
return JS_TRUE;
}
//Used to create net messages for formations--msgList.front() is the original message. see IssueCommand
void CreateFormationMessage( std::vector<CNetMessage*>& msgList, CNetMessage* msg, CEntityList& formation )
{
CNetMessage* retMsg;
const int type = msg->GetType();
if ( type == NMT_GOTO )
{
//formationEnt->GetFormation()->BaseToMovement();
CGotoMessage* tmp = static_cast<CGotoMessage*>(msg);
retMsg = CNetMessage::CreatePositionMessage( formation, NMT_FORMATION_GOTO,
CVector2D(tmp->m_TargetX, tmp->m_TargetY) );
}
else if( type == NMT_RUN )
{
CGotoMessage* tmp = static_cast<CGotoMessage*>(msg);
retMsg = CNetMessage::CreatePositionMessage( formation, NMT_FORMATION_GOTO,
CVector2D(tmp->m_TargetX, tmp->m_TargetY) );
}
else if ( type == NMT_CONTACT_ACTION )
{
CContactActionMessage* tmp = static_cast<CContactActionMessage*>(msg);
retMsg = CNetMessage::CreateEntityIntMessage(formation, NMT_FORMATION_CONTACT_ACTION,
tmp->m_Target, tmp->m_Action);
}
else
return;
msgList.push_back(retMsg);
}
// Issue a command (network message) to an entity or collection.
// params: either an entity- or entity collection object, message ID [int],
// any further params needed by CNetMessage::CommandFromJSArgs
// returns: command in serialized form [string]
JSBool IssueCommand( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
{
// at least one for target object, one for isQueued, and then 1 or more for the CommandFromJSArgs
JSU_REQUIRE_MIN_PARAMS(3);
JSU_ASSERT(JSVAL_IS_OBJECT(argv[0]), "Argument 0 must be an entity collection.");
*rval = JSVAL_NULL;
CEntityList entities, msgEntities;
if (JS_InstanceOf(cx, JSVAL_TO_OBJECT(argv[0]), &CEntity::JSI_class, NULL))
entities.push_back( (ToNative<CEntity>(argv[0])) ->me);
else
entities = *EntityCollection::RetrieveSet(cx, JSVAL_TO_OBJECT(argv[0]));
typedef std::map<size_t, CEntityList> EntityStore;
EntityStore entityStore;
bool isQueued = ToPrimitive<bool>(argv[1]);
//Destroy old notifiers if we're explicitly being reassigned
for ( size_t i=0; i < entities.size(); i++)
{
if ( entities[i]->entf_get(ENTF_DESTROY_NOTIFIERS))
entities[i]->DestroyAllNotifiers();
}
std::vector<CNetMessage*> messages;
//Generate messages for formations
for (size_t i=0; i < entities.size(); i++ )
{
if ( entities[i]->m_formation >= 0)
{
CEntityFormation* formation = entities[i]->GetFormation();
bool duplicate = formation->IsDuplication();
if ( formation->IsLocked() && !duplicate)
{
formation->SelectAllUnits();
entityStore[entities[i]->m_formation] = formation->GetEntityList();
formation->SetDuplication(true);
}
}
else
msgEntities.push_back( entities[i] );
}
CNetMessage* msg = CNetMessage::CommandFromJSArgs(msgEntities, cx, argc-2, argv+2, isQueued);
if (!msg)
{
delete msg;
return JS_TRUE;
}
messages.push_back(msg);
for ( EntityStore::iterator it=entityStore.begin(); it!=entityStore.end(); it++)
CreateFormationMessage(messages, msg, it->second);
for ( std::vector<CNetMessage*>::iterator it=messages.begin(); it != messages.end(); it++ )
{
g_Console->InsertMessage(L"IssueCommand: %hs", (*it)->ToString().c_str());
*rval = g_ScriptingHost.UCStringToValue((*it)->ToString());
g_Game->GetSimulation()->QueueLocalCommand(*it);
}
return JS_TRUE;
}
// Get the state of a given hotkey (from the hotkeys file)
JSBool isOrderQueued( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
{
@ -1408,7 +1303,6 @@ JSFunctionSpec ScriptFunctionTable[] =
JS_FUNC("getEntityByUnitID", GetEntityByUnitID, 1)
JS_FUNC("GetPlayerUnitCount", GetPlayerUnitCount, 1)
JS_FUNC("getEntityTemplate", GetEntityTemplate, 1)
JS_FUNC("issueCommand", IssueCommand, 2)
JS_FUNC("startPlacing", StartPlacing, 1)
// Formation

View File

@ -181,8 +181,10 @@ void CEntityFormation::UpdateFormation()
}
}
CEntityList entities = GetEntityList();
/*
CNetMessage* msg = CNetMessage::CreatePositionMessage( entities, NMT_FORMATION_GOTO, m_position );
g_Game->GetSimulation()->QueueLocalCommand(msg);
*/
}

View File

@ -843,6 +843,7 @@ jsval_t CEntity::GetRallyPoint( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval
jsval_t CEntity::SetRallyPointAtCursor( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv) )
{
// Queue an order over the network to set a rally point
/*
CSetRallyPointMessage* msg = new CSetRallyPointMessage;
msg->m_Entities = CEntityList(me);
msg->m_IsQueued = true;
@ -850,6 +851,7 @@ jsval_t CEntity::SetRallyPointAtCursor( JSContext* UNUSED(cx), uintN UNUSED(argc
msg->m_TargetX = (int) point.X;
msg->m_TargetY = (int) point.Z;
g_Game->GetSimulation()->QueueLocalCommand(msg);
*/
return JS_TRUE;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* 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
@ -42,7 +42,6 @@
#include "simulation/Scheduler.h"
#include "simulation/Simulation.h"
#include "simulation/TerritoryManager.h"
#include "simulation/TurnManager.h"
#include "simulation/TriggerManager.h"
#define LOG_CATEGORY L"simulation"
@ -50,7 +49,6 @@
CSimulation::CSimulation(CGame *pGame):
m_pGame(pGame),
m_pWorld(pGame->GetWorld()),
m_pTurnManager((g_SinglePlayerTurnManager=new CSinglePlayerTurnManager())),
m_DeltaTime(0),
m_Time(0)
{
@ -58,16 +56,12 @@ CSimulation::CSimulation(CGame *pGame):
CSimulation::~CSimulation()
{
delete g_SinglePlayerTurnManager;
g_SinglePlayerTurnManager=NULL;
}
int CSimulation::Initialize(CGameAttributes* pAttribs)
{
m_Random.seed(0); // TODO: Store a random seed in CGameAttributes and synchronize it accross the network
m_pTurnManager->Initialize(m_pGame->GetNumPlayers());
// Call the game startup script
// TODO: Maybe don't do this if we're in Atlas
// [2006-06-26 20ms]
@ -93,42 +87,9 @@ void CSimulation::RegisterInit(CGameAttributes *pAttribs)
bool CSimulation::Update(double frameTime)
bool CSimulation::Update(double UNUSED(frameTime))
{
bool ok = true;
m_DeltaTime += frameTime;
if (m_DeltaTime >= 0.0)
{
// A new simulation frame is required.
if (m_pTurnManager->NewTurnReady())
{
PROFILE( "simulation turn" );
Simulate();
double turnLength = m_pTurnManager->GetTurnLength() / 1000.0;
m_DeltaTime -= turnLength;
if (m_DeltaTime >= 0.0)
{
// The desired sim frame rate can't be achieved - we're being called
// with average(frameTime) > turnLength.
// Let the caller know we can't go fast enough - they should try
// cutting down on Interpolate and rendering, and call us a few times
// with frameTime == 0 to give us a chance to catch up.
ok = false;
debug_printf(L"WARNING: missing a simulation turn due to low FPS\n");
}
}
else
{
// The network is lagging behind the simulation rate.
// Set delta time back to zero so we don't jump into the middle
// of the next simulation frame when we get the next turn.
// This creates "lag" on the client rather than just jumpiness.
m_DeltaTime = 0;
}
}
return ok;
}
@ -138,18 +99,8 @@ void CSimulation::DiscardMissedUpdates()
m_DeltaTime = 0.0;
}
void CSimulation::Interpolate(double frameTime)
void CSimulation::Interpolate(double UNUSED(frameTime))
{
double turnLength = m_pTurnManager->GetTurnLength()/1000.0;
// 'offset' should be how far we are between the previous and next
// simulation frames.
// m_DeltaTime/turnLength will usually be between -1 and 0, indicating
// the time until the next frame, so we can use that easily.
// If the simulation is going too slowly and hasn't been giving a chance
// to catch up before Interpolate is called, then m_DeltaTime > 0, so we'll
// just clamp it to offset=1, which is alright.
Interpolate(frameTime, clamp(m_DeltaTime / turnLength + 1.0, 0.0, 1.0));
}
void CSimulation::Interpolate(double frameTime, double offset)
@ -166,40 +117,6 @@ void CSimulation::Interpolate(double frameTime, double offset)
void CSimulation::Simulate()
{
int time = m_pTurnManager->GetTurnLength();
m_Time += time / 1000.0f;
#if defined(DEBUG_SYNCHRONIZATION)
debug_printf(L"Simulation turn: %.3lf\n", m_Time);
#endif
PROFILE_START( "scheduler tick" );
g_Scheduler.Update(time);
PROFILE_END( "scheduler tick" );
PROFILE_START( "entity updates" );
g_EntityManager.UpdateAll(time);
PROFILE_END( "entity updates" );
PROFILE_START( "projectile updates" );
m_pWorld->GetProjectileManager().UpdateAll(time);
PROFILE_END( "projectile updates" );
PROFILE_START( "los update" );
m_pWorld->GetLOSManager()->Update();
PROFILE_END( "los update" );
PROFILE_START("trigger update");
g_TriggerManager.Update(time);
PROFILE_END("trigger udpate");
PROFILE_START( "turn manager update" );
m_pTurnManager->NewTurn();
m_pTurnManager->IterateBatch(0, TranslateMessage, this);
PROFILE_END( "turn manager update" );
#if defined(DEBUG_SYNCHRONIZATION)
debug_printf(L"End turn\n", m_Time);
#endif
}
// Location randomizer, for group orders...
@ -299,159 +216,6 @@ void QueueOrder(const CEntityOrder& order, const std::vector<HEntity> &entities,
size_t CSimulation::TranslateMessage(CNetMessage* pMsg, size_t clientMask, void* UNUSED(userdata))
{
CEntityOrder order;
bool isQueued = true;
#define ENTITY_POSITION(_msg, _order) \
do { \
_msg *msg=(_msg *)pMsg; \
isQueued = msg->m_IsQueued != 0; \
order.m_type=CEntityOrder::_order; \
order.m_target_location.x=(float)msg->m_TargetX; \
order.m_target_location.y=(float)msg->m_TargetY; \
RandomizeLocations(order, msg->m_Entities, isQueued); \
} while(0)
#define ENTITY_POSITION_FORM(_msg, _order) \
do { \
_msg *msg=(_msg *)pMsg; \
isQueued = msg->m_IsQueued != 0; \
order.m_type=CEntityOrder::_order; \
order.m_target_location.x=(float)msg->m_TargetX; \
order.m_target_location.y=(float)msg->m_TargetY; \
FormationLocations(order, msg->m_Entities, isQueued); \
} while(0)
#define ENTITY_ENTITY_INT(_msg, _order) \
do { \
_msg *msg=(_msg *)pMsg; \
isQueued = msg->m_IsQueued != 0; \
order.m_type=CEntityOrder::_order; \
order.m_target_entity=msg->m_Target; \
order.m_action=msg->m_Action; \
QueueOrder(order, msg->m_Entities, isQueued); \
} while(0)
#define ENTITY_ENTITY_INT_BOOL(_msg, _order) \
do { \
_msg *msg=(_msg *)pMsg; \
isQueued = msg->m_IsQueued != 0; \
order.m_type=CEntityOrder::_order; \
order.m_target_entity=msg->m_Target; \
order.m_action=msg->m_Action; \
order.m_run=msg->m_Run != 0; \
QueueOrder(order, msg->m_Entities, isQueued); \
} while(0)
#define ENTITY_INT_STRING(_msg, _order) \
do { \
_msg *msg=(_msg *)pMsg; \
isQueued = msg->m_IsQueued != 0; \
order.m_type=CEntityOrder::_order; \
order.m_name=msg->m_Name; \
order.m_produce_type=msg->m_Type; \
QueueOrder(order, msg->m_Entities, isQueued); \
} while(0)
#define ENTITY_STRING(_msg, _order) \
do { \
_msg *msg=(_msg *)pMsg; \
isQueued = msg->m_IsQueued != 0; \
order.m_type=CEntityOrder::_order; \
order.m_name=msg->m_Stance; \
QueueOrder(order, msg->m_Entities, isQueued); \
} while(0)
switch (pMsg->GetType())
{
case NMT_ADD_WAYPOINT:
{
CAddWaypointMessage *msg=(CAddWaypointMessage *)pMsg;
isQueued = msg->m_IsQueued != 0;
order.m_type=CEntityOrder::ORDER_LAST;
order.m_target_location.x=(float)msg->m_TargetX;
order.m_target_location.y=(float)msg->m_TargetY;
for(CEntityIt it = msg->m_Entities.begin(); it != msg->m_Entities.end(); ++it)
{
HEntity& hentity = *it;
const CEntityOrders& order_queue = hentity->m_orderQueue;
for(CEntityOrderCRIt ord_it = order_queue.rbegin(); ord_it != order_queue.rend(); ++ord_it)
{
if (ord_it->m_type == CEntityOrder::ORDER_PATH_END_MARKER)
{
order.m_type = CEntityOrder::ORDER_GOTO;
hentity->PushOrder(order);
break;
}
if (ord_it->m_type == CEntityOrder::ORDER_PATROL)
{
order.m_type = ord_it->m_type;
hentity->PushOrder(order);
break;
}
}
if (order.m_type == CEntityOrder::ORDER_LAST)
{
LOG(CLogger::Error, LOG_CATEGORY, L"Got an AddWaypoint message for an entity that isn't moving.");
}
}
break;
}
case NMT_GOTO:
ENTITY_POSITION(CGotoMessage, ORDER_GOTO);
break;
case NMT_RUN:
ENTITY_POSITION(CRunMessage, ORDER_RUN);
break;
case NMT_PATROL:
ENTITY_POSITION(CPatrolMessage, ORDER_PATROL);
break;
case NMT_SET_RALLY_POINT:
ENTITY_POSITION(CSetRallyPointMessage, ORDER_SET_RALLY_POINT);
break;
case NMT_SET_STANCE:
ENTITY_STRING(CSetStanceMessage, ORDER_SET_STANCE);
break;
case NMT_FORMATION_GOTO:
ENTITY_POSITION_FORM(CFormationGotoMessage, ORDER_GOTO);
break;
//TODO: make formation move to within range of target and then attack normally
case NMT_CONTACT_ACTION:
ENTITY_ENTITY_INT_BOOL(CContactActionMessage, ORDER_CONTACT_ACTION);
break;
case NMT_FORMATION_CONTACT_ACTION:
ENTITY_ENTITY_INT(CFormationContactActionMessage, ORDER_CONTACT_ACTION);
break;
case NMT_NOTIFY_REQUEST:
ENTITY_ENTITY_INT(CNotifyRequestMessage, ORDER_NOTIFY_REQUEST);
break;
case NMT_PRODUCE:
ENTITY_INT_STRING(CProduceMessage, ORDER_PRODUCE);
break;
case NMT_PLACE_OBJECT:
{
CPlaceObjectMessage *msg = (CPlaceObjectMessage *) pMsg;
isQueued = msg->m_IsQueued != 0;
// Figure out the player
CPlayer* player = 0;
if(msg->m_Entities.size() > 0)
player = msg->m_Entities[0]->GetPlayer();
else
player = g_Game->GetLocalPlayer();
// Create the object
CVector3D pos(msg->m_X/1000.0f, msg->m_Y/1000.0f, msg->m_Z/1000.0f);
HEntity newObj = g_EntityManager.CreateFoundation( msg->m_Template, player, pos, msg->m_Angle/1000.0f );
newObj->m_actor->SetPlayerID(player->GetPlayerID());
if( newObj->Initialize() )
{
// Order all the selected units to work on the new object using the given action
order.m_type = CEntityOrder::ORDER_START_CONSTRUCTION;
order.m_new_obj = newObj;
QueueOrder(order, msg->m_Entities, isQueued);
}
}
break;
}
return clientMask;
}
@ -466,7 +230,6 @@ size_t CSimulation::GetMessageMask(CNetMessage* UNUSED(pMsg), size_t UNUSED(oldM
void CSimulation::QueueLocalCommand(CNetMessage *pMsg)
{
m_pTurnManager->QueueLocalCommand(pMsg);
}

View File

@ -23,14 +23,12 @@
class CGame;
class CGameAttributes;
class CWorld;
class CTurnManager;
class CNetMessage;
class CSimulation
{
CGame *m_pGame;
CWorld *m_pWorld;
CTurnManager *m_pTurnManager;
// Current game time; store as double for precision
double m_Time;
@ -51,11 +49,6 @@ public:
CSimulation(CGame *pGame);
~CSimulation();
inline void SetTurnManager(CTurnManager *pTurnManager)
{ m_pTurnManager=pTurnManager; }
inline CTurnManager *GetTurnManager()
{ return m_pTurnManager; }
void RegisterInit(CGameAttributes *pGameAttributes);
int Initialize(CGameAttributes *pGameAttributes);

View File

@ -1,168 +0,0 @@
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "TurnManager.h"
#include "network/NetMessage.h"
#include "network/Network.h"
#include "ps/GameRecord.h"
#include "ps/CLogger.h"
#include <vector>
CSinglePlayerTurnManager *g_SinglePlayerTurnManager=NULL;
CTurnManager::CTurnManager()
{
for (int i=0; i<3; i++)
m_Batches[i].m_TurnLength = DEFAULT_TURN_LENGTH;
}
void CTurnManager::ClearBatch(uintptr_t batch)
{
typedef std::vector<SMessageSyncEntry> MsgVector;
MsgVector &messages=m_Batches[batch].m_Messages;
MsgVector::iterator it=messages.begin();
while (it != messages.end())
{
delete it->m_pMessage;
++it;
}
messages.clear();
}
void CTurnManager::SBatch::Swap(SBatch &other)
{
std::swap(m_Messages, other.m_Messages);
std::swap(m_TurnLength, other.m_TurnLength);
}
void CTurnManager::RotateBatches()
{
// {a, b, c} => {b, c, a}:
// {a, b, c}
// -- swap (0, 1)
// {b, a, c}
// -- swap (1, 2)
// {b, c, a}
m_Batches[0].Swap(m_Batches[1]);
m_Batches[1].Swap(m_Batches[2]);
}
void CTurnManager::IterateBatch(uintptr_t batch, BatchIteratorFunc *fp, void *userdata)
{
typedef std::vector<SMessageSyncEntry> MsgVector;
MsgVector &messages=m_Batches[batch].m_Messages;
MsgVector::iterator it=messages.begin();
while (it != messages.end())
{
it->m_ClientMask=(*fp)(it->m_pMessage, it->m_ClientMask, userdata);
++it;
}
}
void CTurnManager::SendBatch(uintptr_t batch)
{
typedef std::vector<SMessageSyncEntry> MsgVector;
MsgVector &messages=m_Batches[batch].m_Messages;
MsgVector::iterator it=messages.begin();
while (it != messages.end())
{
SendMessageMasked(it->m_pMessage, it->m_ClientMask);
++it;
}
CEndCommandBatchMessage *pMsg=new CEndCommandBatchMessage();
pMsg->m_TurnLength=m_Batches[batch].m_TurnLength;
SendMessageMasked(pMsg, (size_t)-1);
}
void CTurnManager::SendMessageMasked(CNetMessage *pMsg, size_t clientMask)
{
for (size_t i=0;i<m_Clients.size();i++)
{
if (clientMask & (1<<i))
{
if (m_Clients[i].m_Pipe)
m_Clients[i].m_Pipe->Push(pMsg);
}
}
}
void CTurnManager::QueueMessage(uintptr_t batch, CNetMessage *pMsg)
{
m_Batches[batch].m_Messages.push_back(SMessageSyncEntry(pMsg));
}
void CTurnManager::SetClientPipe(size_t client, IMessagePipeEnd *pipe)
{
m_Clients[client].m_Pipe=pipe;
}
void CTurnManager::SetTurnLength(uintptr_t batch, int turnLength)
{
m_Batches[batch].m_TurnLength=turnLength;
}
int CTurnManager::GetTurnLength()
{
return m_Batches[0].m_TurnLength;
}
void CTurnManager::Initialize(size_t numClients)
{
m_Clients.resize(numClients);
}
void CTurnManager::RecordBatch(uintptr_t batch)
{
IterateBatch(batch, RecordIterator, m_pRecord);
CEndCommandBatchMessage msg;
m_pRecord->WriteMessage(&msg);
}
size_t CTurnManager::RecordIterator(CNetMessage *pMsg, uintptr_t clientMask, void *userdata)
{
CGameRecord *pRecord=(CGameRecord *)userdata;
pRecord->WriteMessage(pMsg);
return clientMask;
}
CSinglePlayerTurnManager::CSinglePlayerTurnManager()
{}
void CSinglePlayerTurnManager::NewTurn()
{
RecordBatch(2);
RotateBatches();
ClearBatch(2);
}
void CSinglePlayerTurnManager::QueueLocalCommand(CNetMessage *pMsg)
{
QueueMessage(2, pMsg);
}
bool CSinglePlayerTurnManager::NewTurnReady()
{
return true;
}

View File

@ -1,146 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_TURNMANAGER
#define INCLUDED_TURNMANAGER
//#include "Network/NetMessage.h"
//#include "Network/Network.h"
#include <vector>
class CGameRecord;
class CNetMessage;
class IMessagePipeEnd;
class CTurnManager
{
public:
// Default turn length
static const int DEFAULT_TURN_LENGTH = 300;
// Used with IterateBatch() to iterate a command batch and set the sync mask
// for each message. If the iterating function doesn't wish to change the
// mask, it should return oldMask unchanged.
typedef uintptr_t (BatchIteratorFunc)(CNetMessage *pMsg, uintptr_t oldMask, void *userdata);
// FIXME Should be in CNetServer instead
struct SClientTimingData
{
// The maximum latency observed from this client
int m_MaxLatency;
// Approximate current round-trip time in milliseconds
int m_Latency;
// Frames per Second - won't be used unless 1000/m_FPS > m_Latency (i.e.
// framerate is too slow to handle [m_Latency] as the turn length)
int m_FPS;
};
private:
struct SMessageSyncEntry
{
// A bitmask telling which clients to sync this message to
uintptr_t m_ClientMask;
// The message pointer
CNetMessage *m_pMessage;
inline SMessageSyncEntry(CNetMessage *pMsg):
m_ClientMask(0),
m_pMessage(pMsg)
{}
};
struct SBatch
{
std::vector <SMessageSyncEntry> m_Messages;
int m_TurnLength;
void Swap(SBatch &other);
};
struct SClient
{
// FIXME Move to CNetServer
SClientTimingData m_TimingData;
IMessagePipeEnd *m_Pipe;
};
std::vector <SClient> m_Clients;
SBatch m_Batches[3];
CGameRecord *m_pRecord;
public:
// Rotate the three batches: {0, 1, 2} => {1, 2, 0}
void RotateBatches();
// Go through each message in the specified batch and send the message to
// each of the clients whose bit in the message's mask is set
void SendBatch(uintptr_t batch);
void ClearBatch(uintptr_t batch);
void SetClientPipe(size_t client, IMessagePipeEnd *pipe);
// FIXME Should be in CNetServer instead [and implemented]
// void UpdateTimingData(size_t client, int fps, int currentLatency);
void SetTurnLength(uintptr_t batch, int turnLength);
void SendMessageMasked(CNetMessage *pMsg, uintptr_t clientMask);
// Add the message to the specified batch. The message is assumed to be
// validated before passed here, and will be blindly trusted.
void QueueMessage(uintptr_t batch, CNetMessage *pMsg);
// Send the specified batch to CGameRecord for recording
void RecordBatch(uintptr_t batch);
static BatchIteratorFunc RecordIterator;
public:
CTurnManager();
virtual ~CTurnManager() { }
void Initialize(size_t numClients);
// Return the millisecond delay between the last frame and the next.
// CSimulation will use this to determine when to perform the deterministic
// update and call NewTurn()
int GetTurnLength();
// Called by CSimulation when the current turn time has passed.
virtual void NewTurn() = 0;
// Used by CSimulation to ask whether it can call NewTurn.
virtual bool NewTurnReady() = 0;
// Apply a function to all messages in a given batch.
void IterateBatch(uintptr_t batch, BatchIteratorFunc *func, void *userdata);
// Queue a command originating from the local player.
virtual void QueueLocalCommand(CNetMessage *pMsg) = 0;
};
class CSinglePlayerTurnManager: public CTurnManager
{
public:
CSinglePlayerTurnManager();
virtual void NewTurn();
virtual void QueueLocalCommand(CNetMessage *pMsg);
virtual bool NewTurnReady();
};
extern CSinglePlayerTurnManager *g_SinglePlayerTurnManager;
#endif