1
0
forked from 0ad/0ad
0ad/source/ps/Network/NetMessage.cpp
pyrolink 3408b078b7 #Unit formations and rank textures
-Added functionality for "casting" and creating net messages (without
JS)
-Rank textures-specified in XML
-Formations-currently don't attack correctly (i.e. travel like mobs) and
don't switch to their movement formations when tasked to go somewhere
(the pathfinder doesn't give any heads up about destination reached, so
there's no way to change back to the original).  Also, base switching is
untested so no garuntees for next and prior formation things.

This was SVN commit r3710.
2006-03-31 03:30:34 +00:00

354 lines
8.0 KiB
C++
Executable File

#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;
}
}