forked from 0ad/0ad
354 lines
8.0 KiB
C++
354 lines
8.0 KiB
C++
#include "precompiled.h"
|
|
|
|
#include "posix.h"
|
|
#include "lib.h"
|
|
#include <stdio.h>
|
|
#include <map>
|
|
|
|
#include "Entity.h"
|
|
#include "Vector2D.h"
|
|
#define ALLNETMSGS_IMPLEMENT
|
|
|
|
#include "NetMessage.h"
|
|
|
|
#include "CLogger.h"
|
|
|
|
#define LOG_CAT_NET "net"
|
|
|
|
// NEVER modify the deserializer map outside the ONCE-block in DeserializeMessage
|
|
typedef std::map <ENetMessageType, NetMessageDeserializer> MessageDeserializerMap;
|
|
MessageDeserializerMap g_DeserializerMap;
|
|
|
|
CNetMessage::~CNetMessage()
|
|
{
|
|
m_Type=NMT_NONE;
|
|
}
|
|
|
|
u8 *CNetMessage::Serialize(u8 *pos) const
|
|
{ return pos; }
|
|
|
|
uint CNetMessage::GetSerializedLength() const
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
CStr CNetMessage::GetString() const
|
|
{
|
|
if (m_Type==NMT_NONE)
|
|
return "NMT_NONE { Invalid Message }";
|
|
else
|
|
return CStr("Unknown Message ")+CStr(m_Type);
|
|
}
|
|
|
|
const u8 *CNetMessage::Deserialize(const u8* pos, const u8* UNUSED(end))
|
|
{
|
|
return pos;
|
|
}
|
|
|
|
CNetMessage *CNetMessage::Copy() const
|
|
{
|
|
LOG(ERROR, LOG_CAT_NET, "CNetMessage::Copy(): Attempting to copy non-copyable message!");
|
|
return new CNetMessage(NMT_NONE);
|
|
}
|
|
|
|
CNetMessage *CNetMessage::DeserializeMessage(ENetMessageType type, u8 *buffer, uint length)
|
|
{
|
|
{
|
|
ONCE(
|
|
SNetMessageDeserializerRegistration *pReg=&g_DeserializerRegistrations[0];
|
|
for (;pReg->m_pDeserializer;pReg++)
|
|
{
|
|
g_DeserializerMap.insert(std::make_pair(pReg->m_Type, pReg->m_pDeserializer));
|
|
}
|
|
);
|
|
}
|
|
|
|
MessageDeserializerMap::const_iterator dEntry=g_DeserializerMap.find(type);
|
|
if (dEntry == g_DeserializerMap.end())
|
|
{
|
|
LOG(WARNING, LOG_CAT_NET, "Unknown message received on socket: type 0x%04x, length %u", type, length);
|
|
return NULL;
|
|
}
|
|
NetMessageDeserializer pDes=dEntry->second;
|
|
return (pDes)(buffer, length);
|
|
}
|
|
|
|
void CNetMessage::ScriptingInit()
|
|
{
|
|
#define def(_msg) g_ScriptingHost.DefineConstant(#_msg, _msg)
|
|
|
|
def(NMT_Goto);
|
|
def(NMT_Run);
|
|
def(NMT_Patrol);
|
|
def(NMT_AddWaypoint);
|
|
def(NMT_Generic);
|
|
def(NMT_Produce);
|
|
def(NMT_NotifyRequest);
|
|
def(NMT_FormationGoto);
|
|
def(NMT_FormationGeneric);
|
|
}
|
|
|
|
CNetCommand *CNetMessage::CommandFromJSArgs(const CEntityList &entities, JSContext *cx, uintN argc, jsval *argv)
|
|
{
|
|
debug_assert(argc >= 1);
|
|
|
|
int msgType;
|
|
|
|
try
|
|
{
|
|
msgType = ToPrimitive<int>( argv[0] );
|
|
}
|
|
catch(PSERROR_Scripting_ConversionFailed)
|
|
{
|
|
JS_ReportError(cx, "Invalid order type");
|
|
return NULL;
|
|
}
|
|
|
|
#define ArgumentCountError() STMT(\
|
|
JS_ReportError(cx, "Too few parameters!"); \
|
|
return NULL; )
|
|
#define ArgumentTypeError() STMT(\
|
|
JS_ReportError(cx, "Parameter type error!"); \
|
|
return NULL; )
|
|
#define ReadPosition(_msg, _field) \
|
|
try { \
|
|
if (argIndex+2 > argc) \
|
|
ArgumentCountError();\
|
|
if (!JSVAL_IS_INT(argv[argIndex]) || !JSVAL_IS_INT(argv[argIndex+1])) \
|
|
ArgumentTypeError(); \
|
|
_msg->_field ## X = ToPrimitive<int>(argv[argIndex++]); \
|
|
_msg->_field ## Y = ToPrimitive<int>(argv[argIndex++]); \
|
|
} catch (PSERROR_Scripting_ConversionFailed) { \
|
|
JS_ReportError(cx, "Invalid location"); \
|
|
return NULL; \
|
|
}
|
|
#define ReadEntity(_msg, _field) \
|
|
STMT(\
|
|
if (argIndex+1 > argc) \
|
|
ArgumentCountError(); \
|
|
if (!JSVAL_IS_OBJECT(argv[argIndex])) \
|
|
ArgumentTypeError(); \
|
|
CEntity *ent=ToNative<CEntity>(argv[argIndex++]); \
|
|
if (!ent) \
|
|
{ \
|
|
JS_ReportError(cx, "Invalid entity parameter"); \
|
|
return NULL; \
|
|
} \
|
|
_msg->_field=ent->me; \
|
|
)
|
|
#define ReadInt(_msg, _field) \
|
|
STMT(\
|
|
if (argIndex+1 > argc) \
|
|
ArgumentCountError(); \
|
|
if (!JSVAL_IS_INT(argv[argIndex])) \
|
|
ArgumentTypeError(); \
|
|
int val=ToPrimitive<int>(argv[argIndex++]); \
|
|
_msg->_field=val; \
|
|
)
|
|
#define ReadString(_msg, _field) \
|
|
STMT(\
|
|
if (argIndex+1 > argc) \
|
|
ArgumentCountError(); \
|
|
if (!JSVAL_IS_STRING(argv[argIndex])) \
|
|
ArgumentTypeError(); \
|
|
CStrW val=ToPrimitive<CStrW>(argv[argIndex++]); \
|
|
_msg->_field=val; \
|
|
)
|
|
|
|
#define PositionMessage(_msg) \
|
|
case NMT_ ## _msg: \
|
|
{ \
|
|
C##_msg *msg = new C##_msg(); \
|
|
msg->m_Entities = entities; \
|
|
ReadPosition(msg, m_Target); \
|
|
return msg; \
|
|
}
|
|
|
|
#define EntityMessage(_msg) \
|
|
case NMT_ ## _msg: \
|
|
{ \
|
|
C##_msg *msg = new C##_msg(); \
|
|
msg->m_Entities = entities; \
|
|
ReadEntity(msg, m_Target); \
|
|
return msg; \
|
|
}
|
|
|
|
#define EntityIntMessage(_msg) \
|
|
case NMT_ ## _msg: \
|
|
{ \
|
|
C##_msg *msg = new C##_msg(); \
|
|
msg->m_Entities = entities; \
|
|
ReadEntity(msg, m_Target); \
|
|
ReadInt(msg, m_Action); \
|
|
return msg; \
|
|
}
|
|
|
|
#define ProduceMessage(_msg) \
|
|
case NMT_ ## _msg: \
|
|
{ \
|
|
C##_msg *msg = new C##_msg(); \
|
|
msg->m_Entities = entities; \
|
|
ReadInt(msg, m_Type); \
|
|
ReadString(msg, m_Name); \
|
|
return msg; \
|
|
}
|
|
|
|
// argIndex, incremented by reading macros. We have already "eaten" the
|
|
// first argument (message type)
|
|
uint argIndex = 1;
|
|
switch (msgType)
|
|
{
|
|
// NMT_Goto, targetX, targetY
|
|
PositionMessage(Goto)
|
|
PositionMessage(Run)
|
|
PositionMessage(Patrol)
|
|
PositionMessage(AddWaypoint)
|
|
PositionMessage(FormationGoto)
|
|
// NMT_Generic, target, action
|
|
EntityIntMessage(Generic)
|
|
EntityIntMessage(NotifyRequest)
|
|
EntityIntMessage(FormationGeneric)
|
|
|
|
|
|
// NMT_Produce, type, name
|
|
ProduceMessage(Produce)
|
|
|
|
default:
|
|
JS_ReportError(cx, "Invalid order type");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
CNetCommand *CNetMessage::CastCommand(CNetMessage*& message, const CEntityList& entities, const ENetMessageType type)
|
|
{
|
|
#define CopyPositionMessage(_msg) \
|
|
case NMT_ ## _msg: \
|
|
{ \
|
|
C##_msg *msg = new C##_msg(); \
|
|
C##_msg *castmsg = static_cast<C##_msg*>(message); \
|
|
msg->m_TargetX = castmsg->m_TargetX; \
|
|
msg->m_TargetY = castmsg->m_TargetY; \
|
|
msg->m_Entities = entities; \
|
|
return msg; \
|
|
}
|
|
|
|
#define CopyEntityMessage(_msg) \
|
|
case NMT_ ## _msg: \
|
|
{ \
|
|
C##_msg *msg = new C##_msg(); \
|
|
C##_msg *castmsg = static_cast<C##_msg*>(message); \
|
|
msg->m_Entities = entities; \
|
|
msg->m_Target = castmsg->Target; \
|
|
return msg; \
|
|
}
|
|
|
|
#define CopyEntityIntMessage(_msg) \
|
|
case NMT_ ## _msg: \
|
|
{ \
|
|
C##_msg *msg = new C##_msg(); \
|
|
C##_msg *castmsg = static_cast<C##_msg*>(message); \
|
|
msg->m_Entities = entities; \
|
|
msg->m_Target = castmsg->m_Target; \
|
|
msg->m_Action = castmsg->m_Action; \
|
|
return msg; \
|
|
}
|
|
|
|
#define CopyProduceMessage(_msg) \
|
|
case NMT_ ## _msg: \
|
|
{ \
|
|
C##_msg *msg = new C##_msg(); \
|
|
C##_msg *castmsg = static_cast<C##_msg*>(message); \
|
|
msg->m_Entities = entities; \
|
|
msg->m_Name = castmsg->m_Name; \
|
|
msg->m_Type = castmsg->m_Type; \
|
|
return msg; \
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
CopyPositionMessage(Goto)
|
|
CopyPositionMessage(Run)
|
|
CopyPositionMessage(Patrol)
|
|
CopyPositionMessage(AddWaypoint)
|
|
CopyPositionMessage(FormationGoto)
|
|
|
|
CopyEntityIntMessage(Generic)
|
|
CopyEntityIntMessage(NotifyRequest)
|
|
CopyEntityIntMessage(FormationGeneric)
|
|
|
|
CopyProduceMessage(Produce)
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
CNetMessage *CNetMessage::CreatePositionMessage( const CEntityList& entities, const ENetMessageType type, CVector2D pos )
|
|
{
|
|
#define PosMessage(_msg) \
|
|
case NMT_ ## _msg: \
|
|
{ \
|
|
C##_msg* msg = new C##_msg(); \
|
|
msg->m_Entities = entities; \
|
|
msg->m_TargetX = pos.x; \
|
|
msg->m_TargetY = pos.y; \
|
|
return msg; \
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
PosMessage(Goto)
|
|
PosMessage(Run)
|
|
PosMessage(Patrol)
|
|
PosMessage(AddWaypoint)
|
|
PosMessage(FormationGoto)
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
CNetMessage *CNetMessage::CreateEntityIntMessage( const CEntityList& entities, const ENetMessageType type, HEntity& target, int action )
|
|
{
|
|
#define EntMessage(_msg) \
|
|
case NMT_ ## _msg: \
|
|
{ \
|
|
C##_msg* msg = new C##_msg(); \
|
|
msg->m_Entities = entities; \
|
|
msg->m_Target = target; \
|
|
msg->m_Action = action; \
|
|
return msg; \
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
EntMessage(Generic)
|
|
EntMessage(NotifyRequest)
|
|
EntMessage(FormationGeneric)
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
CNetMessage *CNetMessage::CreateProduceMessage( const CEntityList& entities, const ENetMessageType type, int proType, CStrW name )
|
|
{
|
|
#define ProMessage(_msg)\
|
|
case NMT_ ## _msg: \
|
|
{ \
|
|
C##_msg* msg = new C##_msg(); \
|
|
msg->m_Entities = entities; \
|
|
msg->m_Type = proType; \
|
|
msg->m_Name = name; \
|
|
return msg; \
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
ProMessage(Produce)
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|