# 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:
parent
08e383235b
commit
a78e6dbe26
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,18 +84,11 @@ 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,39 +489,14 @@ 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.
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -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->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 );
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,19 +370,8 @@ 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() );
|
||||
}
|
||||
}
|
||||
|
||||
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,25 +514,11 @@ 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 );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -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() );
|
||||
|
||||
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_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:
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}*/
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
return CStr("NetErrorMessage: ") + m_Error;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
CStr CCloseRequestMessage::ToString() 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
|
||||
|
@ -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
|
||||
{
|
||||
public:
|
||||
PS_RESULT m_Error;
|
||||
ESocketState m_State;
|
||||
|
||||
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
|
||||
{
|
||||
inline CCloseRequestMessage(): CNetMessage(NMT_CLOSE_REQUEST)
|
||||
{}
|
||||
inline CCloseRequestMessage() :
|
||||
CNetMessage(NMT_CLOSE_REQUEST)
|
||||
{
|
||||
}
|
||||
|
||||
virtual CStr ToString() const;
|
||||
};
|
||||
|
||||
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
|
||||
|
@ -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
|
@ -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
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
@ -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
|
||||
|
@ -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))
|
||||
{
|
||||
}
|
@ -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
|
@ -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");
|
||||
|
@ -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] )
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
Loading…
Reference in New Issue
Block a user