mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-17 05:44:08 -07:00
- The server will no longer send a new turn until the previous one has been "acknowledged". (TODO: this may create lag between turns in its current form; investigate and possibly allow executing two turns while the third is being negotiated). - Mutexes are now being used in NetServer and NetClient to ensure commands go into the right batches. - Commented out some orders in the GUI code that should not be there and are not 100% working anyway (they were part of the follow/formation system). - Units that spawn or are created by scripts now have net-safe position and orientation. - Added a debug flag that can be turned on to print details about when commands are received and executed (DEBUG_SYNCHRONIZATION). This is especially useful if you diff the stdouts of two running games. There should be no differences if everything is in synch. This was SVN commit r5463.
218 lines
5.8 KiB
C++
218 lines
5.8 KiB
C++
#include "precompiled.h"
|
|
|
|
#include "ServerSession.h"
|
|
#include "Server.h"
|
|
#include "ps/CLogger.h"
|
|
#include "ps/CConsole.h"
|
|
|
|
CNetServerSession::CNetServerSession(CNetServer *pServer, CSocketInternal *pInt,
|
|
MessageHandler *pMsgHandler):
|
|
CNetSession(pInt, pMsgHandler),
|
|
m_pServer(pServer),
|
|
m_pPlayer(NULL),
|
|
m_pPlayerSlot(NULL),
|
|
m_IsObserver(false),
|
|
m_ID(-1),
|
|
m_ReadyForTurn(false)
|
|
{
|
|
ONCE(
|
|
ScriptingInit();
|
|
);
|
|
}
|
|
|
|
CNetServerSession::~CNetServerSession()
|
|
{
|
|
}
|
|
|
|
void CNetServerSession::StartGame()
|
|
{
|
|
if (m_pMessageHandler==PreGameHandler)
|
|
m_pMessageHandler=InGameHandler;
|
|
}
|
|
|
|
#define UNHANDLED(_pMsg) return false;
|
|
#define HANDLED(_pMsg) delete _pMsg; return true;
|
|
#define TAKEN(_pMsg) return true;
|
|
|
|
bool CNetServerSession::BaseHandler(CNetMessage *pMsg, CNetSession *pNetSession)
|
|
{
|
|
CNetServerSession *pSession=(CNetServerSession *)pNetSession;
|
|
switch (pMsg->GetType())
|
|
{
|
|
case NMT_ERROR:
|
|
{
|
|
CNetErrorMessage *msg=(CNetErrorMessage *)pMsg;
|
|
if (msg->m_State == SS_UNCONNECTED)
|
|
{
|
|
if (pSession->m_ID != -1)
|
|
pSession->m_pServer->RemoveSession(pSession);
|
|
delete pSession;
|
|
}
|
|
else // error, but not disconnected? something weird is up...
|
|
LOG(WARNING, LOG_CAT_NET, "CNetServerSession::BaseHandler(): NMT_ERROR: %s", msg->GetString().c_str());
|
|
HANDLED(pMsg);
|
|
}
|
|
|
|
default:
|
|
UNHANDLED(pMsg);
|
|
}
|
|
}
|
|
|
|
bool CNetServerSession::HandshakeHandler(CNetMessage *pMsg, CNetSession *pNetSession)
|
|
{
|
|
CNetServerSession *pSession=(CNetServerSession *)pNetSession;
|
|
LOG(NORMAL, LOG_CAT_NET, "CNetServerSession::HandshakeHandler(): %s.", pMsg->GetString().c_str());
|
|
switch (pMsg->GetType())
|
|
{
|
|
case NMT_ClientHandshake:
|
|
{
|
|
CClientHandshake *msg=(CClientHandshake *)pMsg;
|
|
|
|
if (msg->m_ProtocolVersion != PS_PROTOCOL_VERSION)
|
|
{
|
|
pSession->Push(new CCloseRequestMessage());
|
|
BaseHandler(new CNetErrorMessage(PS_OK, SS_UNCONNECTED), pSession);
|
|
}
|
|
|
|
CServerHandshakeResponse *retmsg=new CServerHandshakeResponse();
|
|
retmsg->m_UseProtocolVersion=PS_PROTOCOL_VERSION;
|
|
retmsg->m_Flags=0;
|
|
retmsg->m_Message=pSession->m_pServer->m_WelcomeMessage;
|
|
pSession->Push(retmsg);
|
|
|
|
pSession->m_pMessageHandler=AuthenticateHandler;
|
|
|
|
HANDLED(pMsg);
|
|
}
|
|
|
|
default:
|
|
return BaseHandler(pMsg, pNetSession);
|
|
}
|
|
}
|
|
|
|
bool CNetServerSession::AuthenticateHandler(CNetMessage *pMsg, CNetSession *pNetSession)
|
|
{
|
|
CNetServerSession *pSession=(CNetServerSession *)pNetSession;
|
|
CNetServer *pServer=pSession->m_pServer;
|
|
LOG(NORMAL, LOG_CAT_NET, "CNetServerSession::AuthenticateHandler(): %s.", pMsg->GetString().c_str());
|
|
if (pMsg->GetType() == NMT_Authenticate)
|
|
{
|
|
CAuthenticate *msg=(CAuthenticate *)pMsg;
|
|
|
|
if (msg->m_Password == pSession->m_pServer->m_Password)
|
|
{
|
|
LOG(NORMAL, LOG_CAT_NET, "CNetServerSession::AuthenticateHandler(): Login Successful");
|
|
pSession->m_Name=msg->m_Name;
|
|
|
|
pServer->AssignSessionID(pSession);
|
|
|
|
CAuthenticationResult *msg=new CAuthenticationResult();
|
|
msg->m_Code=NRC_OK;
|
|
msg->m_SessionID=pSession->m_ID;
|
|
msg->m_Message=L"Logged in";
|
|
pSession->Push(msg);
|
|
|
|
pServer->AddSession(pSession);
|
|
if (pServer->GetServerState() == NSS_PreGame)
|
|
{
|
|
pSession->m_pMessageHandler=PreGameHandler;
|
|
}
|
|
else // We're not in pre-game. The session becomes a chatter/observer here.
|
|
{
|
|
pSession->m_pMessageHandler=ObserverHandler;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG(WARNING, LOG_CAT_NET, "CNetServerSession::AuthenticateHandler(): Login Failed");
|
|
CAuthenticationResult *msg=new CAuthenticationResult();
|
|
msg->m_Code=NRC_PasswordInvalid;
|
|
msg->m_SessionID=0;
|
|
msg->m_Message=L"Invalid Password";
|
|
pSession->Push(msg);
|
|
}
|
|
|
|
HANDLED(pMsg);
|
|
}
|
|
return BaseHandler(pMsg, pNetSession);
|
|
}
|
|
|
|
bool CNetServerSession::PreGameHandler(CNetMessage *pMsg, CNetSession *pNetSession)
|
|
{
|
|
return ChatHandler(pMsg, pNetSession);
|
|
}
|
|
|
|
bool CNetServerSession::ObserverHandler(CNetMessage *pMsg, CNetSession *pNetSession)
|
|
{
|
|
printf("CNetServerSession::ObserverHandler(): %s.\n", pMsg->GetString().c_str());
|
|
|
|
// TODO Implement observers and chatter => observer promotion
|
|
/*
|
|
if (pMsg->GetType() == NMT_RequestObserve)
|
|
*/
|
|
|
|
return ChatHandler(pMsg, pNetSession);
|
|
}
|
|
|
|
bool CNetServerSession::ChatHandler(CNetMessage *pMsg, CNetSession *pNetSession)
|
|
{
|
|
CNetServerSession *pSession=(CNetServerSession *)pNetSession;
|
|
if (pMsg->GetType() == NMT_ChatMessage)
|
|
{
|
|
CChatMessage *msg=(CChatMessage *)pMsg;
|
|
msg->m_Sender=pSession->m_Name;
|
|
g_Console->ReceivedChatMessage(pSession->GetName().c_str(), msg->m_Message.c_str());
|
|
pSession->m_pServer->OnChat(msg->m_Sender, msg->m_Message);
|
|
pSession->m_pServer->Broadcast(msg);
|
|
|
|
TAKEN(pMsg);
|
|
}
|
|
|
|
return BaseHandler(pMsg, pNetSession);
|
|
}
|
|
|
|
bool CNetServerSession::InGameHandler(CNetMessage *pMsg, CNetSession *pNetSession)
|
|
{
|
|
CNetServerSession *pSession=(CNetServerSession *)pNetSession;
|
|
if (pMsg->GetType() != NMT_EndCommandBatch)
|
|
LOG(NORMAL, LOG_CAT_NET, "CNetServerSession::InGameHandler(): %s.", pMsg->GetString().c_str());
|
|
|
|
if (BaseHandler(pMsg, pNetSession))
|
|
return true;
|
|
|
|
if (ChatHandler(pMsg, pNetSession))
|
|
return true;
|
|
|
|
if (pMsg->GetType() >= NMT_COMMAND_FIRST && pMsg->GetType() < NMT_COMMAND_LAST)
|
|
{
|
|
// All Command Messages (i.e. simulation turn synchronized messages)
|
|
//pSession->m_pPlayer->ValidateCommand(pMsg);
|
|
pSession->m_pServer->QueueIncomingCommand(pMsg);
|
|
TAKEN(pMsg);
|
|
}
|
|
|
|
switch (pMsg->GetType())
|
|
{
|
|
case NMT_EndCommandBatch:
|
|
pSession->m_ReadyForTurn = true;
|
|
HANDLED(pMsg);
|
|
|
|
default:
|
|
UNHANDLED(pMsg);
|
|
}
|
|
}
|
|
|
|
void CNetServerSession::ScriptingInit()
|
|
{
|
|
AddMethod<bool, &CNetServerSession::JSI_Close>("close", 0);
|
|
|
|
CJSObject<CNetServerSession>::ScriptingInit("NetSession");
|
|
// Hope this doesn't break anything...
|
|
AddProperty( L"id", &CNetServerSession::m_ID );
|
|
AddProperty( L"name", (CStrW CNetServerSession::*)&CNetServerSession::m_Name );
|
|
}
|
|
|
|
bool CNetServerSession::JSI_Close(JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(argv))
|
|
{
|
|
return false;
|
|
}
|