Oliver Schroeder:
I have prepared a new patch for multiplayer, which fixes endianess issues with multiplayer code. It's basically identical to the patch I sent before my vacation, but contains minor fixes. Multiplayer should now be working under all unix-like environments and windows native. The basic trick is to let configure check for endianess of the host system. It will not work on system not using configure in the build process (excluding windows), ie. possibly MACOS. For those system we should provide #ifdefs in tiny_xdr.hpp. Erik: I've updated the patch to use the Plib utils package for endian swapping an used a preprocessor directive to detect endianess.
This commit is contained in:
parent
dcbc6369ac
commit
7311d05c87
7 changed files with 506 additions and 177 deletions
|
@ -1,6 +1,6 @@
|
||||||
noinst_LIBRARIES = libMultiPlayer.a
|
noinst_LIBRARIES = libMultiPlayer.a
|
||||||
|
|
||||||
libMultiPlayer_a_SOURCES = multiplayrxmgr.cxx multiplayrxmgr.hxx multiplaytxmgr.cxx multiplaytxmgr.hxx mpplayer.cxx mpplayer.hxx mpmessages.hxx
|
libMultiPlayer_a_SOURCES = multiplayrxmgr.cxx multiplayrxmgr.hxx multiplaytxmgr.cxx multiplaytxmgr.hxx mpplayer.cxx mpplayer.hxx mpmessages.hxx tiny_xdr.cpp tiny_xdr.hpp
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||||
|
|
||||||
|
|
|
@ -36,61 +36,55 @@
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
#include "tiny_xdr.hpp"
|
||||||
#ifdef HAVE_STDINT_H
|
|
||||||
# include <stdint.h>
|
|
||||||
#endif
|
|
||||||
#include <plib/sg.h>
|
#include <plib/sg.h>
|
||||||
|
|
||||||
|
// magic value for messages
|
||||||
|
const uint32_t MSG_MAGIC = 0x46474653; // "FGFS"
|
||||||
|
// protocoll version
|
||||||
|
const uint32_t PROTO_VER = 0x00010001; // 1.1
|
||||||
|
|
||||||
// Message identifiers
|
// Message identifiers
|
||||||
#define CHAT_MSG_ID 1
|
#define CHAT_MSG_ID 1
|
||||||
#define UNUSABLE_POS_DATA_ID 2
|
#define UNUSABLE_POS_DATA_ID 2
|
||||||
#define POS_DATA_ID 3
|
#define POS_DATA_ID 3
|
||||||
/* should be a multiple of 8! */
|
|
||||||
#define MAX_CALLSIGN_LEN 8
|
|
||||||
/** Header for use with all messages sent */
|
|
||||||
typedef struct {
|
|
||||||
|
|
||||||
/** Message identifier, multiple of 8! */
|
// XDR demands 4 byte alignment, but some compilers use8 byte alignment
|
||||||
uint32_t MsgId;
|
// so it's safe to let the overall size of a netmork message be a
|
||||||
|
// multiple of 8!
|
||||||
|
#define MAX_CALLSIGN_LEN 8
|
||||||
|
#define MAX_CHAT_MSG_LEN 48
|
||||||
|
#define MAX_MODEL_NAME_LEN 48
|
||||||
|
|
||||||
/** Length of the message inclusive of this header */
|
|
||||||
uint32_t iMsgLen;
|
|
||||||
|
|
||||||
/** IP address for reply to message (player's receiver address) */
|
|
||||||
uint32_t lReplyAddress;
|
|
||||||
|
|
||||||
/** Port for replies (player's receiver port) */
|
|
||||||
uint32_t iReplyPort;
|
|
||||||
|
|
||||||
/** Callsign used by the player */
|
|
||||||
char sCallsign[MAX_CALLSIGN_LEN];
|
|
||||||
|
|
||||||
} T_MsgHdr;
|
|
||||||
|
|
||||||
#define MAX_CHAT_MSG_LEN 48
|
|
||||||
/** Chat message */
|
|
||||||
typedef struct {
|
|
||||||
|
|
||||||
/** Text of chat message */
|
|
||||||
char sText[MAX_CHAT_MSG_LEN];
|
|
||||||
|
|
||||||
} T_ChatMsg;
|
|
||||||
|
|
||||||
/* should be a multiple of 8! */
|
|
||||||
#define MAX_MODEL_NAME_LEN 48
|
|
||||||
/** Aircraft position message */
|
/** Aircraft position message */
|
||||||
typedef struct {
|
typedef xdr_data2_t xdrPosition[3];
|
||||||
|
typedef xdr_data_t xdrOrientation[4];
|
||||||
|
|
||||||
/** Name of the aircraft model */
|
// Header for use with all messages sent
|
||||||
char sModel[MAX_MODEL_NAME_LEN];
|
class T_MsgHdr {
|
||||||
|
public:
|
||||||
|
xdr_data_t Magic; // Magic Value
|
||||||
|
xdr_data_t Version; // Protocoll version
|
||||||
|
xdr_data_t MsgId; // Message identifier
|
||||||
|
xdr_data_t iMsgLen; // absolue length of message
|
||||||
|
xdr_data_t lReplyAddress; // (player's receiver address
|
||||||
|
xdr_data_t iReplyPort; // player's receiver port
|
||||||
|
char sCallsign[MAX_CALLSIGN_LEN]; // Callsign used by the player
|
||||||
|
};
|
||||||
|
|
||||||
/** Position data for the aircraft */
|
// Chat message
|
||||||
sgdVec3 PlayerPosition;
|
class T_ChatMsg {
|
||||||
sgQuat PlayerOrientation;
|
public:
|
||||||
|
char sText[MAX_CHAT_MSG_LEN]; // Text of chat message
|
||||||
} T_PositionMsg;
|
};
|
||||||
|
|
||||||
|
// Position message
|
||||||
|
class T_PositionMsg {
|
||||||
|
public:
|
||||||
|
char sModel[MAX_MODEL_NAME_LEN]; // Name of the aircraft model
|
||||||
|
xdrPosition PlayerPosition; // players position
|
||||||
|
xdrOrientation PlayerOrientation; // players orientation
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,8 @@ bool MPPlayer::Open(const string &sAddress, const int &iPort, const string &sCal
|
||||||
m_sCallsign = sCallsign;
|
m_sCallsign = sCallsign;
|
||||||
m_sModelName = sModelName;
|
m_sModelName = sModelName;
|
||||||
m_bLocalPlayer = bLocalPlayer;
|
m_bLocalPlayer = bLocalPlayer;
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT, "Initialising " << m_sCallsign
|
||||||
|
<< " using '" << m_sModelName << "'" );
|
||||||
|
|
||||||
// If the player is remote then load the model
|
// If the player is remote then load the model
|
||||||
if (!bLocalPlayer) {
|
if (!bLocalPlayer) {
|
||||||
|
@ -169,7 +171,6 @@ void MPPlayer::Close(void) {
|
||||||
void MPPlayer::SetPosition(const sgQuat PlayerOrientation,
|
void MPPlayer::SetPosition(const sgQuat PlayerOrientation,
|
||||||
const sgdVec3 PlayerPosition) {
|
const sgdVec3 PlayerPosition) {
|
||||||
|
|
||||||
|
|
||||||
// Save the position matrix and update time
|
// Save the position matrix and update time
|
||||||
if (m_bInitialised) {
|
if (m_bInitialised) {
|
||||||
sgdCopyVec3(m_ModelPosition, PlayerPosition);
|
sgdCopyVec3(m_ModelPosition, PlayerPosition);
|
||||||
|
@ -178,7 +179,6 @@ void MPPlayer::SetPosition(const sgQuat PlayerOrientation,
|
||||||
m_bUpdated = true;
|
m_bUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -281,10 +281,17 @@ void MPPlayer::FillPosMsg(T_MsgHdr *MsgHdr, T_PositionMsg *PosMsg) {
|
||||||
|
|
||||||
strncpy(PosMsg->sModel, m_sModelName.c_str(), MAX_MODEL_NAME_LEN);
|
strncpy(PosMsg->sModel, m_sModelName.c_str(), MAX_MODEL_NAME_LEN);
|
||||||
PosMsg->sModel[MAX_MODEL_NAME_LEN - 1] = '\0';
|
PosMsg->sModel[MAX_MODEL_NAME_LEN - 1] = '\0';
|
||||||
|
/*
|
||||||
sgdCopyVec3(PosMsg->PlayerPosition, m_ModelPosition);
|
sgdCopyVec3(PosMsg->PlayerPosition, m_ModelPosition);
|
||||||
sgCopyQuat(PosMsg->PlayerOrientation, m_ModelOrientation);
|
sgCopyQuat(PosMsg->PlayerOrientation, m_ModelOrientation);
|
||||||
|
*/
|
||||||
|
PosMsg->PlayerPosition[0] = XDR_encode_double (m_ModelPosition[0]);
|
||||||
|
PosMsg->PlayerPosition[1] = XDR_encode_double (m_ModelPosition[1]);
|
||||||
|
PosMsg->PlayerPosition[2] = XDR_encode_double (m_ModelPosition[2]);
|
||||||
|
PosMsg->PlayerOrientation[0] = XDR_encode_float (m_ModelOrientation[0]);
|
||||||
|
PosMsg->PlayerOrientation[1] = XDR_encode_float (m_ModelOrientation[1]);
|
||||||
|
PosMsg->PlayerOrientation[2] = XDR_encode_float (m_ModelOrientation[2]);
|
||||||
|
PosMsg->PlayerOrientation[3] = XDR_encode_float (m_ModelOrientation[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -294,31 +301,32 @@ void MPPlayer::FillPosMsg(T_MsgHdr *MsgHdr, T_PositionMsg *PosMsg) {
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
void MPPlayer::FillMsgHdr(T_MsgHdr *MsgHdr, const int iMsgId) {
|
void MPPlayer::FillMsgHdr(T_MsgHdr *MsgHdr, const int iMsgId) {
|
||||||
|
|
||||||
struct in_addr address;
|
struct in_addr address;
|
||||||
|
uint32_t len;
|
||||||
MsgHdr->MsgId = iMsgId;
|
|
||||||
|
|
||||||
switch (iMsgId) {
|
switch (iMsgId) {
|
||||||
case CHAT_MSG_ID:
|
case CHAT_MSG_ID:
|
||||||
MsgHdr->iMsgLen = sizeof(T_MsgHdr) + sizeof(T_ChatMsg);
|
len = sizeof(T_MsgHdr) + sizeof(T_ChatMsg);
|
||||||
break;
|
break;
|
||||||
case POS_DATA_ID:
|
case POS_DATA_ID:
|
||||||
MsgHdr->iMsgLen = sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
|
len = sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
MsgHdr->iMsgLen = sizeof(T_MsgHdr);
|
len = sizeof(T_MsgHdr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
MsgHdr->Magic = XDR_encode_uint32 (MSG_MAGIC);
|
||||||
address.s_addr = inet_addr( m_PlayerAddress.getHost() );
|
MsgHdr->Version = XDR_encode_uint32 (PROTO_VER);
|
||||||
MsgHdr->lReplyAddress = address.s_addr;
|
MsgHdr->MsgId = XDR_encode_uint32 (iMsgId);
|
||||||
|
MsgHdr->iMsgLen = XDR_encode_uint32 (len);
|
||||||
MsgHdr->iReplyPort = m_PlayerAddress.getPort();
|
// inet_addr returns address in network byte order
|
||||||
|
// no need to encode it
|
||||||
|
MsgHdr->lReplyAddress = inet_addr( m_PlayerAddress.getHost() );
|
||||||
|
MsgHdr->iReplyPort = XDR_encode_uint32 (m_PlayerAddress.getPort());
|
||||||
|
|
||||||
strncpy(MsgHdr->sCallsign, m_sCallsign.c_str(), MAX_CALLSIGN_LEN);
|
strncpy(MsgHdr->sCallsign, m_sCallsign.c_str(), MAX_CALLSIGN_LEN);
|
||||||
MsgHdr->sCallsign[MAX_CALLSIGN_LEN - 1] = '\0';
|
MsgHdr->sCallsign[MAX_CALLSIGN_LEN - 1] = '\0';
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FG_MPLAYER_AS
|
#endif // FG_MPLAYER_AS
|
||||||
|
|
|
@ -210,123 +210,161 @@ void FGMultiplayRxMgr::ProcessData(void) {
|
||||||
char sMsg[MAX_PACKET_SIZE]; // Buffer for received message
|
char sMsg[MAX_PACKET_SIZE]; // Buffer for received message
|
||||||
int iBytes; // Bytes received
|
int iBytes; // Bytes received
|
||||||
T_MsgHdr *MsgHdr; // Pointer to header in received data
|
T_MsgHdr *MsgHdr; // Pointer to header in received data
|
||||||
T_ChatMsg *ChatMsg; // Pointer to chat message in received data
|
|
||||||
T_PositionMsg *PosMsg; // Pointer to position message in received data
|
|
||||||
char *sIpAddress; // Address information from header
|
|
||||||
char *sModelName; // Model that the remote player is using
|
|
||||||
char *sCallsign; // Callsign of the remote player
|
|
||||||
struct in_addr PlayerAddress; // Used for converting the player's address into dot notation
|
|
||||||
int iPlayerCnt; // Count of players in player array
|
|
||||||
bool bActivePlayer = false; // The state of the player that sent the data
|
|
||||||
int iPort; // Port that the remote player receives on
|
|
||||||
|
|
||||||
|
|
||||||
if (m_bInitialised) {
|
if (! m_bInitialised) {
|
||||||
|
return;
|
||||||
// Read the receive socket and process any data
|
|
||||||
do {
|
|
||||||
|
|
||||||
// Although the recv call asks for MAX_PACKET_SIZE of data,
|
|
||||||
// the number of bytes returned will only be that of the next
|
|
||||||
// packet waiting to be processed.
|
|
||||||
iBytes = mDataRxSocket->recv(sMsg, MAX_PACKET_SIZE, 0);
|
|
||||||
|
|
||||||
// Data received
|
|
||||||
if (iBytes > 0) {
|
|
||||||
if (iBytes >= (int)sizeof(MsgHdr)) {
|
|
||||||
|
|
||||||
// Read header
|
|
||||||
MsgHdr = (T_MsgHdr *)sMsg;
|
|
||||||
PlayerAddress.s_addr = MsgHdr->lReplyAddress;
|
|
||||||
sIpAddress = inet_ntoa(PlayerAddress);
|
|
||||||
iPort = MsgHdr->iReplyPort;
|
|
||||||
sCallsign = MsgHdr->sCallsign;
|
|
||||||
|
|
||||||
// Process the player data unless we generated it
|
|
||||||
if (m_sCallsign != MsgHdr->sCallsign) {
|
|
||||||
|
|
||||||
|
|
||||||
// Process messages
|
|
||||||
switch(MsgHdr->MsgId) {
|
|
||||||
case CHAT_MSG_ID:
|
|
||||||
if (MsgHdr->iMsgLen == sizeof(T_MsgHdr) + sizeof(T_ChatMsg)) {
|
|
||||||
ChatMsg = (T_ChatMsg *)(sMsg + sizeof(T_MsgHdr));
|
|
||||||
SG_LOG( SG_NETWORK, SG_BULK, "Chat [" << MsgHdr->sCallsign << "]" << " " << ChatMsg->sText );
|
|
||||||
} else {
|
|
||||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayRxMgr::MP_ProcessData - Chat message received with insufficient data" );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case POS_DATA_ID:
|
|
||||||
if (MsgHdr->iMsgLen == sizeof(T_MsgHdr) + sizeof(T_PositionMsg)) {
|
|
||||||
PosMsg = (T_PositionMsg *)(sMsg + sizeof(T_MsgHdr));
|
|
||||||
sModelName = PosMsg->sModel;
|
|
||||||
|
|
||||||
// Check if the player is already in the game by using the Callsign.
|
|
||||||
bActivePlayer = false;
|
|
||||||
for (iPlayerCnt = 0; iPlayerCnt < MAX_PLAYERS; iPlayerCnt++) {
|
|
||||||
if (m_Player[iPlayerCnt] != NULL) {
|
|
||||||
if (m_Player[iPlayerCnt]->CompareCallsign(MsgHdr->sCallsign)) {
|
|
||||||
|
|
||||||
// Player found. Update the data for the player.
|
|
||||||
m_Player[iPlayerCnt]->SetPosition(PosMsg->PlayerOrientation, PosMsg->PlayerPosition);
|
|
||||||
bActivePlayer = true;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Player not active, so add as new player
|
|
||||||
if (!bActivePlayer) {
|
|
||||||
iPlayerCnt = 0;
|
|
||||||
do {
|
|
||||||
if (m_Player[iPlayerCnt] == NULL) {
|
|
||||||
SG_LOG( SG_NETWORK, SG_INFO, "FGMultiplayRxMgr::ProcessRxData - Add new player. IP: " << sIpAddress << ", Call: " << sCallsign << ", model: " << sModelName );
|
|
||||||
m_Player[iPlayerCnt] = new MPPlayer;
|
|
||||||
m_Player[iPlayerCnt]->Open(sIpAddress, iPort, sCallsign, sModelName, false);
|
|
||||||
m_Player[iPlayerCnt]->SetPosition(PosMsg->PlayerOrientation, PosMsg->PlayerPosition);
|
|
||||||
bActivePlayer = true;
|
|
||||||
}
|
|
||||||
iPlayerCnt++;
|
|
||||||
} while (iPlayerCnt < MAX_PLAYERS && !bActivePlayer);
|
|
||||||
|
|
||||||
// Check if the player was added
|
|
||||||
if (!bActivePlayer) {
|
|
||||||
if (iPlayerCnt == MAX_PLAYERS) {
|
|
||||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayRxMgr::MP_ProcessData - Unable to add new player (" << sCallsign << "). Too many players." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayRxMgr::MP_ProcessData - Position message received with insufficient data" );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayRxMgr::MP_ProcessData - Unknown message Id received: " << MsgHdr->MsgId );
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Error or no data
|
|
||||||
} else if (iBytes == -1) {
|
|
||||||
if (errno != EAGAIN) {
|
|
||||||
perror("FGMultiplayRxMgr::MP_ProcessData");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (iBytes > 0);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read the receive socket and process any data
|
||||||
|
do {
|
||||||
|
|
||||||
|
// Although the recv call asks for MAX_PACKET_SIZE of data,
|
||||||
|
// the number of bytes returned will only be that of the next
|
||||||
|
// packet waiting to be processed.
|
||||||
|
iBytes = mDataRxSocket->recv(sMsg, MAX_PACKET_SIZE, 0);
|
||||||
|
|
||||||
|
// no Data received
|
||||||
|
if (iBytes <= 0) {
|
||||||
|
if (errno != EAGAIN) {
|
||||||
|
perror("FGMultiplayRxMgr::MP_ProcessData");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (iBytes <= (int)sizeof(MsgHdr)) {
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
|
"FGMultiplayRxMgr::MP_ProcessData - received message with insufficient data" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Read header
|
||||||
|
MsgHdr = (T_MsgHdr *)sMsg;
|
||||||
|
MsgHdr->Magic = XDR_decode_uint32 (MsgHdr->Magic);
|
||||||
|
MsgHdr->Version = XDR_decode_uint32 (MsgHdr->Version);
|
||||||
|
MsgHdr->MsgId = XDR_decode_uint32 (MsgHdr->MsgId);
|
||||||
|
MsgHdr->iMsgLen = XDR_decode_uint32 (MsgHdr->iMsgLen);
|
||||||
|
MsgHdr->iReplyPort = XDR_decode_uint32 (MsgHdr->iReplyPort);
|
||||||
|
if (MsgHdr->Magic != MSG_MAGIC) {
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
|
"FGMultiplayRxMgr::MP_ProcessData - message has invalid magic number!" );
|
||||||
|
}
|
||||||
|
if (MsgHdr->Version != PROTO_VER) {
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
|
"FGMultiplayRxMgr::MP_ProcessData - message has invalid protocoll number!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the player data unless we generated it
|
||||||
|
if (m_sCallsign == MsgHdr->sCallsign) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process messages
|
||||||
|
switch(MsgHdr->MsgId) {
|
||||||
|
case CHAT_MSG_ID:
|
||||||
|
ProcessChatMsg ((char*) & sMsg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POS_DATA_ID:
|
||||||
|
ProcessPosMsg ((char*) & sMsg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
|
"FGMultiplayRxMgr::MP_ProcessData - Unknown message Id received: "
|
||||||
|
<< MsgHdr->MsgId );
|
||||||
|
break;
|
||||||
|
} // switch
|
||||||
|
} while (iBytes > 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FGMultiplayRxMgr::ProcessPosMsg ( const char *Msg ) {
|
||||||
|
|
||||||
|
T_PositionMsg *PosMsg; // Pointer to position message in received data
|
||||||
|
T_MsgHdr *MsgHdr; // Pointer to header in received data
|
||||||
|
int iPlayerCnt; // Count of players in player array
|
||||||
|
bool bActivePlayer = false; // The state of the player that sent the data
|
||||||
|
sgQuat Orientation;
|
||||||
|
sgdVec3 Position;
|
||||||
|
char *sIpAddress; // Address information from header
|
||||||
|
struct in_addr PlayerAddress; // Used for converting the player's address into dot notation
|
||||||
|
|
||||||
|
MsgHdr = (T_MsgHdr *)Msg;
|
||||||
|
if (MsgHdr->iMsgLen != sizeof(T_MsgHdr) + sizeof(T_PositionMsg)) {
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
|
"FGMultiplayRxMgr::MP_ProcessData - Position message received with insufficient data" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PosMsg = (T_PositionMsg *)(Msg + sizeof(T_MsgHdr));
|
||||||
|
Position[0] = XDR_decode_double (PosMsg->PlayerPosition[0]);
|
||||||
|
Position[1] = XDR_decode_double (PosMsg->PlayerPosition[1]);
|
||||||
|
Position[2] = XDR_decode_double (PosMsg->PlayerPosition[2]);
|
||||||
|
Orientation[0] = XDR_decode_float (PosMsg->PlayerOrientation[0]);
|
||||||
|
Orientation[1] = XDR_decode_float (PosMsg->PlayerOrientation[1]);
|
||||||
|
Orientation[2] = XDR_decode_float (PosMsg->PlayerOrientation[2]);
|
||||||
|
Orientation[3] = XDR_decode_float (PosMsg->PlayerOrientation[3]);
|
||||||
|
|
||||||
|
// Check if the player is already in the game by using the Callsign.
|
||||||
|
for (iPlayerCnt = 0; iPlayerCnt < MAX_PLAYERS; iPlayerCnt++) {
|
||||||
|
if (m_Player[iPlayerCnt] != NULL) {
|
||||||
|
if (m_Player[iPlayerCnt]->CompareCallsign(MsgHdr->sCallsign)) {
|
||||||
|
// Player found. Update the data for the player.
|
||||||
|
m_Player[iPlayerCnt]->SetPosition(Orientation, Position);
|
||||||
|
bActivePlayer = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bActivePlayer) {
|
||||||
|
// nothing more to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Player not active, so add as new player
|
||||||
|
iPlayerCnt = 0;
|
||||||
|
do {
|
||||||
|
if (m_Player[iPlayerCnt] == NULL) {
|
||||||
|
PlayerAddress.s_addr = MsgHdr->lReplyAddress; // which is unecoded
|
||||||
|
sIpAddress = inet_ntoa(PlayerAddress);
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
|
"FGMultiplayRxMgr::ProcessRxData - Add new player. IP: " << sIpAddress
|
||||||
|
<< ", Call: " << MsgHdr->sCallsign
|
||||||
|
<< ", model: " << PosMsg->sModel);
|
||||||
|
m_Player[iPlayerCnt] = new MPPlayer;
|
||||||
|
m_Player[iPlayerCnt]->Open(sIpAddress, MsgHdr->iReplyPort,
|
||||||
|
MsgHdr->sCallsign, PosMsg->sModel, false);
|
||||||
|
m_Player[iPlayerCnt]->SetPosition(Orientation, Position);
|
||||||
|
bActivePlayer = true;
|
||||||
|
}
|
||||||
|
iPlayerCnt++;
|
||||||
|
} while (iPlayerCnt < MAX_PLAYERS && !bActivePlayer);
|
||||||
|
|
||||||
|
// Check if the player was added
|
||||||
|
if (!bActivePlayer) {
|
||||||
|
if (iPlayerCnt == MAX_PLAYERS) {
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
|
"FGMultiplayRxMgr::MP_ProcessData - Unable to add new player ("
|
||||||
|
<< MsgHdr->sCallsign
|
||||||
|
<< "). Too many players." );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGMultiplayRxMgr::ProcessChatMsg ( const char *Msg ) {
|
||||||
|
|
||||||
|
T_ChatMsg *ChatMsg; // Pointer to chat message in received data
|
||||||
|
T_MsgHdr *MsgHdr; // Pointer to header in received data
|
||||||
|
|
||||||
|
MsgHdr = (T_MsgHdr *)Msg;
|
||||||
|
if (MsgHdr->iMsgLen != sizeof(T_MsgHdr) + sizeof(T_ChatMsg)) {
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
|
"FGMultiplayRxMgr::MP_ProcessData - Chat message received with insufficient data" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatMsg = (T_ChatMsg *)(Msg + sizeof(T_MsgHdr));
|
||||||
|
SG_LOG( SG_NETWORK, SG_BULK, "Chat [" << MsgHdr->sCallsign << "]" << " " << ChatMsg->sText );
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* Name: Update
|
* Name: Update
|
||||||
|
|
|
@ -30,10 +30,6 @@
|
||||||
#include "mpplayer.hxx"
|
#include "mpplayer.hxx"
|
||||||
#include "mpmessages.hxx"
|
#include "mpmessages.hxx"
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include STL_STRING
|
#include STL_STRING
|
||||||
SG_USING_STD(string);
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
@ -71,6 +67,8 @@ public:
|
||||||
/** Initiates processing of any data waiting at the rx socket.
|
/** Initiates processing of any data waiting at the rx socket.
|
||||||
*/
|
*/
|
||||||
void ProcessData(void);
|
void ProcessData(void);
|
||||||
|
void ProcessPosMsg ( const char *Msg );
|
||||||
|
void ProcessChatMsg ( const char *Msg );
|
||||||
|
|
||||||
/** Updates the model positions for the players
|
/** Updates the model positions for the players
|
||||||
*/
|
*/
|
||||||
|
|
163
src/MultiPlayer/tiny_xdr.cpp
Normal file
163
src/MultiPlayer/tiny_xdr.cpp
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Tiny XDR implementation for flightgear
|
||||||
|
// written by Oliver Schroeder
|
||||||
|
// released to the puiblic domain
|
||||||
|
//
|
||||||
|
// This implementation is not complete, but implements
|
||||||
|
// everything we need.
|
||||||
|
//
|
||||||
|
// For further reading on XDR read RFC 1832.
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <plib/ul.h>
|
||||||
|
|
||||||
|
#include "tiny_xdr.hpp"
|
||||||
|
|
||||||
|
/* XDR 8bit integers */
|
||||||
|
xdr_data_t
|
||||||
|
XDR_encode_int8 ( int8_t n_Val )
|
||||||
|
{
|
||||||
|
return (SWAP32(static_cast<xdr_data_t> (n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
xdr_data_t
|
||||||
|
XDR_encode_uint8 ( uint8_t n_Val )
|
||||||
|
{
|
||||||
|
return (SWAP32(static_cast<xdr_data_t> (n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
XDR_decode_int8 ( xdr_data_t n_Val )
|
||||||
|
{
|
||||||
|
return (static_cast<int8_t> (SWAP32(n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
XDR_decode_uint8 ( xdr_data_t n_Val )
|
||||||
|
{
|
||||||
|
return (static_cast<uint8_t> (SWAP32(n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XDR 16bit integers */
|
||||||
|
xdr_data_t
|
||||||
|
XDR_encode_int16 ( int16_t n_Val )
|
||||||
|
{
|
||||||
|
return (SWAP32(static_cast<xdr_data_t> (n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
xdr_data_t
|
||||||
|
XDR_encode_uint16 ( uint16_t n_Val )
|
||||||
|
{
|
||||||
|
return (SWAP32(static_cast<xdr_data_t> (n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t
|
||||||
|
XDR_decode_int16 ( xdr_data_t n_Val )
|
||||||
|
{
|
||||||
|
return (static_cast<int16_t> (SWAP32(n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
XDR_decode_uint16 ( xdr_data_t n_Val )
|
||||||
|
{
|
||||||
|
return (static_cast<uint16_t> (SWAP32(n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* XDR 32bit integers */
|
||||||
|
xdr_data_t
|
||||||
|
XDR_encode_int32 ( int32_t n_Val )
|
||||||
|
{
|
||||||
|
return (SWAP32(static_cast<xdr_data_t> (n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
xdr_data_t
|
||||||
|
XDR_encode_uint32 ( uint32_t n_Val )
|
||||||
|
{
|
||||||
|
return (SWAP32(static_cast<xdr_data_t> (n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
XDR_decode_int32 ( xdr_data_t n_Val )
|
||||||
|
{
|
||||||
|
return (static_cast<int32_t> (SWAP32(n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
XDR_decode_uint32 ( xdr_data_t n_Val )
|
||||||
|
{
|
||||||
|
return (static_cast<uint32_t> (SWAP32(n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* XDR 64bit integers */
|
||||||
|
xdr_data2_t
|
||||||
|
XDR_encode_int64 ( int64_t n_Val )
|
||||||
|
{
|
||||||
|
return (SWAP64(static_cast<xdr_data2_t> (n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
xdr_data2_t
|
||||||
|
XDR_encode_uint64 ( uint64_t n_Val )
|
||||||
|
{
|
||||||
|
return (SWAP64(static_cast<xdr_data2_t> (n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
XDR_decode_int64 ( xdr_data2_t n_Val )
|
||||||
|
{
|
||||||
|
return (static_cast<int64_t> (SWAP64(n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
XDR_decode_uint64 ( xdr_data2_t n_Val )
|
||||||
|
{
|
||||||
|
return (static_cast<uint64_t> (SWAP64(n_Val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* float */
|
||||||
|
xdr_data_t
|
||||||
|
XDR_encode_float ( float f_Val )
|
||||||
|
{
|
||||||
|
xdr_data_t* tmp;
|
||||||
|
|
||||||
|
tmp = (xdr_data_t*) &f_Val;
|
||||||
|
return (XDR_encode_int32 (*tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
XDR_decode_float ( xdr_data_t f_Val )
|
||||||
|
{
|
||||||
|
float* tmp;
|
||||||
|
xdr_data_t dummy;
|
||||||
|
|
||||||
|
dummy = XDR_decode_int32 (f_Val);
|
||||||
|
tmp = (float*) &dummy;
|
||||||
|
return (*tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* double */
|
||||||
|
xdr_data2_t
|
||||||
|
XDR_encode_double ( double d_Val )
|
||||||
|
{
|
||||||
|
xdr_data2_t* tmp;
|
||||||
|
|
||||||
|
tmp = (xdr_data2_t*) &d_Val;
|
||||||
|
return (XDR_encode_int64 (*tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
XDR_decode_double ( xdr_data2_t d_Val )
|
||||||
|
{
|
||||||
|
double* tmp;
|
||||||
|
xdr_data2_t dummy;
|
||||||
|
|
||||||
|
dummy = XDR_decode_int64 (d_Val);
|
||||||
|
tmp = (double*) &dummy;
|
||||||
|
return (*tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
128
src/MultiPlayer/tiny_xdr.hpp
Normal file
128
src/MultiPlayer/tiny_xdr.hpp
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Tiny XDR implementation for flightgear
|
||||||
|
// written by Oliver Schroeder
|
||||||
|
// released to the puiblic domain
|
||||||
|
//
|
||||||
|
// This implementation is not complete, but implements
|
||||||
|
// everything we need.
|
||||||
|
//
|
||||||
|
// For further reading on XDR read RFC 1832.
|
||||||
|
//
|
||||||
|
// NEW
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef TINY_XDR_HEADER
|
||||||
|
#define TINY_XDR_HEADER
|
||||||
|
|
||||||
|
#if defined HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#if defined HAVE_STDINT_H
|
||||||
|
# include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <plib/ul.h>
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// There are many sick systems out there:
|
||||||
|
//
|
||||||
|
// check for sizeof(float) and sizeof(double)
|
||||||
|
// if sizeof(float) != 4 this code must be patched
|
||||||
|
// if sizeof(double) != 8 this code must be patched
|
||||||
|
//
|
||||||
|
// Those are comments I fetched out of glibc source:
|
||||||
|
// - s390 is big-endian
|
||||||
|
// - Sparc is big-endian, but v9 supports endian conversion
|
||||||
|
// on loads/stores and GCC supports such a mode. Be prepared.
|
||||||
|
// - The MIPS architecture has selectable endianness.
|
||||||
|
// - x86_64 is little-endian.
|
||||||
|
// - CRIS is little-endian.
|
||||||
|
// - m68k is big-endian.
|
||||||
|
// - Alpha is little-endian.
|
||||||
|
// - PowerPC can be little or big endian.
|
||||||
|
// - SH is bi-endian but with a big-endian FPU.
|
||||||
|
// - hppa1.1 big-endian.
|
||||||
|
// - ARM is (usually) little-endian but with a big-endian FPU.
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
inline uint32_t bswap_32(unsigned int b) {
|
||||||
|
unsigned x = b;
|
||||||
|
ulEndianSwap(&x);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t bswap_64(unsigned long long b) {
|
||||||
|
uint64_t x = b;
|
||||||
|
x = ((x >> 32) & 0x00000000FFFFFFFFLL) | ((x << 32) & 0xFFFFFFFF00000000LL);
|
||||||
|
x = ((x >> 16) & 0x0000FFFF0000FFFFLL) | ((x << 16) & 0xFFFF0000FFFF0000LL);
|
||||||
|
x = ((x >> 8) & 0x00FF00FF00FF00FFLL) | ((x << 8) & 0xFF00FF00FF00FF00LL);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BYTE_ORDER == BIG_ENDIAN
|
||||||
|
# define SWAP32(arg) arg
|
||||||
|
# define SWAP64(arg) arg
|
||||||
|
# define LOW 0
|
||||||
|
# define HIGH 1
|
||||||
|
#else
|
||||||
|
# define SWAP32(arg) bswap_32(arg)
|
||||||
|
# define SWAP64(arg) bswap_64(arg)
|
||||||
|
# define LOW 1
|
||||||
|
# define HIGH 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define XDR_BYTES_PER_UNIT 4
|
||||||
|
|
||||||
|
typedef uint32_t xdr_data_t; /* 4 Bytes */
|
||||||
|
typedef uint64_t xdr_data2_t; /* 8 Bytes */
|
||||||
|
|
||||||
|
/* XDR 8bit integers */
|
||||||
|
xdr_data_t XDR_encode_int8 ( int8_t n_Val );
|
||||||
|
xdr_data_t XDR_encode_uint8 ( uint8_t n_Val );
|
||||||
|
int8_t XDR_decode_int8 ( xdr_data_t n_Val );
|
||||||
|
uint8_t XDR_decode_uint8 ( xdr_data_t n_Val );
|
||||||
|
|
||||||
|
/* XDR 16bit integers */
|
||||||
|
xdr_data_t XDR_encode_int16 ( int16_t n_Val );
|
||||||
|
xdr_data_t XDR_encode_uint16 ( uint16_t n_Val );
|
||||||
|
int16_t XDR_decode_int16 ( xdr_data_t n_Val );
|
||||||
|
uint16_t XDR_decode_uint16 ( xdr_data_t n_Val );
|
||||||
|
|
||||||
|
/* XDR 32bit integers */
|
||||||
|
xdr_data_t XDR_encode_int32 ( int32_t n_Val );
|
||||||
|
xdr_data_t XDR_encode_uint32 ( const uint32_t n_Val );
|
||||||
|
int32_t XDR_decode_int32 ( xdr_data_t n_Val );
|
||||||
|
uint32_t XDR_decode_uint32 ( const xdr_data_t n_Val );
|
||||||
|
|
||||||
|
/* XDR 64bit integers */
|
||||||
|
xdr_data2_t XDR_encode_int64 ( int64_t n_Val );
|
||||||
|
xdr_data2_t XDR_encode_uint64 ( uint64_t n_Val );
|
||||||
|
int64_t XDR_decode_int64 ( xdr_data2_t n_Val );
|
||||||
|
uint64_t XDR_decode_uint64 ( xdr_data2_t n_Val );
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// FIXME: #1 these funtions must be fixed for
|
||||||
|
// none IEEE-encoding architecturs
|
||||||
|
// (eg. vax, big suns etc)
|
||||||
|
// FIXME: #2 some compilers return 'double'
|
||||||
|
// regardless of return-type 'float'
|
||||||
|
// this must be fixed, too
|
||||||
|
// FIXME: #3 some machines may need to use a
|
||||||
|
// different endianess for floats!
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
/* float */
|
||||||
|
xdr_data_t XDR_encode_float ( float f_Val );
|
||||||
|
float XDR_decode_float ( xdr_data_t f_Val );
|
||||||
|
|
||||||
|
/* double */
|
||||||
|
xdr_data2_t XDR_encode_double ( double d_Val );
|
||||||
|
double XDR_decode_double ( xdr_data2_t d_Val );
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue