Oliver Schroeder:
This is mainly an intermediate patch. I've restructured the network code.
This commit is contained in:
parent
bc703b2bd3
commit
eed55b48b7
17 changed files with 780 additions and 1085 deletions
|
@ -114,8 +114,7 @@
|
|||
#include <Traffic/TrafficMgr.hxx>
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
#include <MultiPlayer/multiplaytxmgr.hxx>
|
||||
#include <MultiPlayer/multiplayrxmgr.hxx>
|
||||
#include <MultiPlayer/multiplaymgr.hpp>
|
||||
#endif
|
||||
|
||||
#include <Environment/environment_mgr.hxx>
|
||||
|
@ -1842,11 +1841,8 @@ bool fgInitSubsystems() {
|
|||
// Initialize multiplayer subsystem
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
globals->set_multiplayer_tx_mgr(new FGMultiplayTxMgr);
|
||||
globals->get_multiplayer_tx_mgr()->init();
|
||||
|
||||
globals->set_multiplayer_rx_mgr(new FGMultiplayRxMgr);
|
||||
globals->get_multiplayer_rx_mgr()->init();
|
||||
globals->set_multiplayer_mgr(new FGMultiplayMgr);
|
||||
globals->get_multiplayer_mgr()->init();
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -80,8 +80,7 @@ class FGModelMgr;
|
|||
class FGRouteMgr;
|
||||
class FGScenery;
|
||||
#ifdef FG_MPLAYER_AS
|
||||
class FGMultiplayRxMgr;
|
||||
class FGMultiplayTxMgr;
|
||||
class FGMultiplayMgr;
|
||||
#endif
|
||||
class FGPanel;
|
||||
class FGTileMgr;
|
||||
|
@ -214,9 +213,7 @@ private:
|
|||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
//Mulitplayer managers
|
||||
FGMultiplayTxMgr *multiplayer_tx_mgr;
|
||||
|
||||
FGMultiplayRxMgr *multiplayer_rx_mgr;
|
||||
FGMultiplayMgr *multiplayer_mgr;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
@ -330,19 +327,13 @@ public:
|
|||
}
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
inline FGMultiplayTxMgr *get_multiplayer_tx_mgr () { return multiplayer_tx_mgr; }
|
||||
inline FGMultiplayMgr *get_multiplayer_mgr () { return multiplayer_mgr; }
|
||||
|
||||
inline void set_multiplayer_tx_mgr (FGMultiplayTxMgr * mgr)
|
||||
inline void set_multiplayer_mgr (FGMultiplayMgr * mgr)
|
||||
{
|
||||
multiplayer_tx_mgr = mgr;
|
||||
multiplayer_mgr = mgr;
|
||||
}
|
||||
|
||||
inline FGMultiplayRxMgr *get_multiplayer_rx_mgr () { return multiplayer_rx_mgr; }
|
||||
|
||||
inline void set_multiplayer_rx_mgr (FGMultiplayRxMgr * mgr)
|
||||
{
|
||||
multiplayer_rx_mgr = mgr;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline string_list *get_channel_options_list () {
|
||||
|
|
|
@ -76,8 +76,7 @@
|
|||
#include <GUI/new_gui.hxx>
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
#include <MultiPlayer/multiplaytxmgr.hxx>
|
||||
#include <MultiPlayer/multiplayrxmgr.hxx>
|
||||
#include <MultiPlayer/multiplaymgr.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -449,7 +448,7 @@ static void fgMainLoop( void ) {
|
|||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
// Update any multiplayer models
|
||||
globals->get_multiplayer_rx_mgr()->Update();
|
||||
globals->get_multiplayer_mgr()->Update();
|
||||
#endif
|
||||
|
||||
// Run flight model
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
noinst_LIBRARIES = libMultiPlayer.a
|
||||
|
||||
libMultiPlayer_a_SOURCES = multiplayrxmgr.cxx multiplayrxmgr.hxx multiplaytxmgr.cxx multiplaytxmgr.hxx mpplayer.cxx mpplayer.hxx mpmessages.hxx tiny_xdr.cpp tiny_xdr.hpp
|
||||
libMultiPlayer_a_SOURCES = multiplaymgr.cpp multiplaymgr.hpp mpplayer.cxx mpplayer.hxx mpmessages.hxx tiny_xdr.cpp tiny_xdr.hpp
|
||||
|
||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||
|
||||
|
|
|
@ -66,22 +66,22 @@ 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
|
||||
xdr_data_t MsgLen; // absolue length of message
|
||||
xdr_data_t ReplyAddress; // (player's receiver address
|
||||
xdr_data_t ReplyPort; // player's receiver port
|
||||
char Callsign[MAX_CALLSIGN_LEN]; // Callsign used by the player
|
||||
};
|
||||
|
||||
// Chat message
|
||||
class T_ChatMsg {
|
||||
public:
|
||||
char sText[MAX_CHAT_MSG_LEN]; // Text of chat message
|
||||
char Text[MAX_CHAT_MSG_LEN]; // Text of chat message
|
||||
};
|
||||
|
||||
// Position message
|
||||
class T_PositionMsg {
|
||||
public:
|
||||
char sModel[MAX_MODEL_NAME_LEN]; // Name of the aircraft model
|
||||
char Model[MAX_MODEL_NAME_LEN]; // Name of the aircraft model
|
||||
xdrPosition PlayerPosition; // players position
|
||||
xdrOrientation PlayerOrientation; // players orientation
|
||||
};
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// mpplayer.cxx -- routines for a player within a multiplayer Flightgear
|
||||
//
|
||||
// Written by Duncan McCreanor, started February 2003.
|
||||
// duncan.mccreanor@airservicesaustralia.com
|
||||
//
|
||||
// Copyright (C) 2003 Airservices Australia
|
||||
// Copyright (C) 2005 Oliver Schroeder
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
|
@ -19,6 +22,7 @@
|
|||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
|
@ -44,10 +48,10 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#if !(defined(_MSC_VER) || defined(__MINGW32__))
|
||||
# include <netdb.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <netdb.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#include <plib/netSocket.h>
|
||||
#include <plib/sg.h>
|
||||
|
@ -63,228 +67,214 @@
|
|||
const char sMPPLAYER_BID[] = "$Id$";
|
||||
const char sMPPLAYER_HID[] = MPPLAYER_HID;
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: MPPlayer
|
||||
* Description: Constructor.
|
||||
******************************************************************/
|
||||
MPPlayer::MPPlayer() {
|
||||
|
||||
// Initialise private members
|
||||
m_bInitialised = false;
|
||||
m_LastUpdate = 0;
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// constructor
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
MPPlayer::MPPlayer()
|
||||
{
|
||||
m_Initialised = false;
|
||||
m_LastUpdate = 0;
|
||||
m_Callsign = "none";
|
||||
m_PlayerAddress.set("localhost", 0);
|
||||
m_sCallsign = "none";
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // MPPlayer::MPPlayer()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/******************************************************************
|
||||
* Name: ~MPPlayer
|
||||
* Description: Destructor.
|
||||
******************************************************************/
|
||||
MPPlayer::~MPPlayer() {
|
||||
|
||||
MPPlayer::~MPPlayer()
|
||||
{
|
||||
Close();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: Open
|
||||
* Description: Initialises class.
|
||||
******************************************************************/
|
||||
bool MPPlayer::Open(const string &sAddress, const int &iPort, const string &sCallsign, const string &sModelName, bool bLocalPlayer) {
|
||||
|
||||
bool bSuccess = true;
|
||||
|
||||
if (!m_bInitialised) {
|
||||
|
||||
m_PlayerAddress.set(sAddress.c_str(), iPort);
|
||||
m_sCallsign = sCallsign;
|
||||
m_sModelName = sModelName;
|
||||
m_bLocalPlayer = bLocalPlayer;
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "Initialising " << m_sCallsign
|
||||
<< " using '" << m_sModelName << "'" );
|
||||
bool
|
||||
MPPlayer::Open
|
||||
(
|
||||
const string &Address,
|
||||
const int &Port,
|
||||
const string &Callsign,
|
||||
const string &ModelName,
|
||||
bool LocalPlayer
|
||||
)
|
||||
{
|
||||
bool Success = true;
|
||||
|
||||
if (!m_Initialised)
|
||||
{
|
||||
m_PlayerAddress.set(Address.c_str(), Port);
|
||||
m_Callsign = Callsign;
|
||||
m_ModelName = ModelName;
|
||||
m_LocalPlayer = LocalPlayer;
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "Initialising " << m_Callsign
|
||||
<< " using '" << m_ModelName << "'" );
|
||||
// If the player is remote then load the model
|
||||
if (!bLocalPlayer) {
|
||||
if (!LocalPlayer)
|
||||
{
|
||||
try {
|
||||
LoadModel();
|
||||
} catch (...) {
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "Failed to load remote model '" << sModelName << "'." );
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"Failed to load remote model '" << ModelName << "'." );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_bInitialised = bSuccess;
|
||||
|
||||
} else {
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "MPPlayer::Open - Attempt to open an already open player connection." );
|
||||
bSuccess = false;
|
||||
m_Initialised = Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "MPPlayer::Open - "
|
||||
<< "Attempt to open an already opened player connection." );
|
||||
Success = false;
|
||||
}
|
||||
|
||||
|
||||
/* Return true if open succeeds */
|
||||
return bSuccess;
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: Close
|
||||
* Description: Resets the object.
|
||||
******************************************************************/
|
||||
void MPPlayer::Close(void) {
|
||||
|
||||
void
|
||||
MPPlayer::Close(void)
|
||||
{
|
||||
// Remove the model from the game
|
||||
if (m_bInitialised && !m_bLocalPlayer) {
|
||||
|
||||
// Disconnect the model from the transform, then the transform from the scene.
|
||||
if (m_Initialised && !m_LocalPlayer)
|
||||
{
|
||||
// Disconnect the model from the transform,
|
||||
// then the transform from the scene.
|
||||
m_ModelTrans->removeKid(m_Model);
|
||||
globals->get_scenery()->unregister_placement_transform(m_ModelTrans);
|
||||
globals->get_scenery()->get_aircraft_branch()->removeKid( m_ModelTrans);
|
||||
|
||||
// Flush the model loader so that it erases the model from its list of
|
||||
// models.
|
||||
// globals->get_model_lib()->flush1();
|
||||
|
||||
// globals->get_model_lib()->flush1();
|
||||
// Assume that plib/ssg deletes the model and transform as their
|
||||
// refcounts should be zero.
|
||||
|
||||
}
|
||||
|
||||
m_bInitialised = false;
|
||||
m_bUpdated = false;
|
||||
m_LastUpdate = 0;
|
||||
m_sCallsign = "none";
|
||||
|
||||
m_Initialised = false;
|
||||
m_Updated = false;
|
||||
m_LastUpdate = 0;
|
||||
m_Callsign = "none";
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: SetPosition
|
||||
* Description: Updates position data held for this player and resets
|
||||
* the last update time.
|
||||
******************************************************************/
|
||||
void MPPlayer::SetPosition(const sgQuat PlayerOrientation,
|
||||
const sgdVec3 PlayerPosition) {
|
||||
|
||||
void
|
||||
MPPlayer::SetPosition
|
||||
(
|
||||
const sgQuat PlayerOrientation,
|
||||
const sgdVec3 PlayerPosition
|
||||
)
|
||||
{
|
||||
// Save the position matrix and update time
|
||||
if (m_bInitialised) {
|
||||
if (m_Initialised)
|
||||
{
|
||||
sgdCopyVec3(m_ModelPosition, PlayerPosition);
|
||||
sgCopyVec4(m_ModelOrientation, PlayerOrientation);
|
||||
time(&m_LastUpdate);
|
||||
m_bUpdated = true;
|
||||
m_Updated = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: Draw
|
||||
* Description: Updates the position for the player's model
|
||||
* The state of the player's data is returned.
|
||||
******************************************************************/
|
||||
MPPlayer::TPlayerDataState MPPlayer::Draw(void) {
|
||||
|
||||
MPPlayer::TPlayerDataState
|
||||
MPPlayer::Draw (void)
|
||||
{
|
||||
MPPlayer::TPlayerDataState eResult = PLAYER_DATA_NOT_AVAILABLE;
|
||||
|
||||
if (m_bInitialised && !m_bLocalPlayer) {
|
||||
if ((time(NULL) - m_LastUpdate < TIME_TO_LIVE)) {
|
||||
if (m_Initialised && !m_LocalPlayer)
|
||||
{
|
||||
if ((time(NULL) - m_LastUpdate < TIME_TO_LIVE))
|
||||
{
|
||||
// Peform an update if it has changed since the last update
|
||||
if (m_bUpdated) {
|
||||
|
||||
if (m_Updated)
|
||||
{
|
||||
// Transform and update player model
|
||||
sgMat4 orMat;
|
||||
sgMakeIdentMat4(orMat);
|
||||
sgQuatToMatrix(orMat, m_ModelOrientation);
|
||||
m_ModelTrans->setTransform(m_ModelPosition, orMat);
|
||||
|
||||
eResult = PLAYER_DATA_AVAILABLE;
|
||||
|
||||
// Clear the updated flag so that the position data
|
||||
// is only available if it has changed
|
||||
m_bUpdated = false;
|
||||
m_Updated = false;
|
||||
}
|
||||
|
||||
// Data has not been updated for some time.
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{ // Data has not been updated for some time.
|
||||
eResult = PLAYER_DATA_EXPIRED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return eResult;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: Callsign
|
||||
* Description: Returns the player's callsign.
|
||||
******************************************************************/
|
||||
string MPPlayer::Callsign(void) const {
|
||||
|
||||
return m_sCallsign;
|
||||
|
||||
string
|
||||
MPPlayer::Callsign(void) const
|
||||
{
|
||||
return m_Callsign;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: CompareCallsign
|
||||
* Description: Returns true if the player's callsign matches
|
||||
* the given callsign.
|
||||
******************************************************************/
|
||||
bool MPPlayer::CompareCallsign(const char *sCallsign) const {
|
||||
|
||||
return (m_sCallsign == sCallsign);
|
||||
|
||||
bool
|
||||
MPPlayer::CompareCallsign(const char *Callsign) const
|
||||
{
|
||||
return (m_Callsign == Callsign);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: LoadModel
|
||||
* Description: Loads the player's aircraft model.
|
||||
******************************************************************/
|
||||
void MPPlayer::LoadModel(void) {
|
||||
|
||||
|
||||
void
|
||||
MPPlayer::LoadModel (void)
|
||||
{
|
||||
m_ModelTrans = new ssgPlacementTransform;
|
||||
|
||||
// Load the model
|
||||
m_Model = globals->get_model_lib()->load_model( globals->get_fg_root(),
|
||||
m_sModelName,
|
||||
globals->get_props(),
|
||||
globals->get_sim_time_sec() );
|
||||
m_ModelName, globals->get_props(), globals->get_sim_time_sec() );
|
||||
m_Model->clrTraversalMaskBits( SSGTRAV_HOT );
|
||||
|
||||
// Add model to transform
|
||||
m_ModelTrans->addKid( m_Model );
|
||||
|
||||
// Place on scene under aircraft branch
|
||||
globals->get_scenery()->get_aircraft_branch()->addKid( m_ModelTrans );
|
||||
globals->get_scenery()->register_placement_transform( m_ModelTrans);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: FillPosMsg
|
||||
* Description: Populates the header and data for a position message.
|
||||
******************************************************************/
|
||||
void MPPlayer::FillPosMsg(T_MsgHdr *MsgHdr, T_PositionMsg *PosMsg) {
|
||||
|
||||
void
|
||||
MPPlayer::FillPosMsg
|
||||
(
|
||||
T_MsgHdr *MsgHdr,
|
||||
T_PositionMsg *PosMsg
|
||||
)
|
||||
{
|
||||
FillMsgHdr(MsgHdr, POS_DATA_ID);
|
||||
|
||||
strncpy(PosMsg->sModel, m_sModelName.c_str(), MAX_MODEL_NAME_LEN);
|
||||
PosMsg->sModel[MAX_MODEL_NAME_LEN - 1] = '\0';
|
||||
/*
|
||||
sgdCopyVec3(PosMsg->PlayerPosition, m_ModelPosition);
|
||||
sgCopyQuat(PosMsg->PlayerOrientation, m_ModelOrientation);
|
||||
*/
|
||||
strncpy(PosMsg->Model, m_ModelName.c_str(), MAX_MODEL_NAME_LEN);
|
||||
PosMsg->Model[MAX_MODEL_NAME_LEN - 1] = '\0';
|
||||
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]);
|
||||
|
@ -294,17 +284,22 @@ void MPPlayer::FillPosMsg(T_MsgHdr *MsgHdr, T_PositionMsg *PosMsg) {
|
|||
PosMsg->PlayerOrientation[3] = XDR_encode_float (m_ModelOrientation[3]);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: FillMsgHdr
|
||||
* Description: Populates the header of a multiplayer message.
|
||||
******************************************************************/
|
||||
void MPPlayer::FillMsgHdr(T_MsgHdr *MsgHdr, const int iMsgId) {
|
||||
|
||||
void
|
||||
MPPlayer::FillMsgHdr
|
||||
(
|
||||
T_MsgHdr *MsgHdr,
|
||||
const int MsgId
|
||||
)
|
||||
{
|
||||
struct in_addr address;
|
||||
uint32_t len;
|
||||
|
||||
switch (iMsgId) {
|
||||
switch (MsgId)
|
||||
{
|
||||
case CHAT_MSG_ID:
|
||||
len = sizeof(T_MsgHdr) + sizeof(T_ChatMsg);
|
||||
break;
|
||||
|
@ -317,16 +312,14 @@ void MPPlayer::FillMsgHdr(T_MsgHdr *MsgHdr, const int iMsgId) {
|
|||
}
|
||||
MsgHdr->Magic = XDR_encode_uint32 (MSG_MAGIC);
|
||||
MsgHdr->Version = XDR_encode_uint32 (PROTO_VER);
|
||||
MsgHdr->MsgId = XDR_encode_uint32 (iMsgId);
|
||||
MsgHdr->iMsgLen = XDR_encode_uint32 (len);
|
||||
MsgHdr->MsgId = XDR_encode_uint32 (MsgId);
|
||||
MsgHdr->MsgLen = XDR_encode_uint32 (len);
|
||||
// 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);
|
||||
MsgHdr->sCallsign[MAX_CALLSIGN_LEN - 1] = '\0';
|
||||
|
||||
MsgHdr->ReplyAddress = inet_addr( m_PlayerAddress.getHost() );
|
||||
MsgHdr->ReplyPort = XDR_encode_uint32 (m_PlayerAddress.getPort());
|
||||
strncpy(MsgHdr->Callsign, m_Callsign.c_str(), MAX_CALLSIGN_LEN);
|
||||
MsgHdr->Callsign[MAX_CALLSIGN_LEN - 1] = '\0';
|
||||
}
|
||||
|
||||
#endif // FG_MPLAYER_AS
|
||||
|
|
|
@ -52,26 +52,23 @@ SG_USING_STD(string);
|
|||
// Number of seconds before a player is consider to be lost
|
||||
#define TIME_TO_LIVE 10
|
||||
|
||||
|
||||
class ssgEntity;
|
||||
class ssgPlacementTransform;
|
||||
|
||||
|
||||
class MPPlayer {
|
||||
class MPPlayer
|
||||
{
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
MPPlayer();
|
||||
|
||||
/** Destructor. */
|
||||
~MPPlayer();
|
||||
|
||||
/** Enumeration of the states for the player's data */
|
||||
enum PlayerDataState {PLAYER_DATA_NOT_AVAILABLE = 0, PLAYER_DATA_AVAILABLE, PLAYER_DATA_EXPIRED};
|
||||
|
||||
enum PlayerDataState
|
||||
{
|
||||
PLAYER_DATA_NOT_AVAILABLE = 0,
|
||||
PLAYER_DATA_AVAILABLE,
|
||||
PLAYER_DATA_EXPIRED
|
||||
};
|
||||
/** Player data state */
|
||||
typedef enum PlayerDataState TPlayerDataState;
|
||||
|
||||
/** Initialises the class.
|
||||
* @param sIP IP address or host name for sending data to the player
|
||||
* @param sPort Port number for sending data to the player
|
||||
|
@ -80,84 +77,50 @@ public:
|
|||
* @param bLocalPlayer True if this player is the local player, else false
|
||||
* @return True if class opens successfully, else false
|
||||
*/
|
||||
bool Open(const string &sIP, const int &iPort, const string &sCallsign,
|
||||
const string &sModelName, const bool bLocalPlayer);
|
||||
|
||||
bool Open(const string &IP, const int &Port, const string &Callsign,
|
||||
const string &ModelName, const bool LocalPlayer);
|
||||
/** Closes the player connection */
|
||||
void Close(void);
|
||||
|
||||
/** Sets the positioning matrix held for this player
|
||||
* @param PlayerPosMat4 Matrix for positioning player's aircraft
|
||||
*/
|
||||
void SetPosition(const sgQuat PlayerOrientation,
|
||||
const sgdVec3 PlayerPosition);
|
||||
|
||||
/** Transform and place model for player
|
||||
*/
|
||||
TPlayerDataState Draw(void);
|
||||
|
||||
/** Returns the callsign for the player
|
||||
* @return Aircraft's callsign
|
||||
*/
|
||||
string Callsign(void) const;
|
||||
|
||||
/** Compares the player's callsign with the given callsign
|
||||
* @param sCallsign Callsign to compare
|
||||
* @return True if callsign matches
|
||||
*/
|
||||
bool CompareCallsign(const char *sCallsign) const;
|
||||
|
||||
bool CompareCallsign(const char *Callsign) const;
|
||||
/** Populates a position message for the player
|
||||
* @param MsgHdr Header to be populated
|
||||
* @param PosMsg Position message to be populated
|
||||
*/
|
||||
void FillPosMsg(T_MsgHdr *MsgHdr, T_PositionMsg *PosMsg);
|
||||
|
||||
/** Populates a mesage header with information for the player
|
||||
* @param MsgHdr Header to be populated
|
||||
* @param iMsgId Message type identifier to insert into header
|
||||
*/
|
||||
void FillMsgHdr(T_MsgHdr *MsgHdr, const int iMsgId);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/** Loads the model of the aircraft */
|
||||
void LoadModel(void);
|
||||
|
||||
/** True if object is initialised */
|
||||
bool m_bInitialised;
|
||||
|
||||
/** Position of the player's aircraft wrt the earth fixed global system */
|
||||
sgdVec3 m_ModelPosition;
|
||||
|
||||
/** Orientation the player's aircraft wrt the earth fixed global system */
|
||||
sgQuat m_ModelOrientation;
|
||||
|
||||
/** Used to remove player if no activity */
|
||||
time_t m_LastUpdate;
|
||||
|
||||
/** Set when the player data is updated and cleared when read */
|
||||
bool m_bUpdated;
|
||||
|
||||
/** Player's callsign */
|
||||
string m_sCallsign;
|
||||
|
||||
/** Aircraft model name for player */
|
||||
string m_sModelName;
|
||||
|
||||
/** The player's loaded model */
|
||||
ssgEntity *m_Model;
|
||||
|
||||
/** Model transform */
|
||||
ssgPlacementTransform *m_ModelTrans;
|
||||
|
||||
/** True if this player is the local player */
|
||||
bool m_bLocalPlayer;
|
||||
|
||||
/** Address information for the player */
|
||||
netAddress m_PlayerAddress;
|
||||
|
||||
void LoadModel(void); // Loads the model of the aircraft
|
||||
bool m_Initialised; // True if object is initialised
|
||||
sgdVec3 m_ModelPosition; // players global position on earth
|
||||
sgQuat m_ModelOrientation; // players global orientation
|
||||
time_t m_LastUpdate; // last time update data received
|
||||
bool m_Updated; // Set when the player data is updated
|
||||
string m_Callsign; // players callsign
|
||||
bool m_LocalPlayer; // true if player is the local player
|
||||
string m_ModelName; // Aircraft model name for player
|
||||
ssgEntity *m_Model; // The player's loaded model
|
||||
netAddress m_PlayerAddress; // Address information for the player
|
||||
ssgPlacementTransform *m_ModelTrans; // Model transform
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
524
src/MultiPlayer/multiplaymgr.cpp
Normal file
524
src/MultiPlayer/multiplaymgr.cpp
Normal file
|
@ -0,0 +1,524 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// multiplaymgr.hpp
|
||||
//
|
||||
// Written by Duncan McCreanor, started February 2003.
|
||||
// duncan.mccreanor@airservicesaustralia.com
|
||||
//
|
||||
// Copyright (C) 2003 Airservices Australia
|
||||
// Copyright (C) 2005 Oliver Schroeder
|
||||
//
|
||||
// This program 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.
|
||||
//
|
||||
// This program 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 this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
|
||||
#include <sys/types.h>
|
||||
#if !(defined(_MSC_VER) || defined(__MINGW32__))
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#include <plib/netSocket.h>
|
||||
#include <stdlib.h>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include "multiplaymgr.hpp"
|
||||
#include "mpmessages.hxx"
|
||||
#include "mpplayer.hxx"
|
||||
#define MAX_PACKET_SIZE 1024
|
||||
|
||||
// These constants are provided so that the ident
|
||||
// command can list file versions
|
||||
const char sMULTIPLAYMGR_BID[] =
|
||||
"$Id$";
|
||||
const char sMULTIPLAYMGR_HID[] = MULTIPLAYTXMGR_HID;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MultiplayMgr constructor
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
FGMultiplayMgr::FGMultiplayMgr()
|
||||
{
|
||||
m_Initialised = false;
|
||||
m_LocalPlayer = NULL;
|
||||
m_RxAddress = "0";
|
||||
m_RxPort = 0;
|
||||
m_Initialised = false;
|
||||
m_HaveServer = false;
|
||||
} // FGMultiplayMgr::FGMultiplayMgr()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MultiplayMgr destructor
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
FGMultiplayMgr::~FGMultiplayMgr()
|
||||
{
|
||||
Close();
|
||||
} // FGMultiplayMgr::~FGMultiplayMgr()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Initialise object
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
FGMultiplayMgr::init (void)
|
||||
{
|
||||
string TxAddress; // Destination address
|
||||
int TxPort;
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Initialise object if not already done
|
||||
//////////////////////////////////////////////////
|
||||
if (m_Initialised)
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_WARN,
|
||||
"FGMultiplayMgr::init - already initialised" );
|
||||
return (false);
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Set members from property values
|
||||
//////////////////////////////////////////////////
|
||||
TxAddress = fgGetString ("/sim/multiplay/txhost");
|
||||
TxPort = fgGetInt ("/sim/multiplay/txport");
|
||||
m_Callsign = fgGetString ("/sim/multiplay/callsign");
|
||||
m_RxAddress = fgGetString ("/sim/multiplay/rxhost");
|
||||
m_RxPort = fgGetInt ("/sim/multiplay/rxport");
|
||||
if (m_RxPort <= 0)
|
||||
{
|
||||
m_RxPort = 5000;
|
||||
}
|
||||
if (m_Callsign == "")
|
||||
{
|
||||
// FIXME: use getpwuid
|
||||
m_Callsign = "JohnDoe";
|
||||
}
|
||||
if (m_RxAddress == "")
|
||||
{
|
||||
m_RxAddress = "127.0.0.1";
|
||||
}
|
||||
if ((TxPort > 0) && (TxAddress != ""))
|
||||
{
|
||||
m_HaveServer = true;
|
||||
m_Server.set (TxAddress.c_str(), TxPort);
|
||||
}
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-txaddress= "<<TxAddress);
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-txport= "<<TxPort );
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-rxaddress="<<m_RxAddress );
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-rxport= "<<m_RxPort);
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-callsign= "<<m_Callsign);
|
||||
m_DataSocket = new netSocket();
|
||||
if (!m_DataSocket->open(false))
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::init - Failed to create data socket" );
|
||||
return (false);
|
||||
}
|
||||
m_DataSocket->setBlocking(false);
|
||||
m_DataSocket->setBroadcast(true);
|
||||
if (m_DataSocket->bind(m_RxAddress.c_str(), m_RxPort) != 0)
|
||||
{
|
||||
perror("bind");
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::Open - Failed to bind receive socket" );
|
||||
return (false);
|
||||
}
|
||||
m_LocalPlayer = new MPPlayer();
|
||||
if (!m_LocalPlayer->Open(m_RxAddress, m_RxPort, m_Callsign,
|
||||
fgGetString("/sim/model/path"), true))
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::init - Failed to create local player" );
|
||||
return (false);
|
||||
}
|
||||
m_Initialised = true;
|
||||
return (true);
|
||||
} // FGMultiplayMgr::init()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Closes and deletes the local player object. Closes
|
||||
// and deletes the tx socket. Resets the object state to unitialised.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::Close (void)
|
||||
{
|
||||
//////////////////////////////////////////////////
|
||||
// Delete local player
|
||||
//////////////////////////////////////////////////
|
||||
if (m_LocalPlayer)
|
||||
{
|
||||
delete m_LocalPlayer;
|
||||
m_LocalPlayer = NULL;
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Delete any existing players
|
||||
//////////////////////////////////////////////////
|
||||
t_MPClientListIterator CurrentPlayer;
|
||||
t_MPClientListIterator P;
|
||||
CurrentPlayer = m_MPClientList.begin ();
|
||||
while (CurrentPlayer != m_MPClientList.end ())
|
||||
{
|
||||
P = CurrentPlayer;
|
||||
delete (*P);
|
||||
*P = 0;
|
||||
CurrentPlayer = m_MPClientList.erase (P);
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Delete socket
|
||||
//////////////////////////////////////////////////
|
||||
if (m_DataSocket)
|
||||
{
|
||||
m_DataSocket->close();
|
||||
delete m_DataSocket;
|
||||
m_DataSocket = NULL;
|
||||
}
|
||||
m_Initialised = false;
|
||||
} // FGMultiplayMgr::Close(void)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Description: Sends the position data for the local position.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::SendMyPosition
|
||||
(
|
||||
const sgQuat PlayerOrientation,
|
||||
const sgdVec3 PlayerPosition
|
||||
)
|
||||
{
|
||||
T_MsgHdr MsgHdr;
|
||||
T_PositionMsg PosMsg;
|
||||
char Msg[sizeof(T_MsgHdr) + sizeof(T_PositionMsg)];
|
||||
|
||||
if ((! m_Initialised) || (! m_HaveServer))
|
||||
{
|
||||
if (! m_Initialised)
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::SendMyPosition - not initialised" );
|
||||
if (! m_HaveServer)
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::SendMyPosition - no server" );
|
||||
return;
|
||||
}
|
||||
m_LocalPlayer->SetPosition(PlayerOrientation, PlayerPosition);
|
||||
m_LocalPlayer->FillPosMsg(&MsgHdr, &PosMsg);
|
||||
memcpy(Msg, &MsgHdr, sizeof(T_MsgHdr));
|
||||
memcpy(Msg + sizeof(T_MsgHdr), &PosMsg, sizeof(T_PositionMsg));
|
||||
m_DataSocket->sendto (Msg,
|
||||
sizeof(T_MsgHdr) + sizeof(T_PositionMsg), 0, &m_Server);
|
||||
} // FGMultiplayMgr::SendMyPosition()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: SendTextMessage
|
||||
// Description: Sends a message to the player. The message must
|
||||
// contain a valid and correctly filled out header and optional
|
||||
// message body.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::SendTextMessage
|
||||
(
|
||||
const string &MsgText
|
||||
) const
|
||||
{
|
||||
T_MsgHdr MsgHdr;
|
||||
T_ChatMsg ChatMsg;
|
||||
unsigned int iNextBlockPosition = 0;
|
||||
char Msg[sizeof(T_MsgHdr) + sizeof(T_ChatMsg)];
|
||||
|
||||
if ((! m_Initialised) || (! m_HaveServer))
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_LocalPlayer->FillMsgHdr(&MsgHdr, CHAT_MSG_ID);
|
||||
//////////////////////////////////////////////////
|
||||
// Divide the text string into blocks that fit
|
||||
// in the message and send the blocks.
|
||||
//////////////////////////////////////////////////
|
||||
while (iNextBlockPosition < MsgText.length())
|
||||
{
|
||||
strncpy (ChatMsg.Text,
|
||||
MsgText.substr(iNextBlockPosition, MAX_CHAT_MSG_LEN - 1).c_str(),
|
||||
MAX_CHAT_MSG_LEN);
|
||||
ChatMsg.Text[MAX_CHAT_MSG_LEN - 1] = '\0';
|
||||
memcpy (Msg, &MsgHdr, sizeof(T_MsgHdr));
|
||||
memcpy (Msg + sizeof(T_MsgHdr), &ChatMsg, sizeof(T_ChatMsg));
|
||||
m_DataSocket->sendto (Msg,
|
||||
sizeof(T_MsgHdr) + sizeof(T_ChatMsg), 0, &m_Server);
|
||||
iNextBlockPosition += MAX_CHAT_MSG_LEN - 1;
|
||||
}
|
||||
} // FGMultiplayMgr::SendTextMessage ()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: ProcessData
|
||||
// Description: Processes data waiting at the receive socket. The
|
||||
// processing ends when there is no more data at the socket.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::ProcessData (void)
|
||||
{
|
||||
char Msg[MAX_PACKET_SIZE]; // Buffer for received message
|
||||
int Bytes; // Bytes received
|
||||
T_MsgHdr* MsgHdr; // Pointer to header in received data
|
||||
netAddress SenderAddress;
|
||||
|
||||
if (! m_Initialised)
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::ProcessData - not initialised" );
|
||||
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.
|
||||
//////////////////////////////////////////////////
|
||||
Bytes = m_DataSocket->recvfrom (Msg, MAX_PACKET_SIZE, 0,
|
||||
&SenderAddress);
|
||||
//////////////////////////////////////////////////
|
||||
// no Data received
|
||||
//////////////////////////////////////////////////
|
||||
if (Bytes <= 0)
|
||||
{
|
||||
if (errno != EAGAIN)
|
||||
{
|
||||
perror("FGMultiplayMgr::MP_ProcessData");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (Bytes <= (int)sizeof(MsgHdr))
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "received message with insufficient data" );
|
||||
return;
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Read header
|
||||
//////////////////////////////////////////////////
|
||||
MsgHdr = (T_MsgHdr *)Msg;
|
||||
MsgHdr->Magic = XDR_decode_uint32 (MsgHdr->Magic);
|
||||
MsgHdr->Version = XDR_decode_uint32 (MsgHdr->Version);
|
||||
MsgHdr->MsgId = XDR_decode_uint32 (MsgHdr->MsgId);
|
||||
MsgHdr->MsgLen = XDR_decode_uint32 (MsgHdr->MsgLen);
|
||||
MsgHdr->ReplyPort = XDR_decode_uint32 (MsgHdr->ReplyPort);
|
||||
if (MsgHdr->Magic != MSG_MAGIC)
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "message has invalid magic number!" );
|
||||
}
|
||||
if (MsgHdr->Version != PROTO_VER)
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "message has invalid protocoll number!" );
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Process the player data unless we generated it
|
||||
//////////////////////////////////////////////////
|
||||
if (m_Callsign == MsgHdr->Callsign)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Process messages
|
||||
//////////////////////////////////////////////////
|
||||
switch(MsgHdr->MsgId)
|
||||
{
|
||||
case CHAT_MSG_ID:
|
||||
ProcessChatMsg ((char*) & Msg, SenderAddress);
|
||||
break;
|
||||
case POS_DATA_ID:
|
||||
ProcessPosMsg ((char*) & Msg, SenderAddress);
|
||||
break;
|
||||
default:
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "Unknown message Id received: "
|
||||
<< MsgHdr->MsgId );
|
||||
break;
|
||||
} // switch
|
||||
} while (Bytes > 0);
|
||||
} // FGMultiplayMgr::ProcessData(void)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// handle a position message
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::ProcessPosMsg
|
||||
(
|
||||
const char *Msg,
|
||||
netAddress & SenderAddress
|
||||
)
|
||||
{
|
||||
T_PositionMsg* PosMsg; // Pointer to position message in received data
|
||||
T_MsgHdr* MsgHdr; // Pointer to header in received data
|
||||
bool ActivePlayer;
|
||||
sgQuat Orientation;
|
||||
sgdVec3 Position;
|
||||
struct in_addr PlayerAddress;
|
||||
t_MPClientListIterator CurrentPlayer;
|
||||
int iPlayerCnt;
|
||||
char *sIpAddress;
|
||||
|
||||
ActivePlayer = false;
|
||||
MsgHdr = (T_MsgHdr *)Msg;
|
||||
if (MsgHdr->MsgLen != sizeof(T_MsgHdr) + sizeof(T_PositionMsg))
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::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 (CurrentPlayer = m_MPClientList.begin ();
|
||||
CurrentPlayer != m_MPClientList.end ();
|
||||
CurrentPlayer++)
|
||||
{
|
||||
if ((*CurrentPlayer)->CompareCallsign(MsgHdr->Callsign))
|
||||
{
|
||||
// Player found. Update the data for the player.
|
||||
(*CurrentPlayer)->SetPosition(Orientation, Position);
|
||||
ActivePlayer = true;
|
||||
}
|
||||
} // for (...)
|
||||
if (ActivePlayer)
|
||||
{ // nothing more to do
|
||||
return;
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Player not active, so add as new player
|
||||
//////////////////////////////////////////////////
|
||||
MPPlayer* NewPlayer;
|
||||
NewPlayer = new MPPlayer;
|
||||
NewPlayer->Open(SenderAddress.getHost(), MsgHdr->ReplyPort,
|
||||
MsgHdr->Callsign, PosMsg->Model, false);
|
||||
NewPlayer->SetPosition(Orientation, Position);
|
||||
m_MPClientList.push_back (NewPlayer);
|
||||
} // FGMultiplayMgr::ProcessPosMsg()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// handle a chat message
|
||||
// FIXME: display chat message withi flightgear
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::ProcessChatMsg
|
||||
(
|
||||
const char *Msg,
|
||||
netAddress & SenderAddress
|
||||
)
|
||||
{
|
||||
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->MsgLen != sizeof(T_MsgHdr) + sizeof(T_ChatMsg))
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "Chat message received with insufficient data" );
|
||||
return;
|
||||
}
|
||||
ChatMsg = (T_ChatMsg *)(Msg + sizeof(T_MsgHdr));
|
||||
SG_LOG ( SG_NETWORK, SG_ALERT,
|
||||
"Chat [" << MsgHdr->Callsign << "]" << " " << ChatMsg->Text << endl);
|
||||
} // FGMultiplayMgr::ProcessChatMsg ()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// For each active player, tell the player object
|
||||
// to update its position on the scene. If a player object
|
||||
// returns status information indicating that it has not
|
||||
// had an update for some time then the player is deleted.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::Update (void)
|
||||
{
|
||||
MPPlayer::TPlayerDataState ePlayerDataState;
|
||||
t_MPClientListIterator CurrentPlayer;
|
||||
|
||||
CurrentPlayer = m_MPClientList.begin ();
|
||||
while (CurrentPlayer != m_MPClientList.end ())
|
||||
{
|
||||
ePlayerDataState = (*CurrentPlayer)->Draw();
|
||||
//////////////////////////////////////////////////
|
||||
// If the player has not received an update for
|
||||
// some time then assume that the player has quit.
|
||||
//////////////////////////////////////////////////
|
||||
if (ePlayerDataState == MPPlayer::PLAYER_DATA_EXPIRED)
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayMgr::Update - "
|
||||
<< "Deleting player from game. Callsign: "
|
||||
<< (*CurrentPlayer)->Callsign() );
|
||||
t_MPClientListIterator P;
|
||||
P = CurrentPlayer;
|
||||
delete (*P);
|
||||
*P = 0;
|
||||
CurrentPlayer = m_MPClientList.erase (P);
|
||||
}
|
||||
else CurrentPlayer++;
|
||||
}
|
||||
} // FGMultiplayMgr::Update()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // FG_MPLAYER_AS
|
||||
|
85
src/MultiPlayer/multiplaymgr.hpp
Normal file
85
src/MultiPlayer/multiplaymgr.hpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// multiplaymgr.hpp
|
||||
//
|
||||
// Written by Duncan McCreanor, started February 2003.
|
||||
// duncan.mccreanor@airservicesaustralia.com
|
||||
//
|
||||
// Copyright (C) 2003 Airservices Australia
|
||||
// Copyright (C) 2005 Oliver Schroeder
|
||||
//
|
||||
// This program 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.
|
||||
//
|
||||
// This program 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 this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef MULTIPLAYMGR_H
|
||||
#define MULTIPLAYMGR_H
|
||||
|
||||
#define MULTIPLAYTXMGR_HID "$Id$"
|
||||
|
||||
#include "mpplayer.hxx"
|
||||
#include "mpmessages.hxx"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include STL_STRING
|
||||
SG_USING_STD(string);
|
||||
#include <vector>
|
||||
SG_USING_STD(vector);
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <plib/netSocket.h>
|
||||
#include <Main/globals.hxx>
|
||||
|
||||
// Maximum number of players that can exist at any time
|
||||
// FIXME: use a list<mplayer> instead
|
||||
#define MAX_PLAYERS 10
|
||||
|
||||
class FGMultiplayMgr
|
||||
{
|
||||
public:
|
||||
FGMultiplayMgr();
|
||||
~FGMultiplayMgr();
|
||||
bool init(void);
|
||||
void Close(void);
|
||||
// transmitter
|
||||
void SendMyPosition (const sgQuat PlayerOrientation,
|
||||
const sgdVec3 PlayerPosition);
|
||||
void SendTextMessage (const string &sMsgText) const;
|
||||
// receiver
|
||||
void ProcessData(void);
|
||||
void ProcessPosMsg ( const char *Msg, netAddress & SenderAddress );
|
||||
void ProcessChatMsg ( const char *Msg, netAddress & SenderAddress );
|
||||
void Update(void);
|
||||
private:
|
||||
typedef vector<MPPlayer*> t_MPClientList;
|
||||
typedef t_MPClientList::iterator t_MPClientListIterator;
|
||||
MPPlayer* m_LocalPlayer;
|
||||
netSocket* m_DataSocket;
|
||||
netAddress m_Server;
|
||||
bool m_HaveServer;
|
||||
bool m_Initialised;
|
||||
t_MPClientList m_MPClientList;
|
||||
string m_RxAddress;
|
||||
int m_RxPort;
|
||||
string m_Callsign;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,400 +0,0 @@
|
|||
// multiplayrxmgr.cxx -- routines for receiving multiplayer data
|
||||
// for Flightgear
|
||||
//
|
||||
// Written by Duncan McCreanor, started February 2003.
|
||||
// duncan.mccreanor@airservicesaustralia.com
|
||||
//
|
||||
// Copyright (C) 2003 Airservices Australia
|
||||
//
|
||||
// This program 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.
|
||||
//
|
||||
// This program 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 this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
|
||||
/******************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Description: The multiplayer rx manager provides control over
|
||||
* multiplayer data reception and processing for an interactive
|
||||
* multiplayer FlightGear simulation.
|
||||
*
|
||||
* The objects that hold player information are accessed via
|
||||
* a fixed size array. A fixed array is used since it provides
|
||||
* speed benefits over working with linked lists and is easier
|
||||
* to code. Also, there is no point allowing for an unlimited
|
||||
* number of players as too many players will slow the game
|
||||
* down to the point where it is unplayable.
|
||||
*
|
||||
* When player position data is received, the callsign of
|
||||
* the player is checked against existing players. If the
|
||||
* player does not exist, a new player is created in the
|
||||
* next free slot of the player array. If the player does
|
||||
* exist, the player's positional matrix is updated.
|
||||
*
|
||||
* The Update method is used to move the players on the
|
||||
* scene. The return value from calling MPPlayer::Draw
|
||||
* indicates the state of the player. If data for a player
|
||||
* has not been received data for some time, the player object
|
||||
* is deleted and the array element freed.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
#if !(defined(_MSC_VER) || defined(__MINGW32__))
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#include <plib/netSocket.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#include "multiplayrxmgr.hxx"
|
||||
#include "mpmessages.hxx"
|
||||
#include "mpplayer.hxx"
|
||||
|
||||
#define MAX_PACKET_SIZE 1024
|
||||
|
||||
// These constants are provided so that the ident command can list file versions.
|
||||
const char sMULTIPLAYTXMGR_BID[] = "$Id$";
|
||||
const char sMULTIPLAYRXMGR_HID[] = MULTIPLAYRXMGR_HID;
|
||||
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: FGMultiplayRxMgr
|
||||
* Description: Constructor.
|
||||
******************************************************************/
|
||||
FGMultiplayRxMgr::FGMultiplayRxMgr() {
|
||||
|
||||
int iPlayerCnt; // Count of players in player array
|
||||
|
||||
// Initialise private members
|
||||
m_sRxAddress = "0";
|
||||
m_iRxPort = 0;
|
||||
m_bInitialised = false;
|
||||
|
||||
// Clear the player array
|
||||
for (iPlayerCnt = 0; iPlayerCnt < MAX_PLAYERS; iPlayerCnt++) {
|
||||
m_Player[iPlayerCnt] = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: ~FGMultiplayRxMgr
|
||||
* Description: Destructor. Closes and deletes objects owned by
|
||||
* this object.
|
||||
******************************************************************/
|
||||
FGMultiplayRxMgr::~FGMultiplayRxMgr() {
|
||||
|
||||
Close();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: init
|
||||
* Description: Initialises multiplayer receive.
|
||||
******************************************************************/
|
||||
bool FGMultiplayRxMgr::init(void) {
|
||||
|
||||
bool bSuccess = true; // Result of initialisation
|
||||
|
||||
// Initialise object if not already done
|
||||
if (!m_bInitialised) {
|
||||
|
||||
// Set members from property values
|
||||
m_sCallsign = fgGetString("/sim/multiplay/callsign");
|
||||
m_sRxAddress = fgGetString("/sim/multiplay/rxhost");
|
||||
m_iRxPort = fgGetInt("/sim/multiplay/rxport");
|
||||
|
||||
SG_LOG( SG_NETWORK, SG_INFO, "FGMultiplayRxMgr::init - rxaddress= "
|
||||
<< m_sRxAddress );
|
||||
SG_LOG( SG_NETWORK, SG_INFO, "FGMultiplayRxMgr::init - rxport= "
|
||||
<< m_iRxPort);
|
||||
SG_LOG( SG_NETWORK, SG_INFO, "FGMultiplayRxMgr::init - callsign= "
|
||||
<< m_sCallsign );
|
||||
|
||||
|
||||
// Create and open rx socket
|
||||
mDataRxSocket = new netSocket();
|
||||
if (!mDataRxSocket->open(false)) {
|
||||
// Failed to open rx socket
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayRxMgr::Open - Failed to create data receive socket" );
|
||||
bSuccess = false;
|
||||
} else {
|
||||
|
||||
// Configure the socket
|
||||
mDataRxSocket->setBlocking(false);
|
||||
mDataRxSocket->setBroadcast(true);
|
||||
if (mDataRxSocket->bind(m_sRxAddress.c_str(), m_iRxPort) != 0) {
|
||||
perror("bind");
|
||||
// Failed to bind
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayRxMgr::Open - Failed to bind receive socket" );
|
||||
bSuccess = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Save manager state
|
||||
m_bInitialised = bSuccess;
|
||||
|
||||
} else {
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayRxMgr::OpenRx - Receiver open requested when receiver is already open" );
|
||||
bSuccess = false;
|
||||
}
|
||||
|
||||
/* Return true if open succeeds */
|
||||
return bSuccess;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: Close
|
||||
* Description: Closes and deletes and player connections. Closes
|
||||
* and deletes the rx socket. Resets the object state
|
||||
* to unitialised.
|
||||
******************************************************************/
|
||||
void FGMultiplayRxMgr::Close(void) {
|
||||
|
||||
int iPlayerCnt; // Count of players in player array
|
||||
|
||||
// Delete any existing players
|
||||
for (iPlayerCnt = 0; iPlayerCnt < MAX_PLAYERS; iPlayerCnt++) {
|
||||
if (m_Player[iPlayerCnt] != NULL) {
|
||||
delete m_Player[iPlayerCnt];
|
||||
m_Player[iPlayerCnt] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete socket
|
||||
if (mDataRxSocket) {
|
||||
mDataRxSocket->close();
|
||||
delete mDataRxSocket;
|
||||
mDataRxSocket = NULL;
|
||||
}
|
||||
|
||||
m_bInitialised = false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: ProcessData
|
||||
* Description: Processes data waiting at the receive socket. The
|
||||
* processing ends when there is no more data at the socket.
|
||||
******************************************************************/
|
||||
void FGMultiplayRxMgr::ProcessData(void) {
|
||||
|
||||
char sMsg[MAX_PACKET_SIZE]; // Buffer for received message
|
||||
int iBytes; // Bytes received
|
||||
T_MsgHdr *MsgHdr; // Pointer to header in received data
|
||||
|
||||
|
||||
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);
|
||||
|
||||
// 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
|
||||
* Description: For each active player, tell the player object
|
||||
* to update its position on the scene. If a player object
|
||||
* returns status information indicating that it has not
|
||||
* had an update for some time then the player is deleted.
|
||||
******************************************************************/
|
||||
void FGMultiplayRxMgr::Update(void) {
|
||||
|
||||
MPPlayer::TPlayerDataState ePlayerDataState;
|
||||
int iPlayerId;
|
||||
|
||||
for (iPlayerId = 0; iPlayerId < MAX_PLAYERS; iPlayerId++) {
|
||||
if (m_Player[iPlayerId] != NULL) {
|
||||
ePlayerDataState = m_Player[iPlayerId]->Draw();
|
||||
|
||||
// If the player has not received an update for some
|
||||
// time then assume that the player has quit.
|
||||
if (ePlayerDataState == MPPlayer::PLAYER_DATA_EXPIRED) {
|
||||
SG_LOG( SG_NETWORK, SG_BULK, "FGMultiplayRxMgr::Update - Deleting player from game. Callsign: "
|
||||
<< m_Player[iPlayerId]->Callsign() );
|
||||
delete m_Player[iPlayerId];
|
||||
m_Player[iPlayerId] = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // FG_MPLAYER_AS
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
// multiplayrxmgr.hxx -- routines for receiving multiplayer data
|
||||
// for Flghtgear
|
||||
//
|
||||
// Written by Duncan McCreanor, started February 2003.
|
||||
// duncan.mccreanor@airservicesaustralia.com
|
||||
//
|
||||
// Copyright (C) 2003 Airservices Australia
|
||||
//
|
||||
// This program 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.
|
||||
//
|
||||
// This program 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 this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
|
||||
#ifndef MULTIPLAYRXMGR_H
|
||||
#define MULTIPLAYRXMGR_H
|
||||
|
||||
#define MULTIPLAYRXMGR_HID "$Id$"
|
||||
|
||||
|
||||
#include "mpplayer.hxx"
|
||||
#include "mpmessages.hxx"
|
||||
|
||||
#include STL_STRING
|
||||
SG_USING_STD(string);
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <plib/netSocket.h>
|
||||
|
||||
// Maximum number of players that can exist at any time
|
||||
#define MAX_PLAYERS 10
|
||||
|
||||
/****************************************************************
|
||||
* @version $Id$
|
||||
*
|
||||
* Description: The multiplay rx manager is responsible for
|
||||
* receiving and processing data from other players.
|
||||
|
||||
* Data from remote players is read from the network and processed
|
||||
* via calling ProcessData. The models for the remote player are
|
||||
* positioned onto the scene by calling Update.
|
||||
*
|
||||
*******************************************************************/
|
||||
class FGMultiplayRxMgr {
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
FGMultiplayRxMgr();
|
||||
|
||||
/** Destructor. */
|
||||
~FGMultiplayRxMgr();
|
||||
|
||||
/** Initialises the multiplayer receiver.
|
||||
* @return True if initialisation succeeds, else false
|
||||
*/
|
||||
bool init(void);
|
||||
|
||||
/** Initiates processing of any data waiting at the rx socket.
|
||||
*/
|
||||
void ProcessData(void);
|
||||
void ProcessPosMsg ( const char *Msg );
|
||||
void ProcessChatMsg ( const char *Msg );
|
||||
|
||||
/** Updates the model positions for the players
|
||||
*/
|
||||
void Update(void);
|
||||
|
||||
/** Closes the multiplayer manager. Stops any further player packet processing.
|
||||
*/
|
||||
void Close(void);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
/** Holds the players that exist in the game */
|
||||
MPPlayer *m_Player[MAX_PLAYERS];
|
||||
|
||||
/** Socket for receiving data from the server or another player */
|
||||
netSocket *mDataRxSocket;
|
||||
|
||||
/** True if multiplay receive is initialised */
|
||||
bool m_bInitialised;
|
||||
|
||||
/** Receive address for multiplayer messages */
|
||||
string m_sRxAddress;
|
||||
|
||||
/** Receive port for multiplayer messages */
|
||||
int m_iRxPort;
|
||||
|
||||
/** Local player's callsign */
|
||||
string m_sCallsign;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -1,246 +0,0 @@
|
|||
// multiplaytxmgr.cxx -- routines for transmitting multiplayer data
|
||||
// for Flightgear
|
||||
//
|
||||
// Written by Duncan McCreanor, started February 2003.
|
||||
// duncan.mccreanor@airservicesaustralia.com
|
||||
//
|
||||
// Copyright (C) 2003 Airservices Australia
|
||||
//
|
||||
// This program 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.
|
||||
//
|
||||
// This program 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 this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
|
||||
/******************************************************************
|
||||
* $Id$
|
||||
*
|
||||
* Description: The multiplayer tx manager provides is used
|
||||
* to send data to another player or a server for an
|
||||
* interactive multiplayer FlightGear simulation.
|
||||
*
|
||||
******************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
#if !(defined(_MSC_VER) || defined(__MINGW32__))
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#include <plib/netSocket.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#include "multiplaytxmgr.hxx"
|
||||
#include "mpmessages.hxx"
|
||||
#include "mpplayer.hxx"
|
||||
|
||||
// These constants are provided so that the ident command can list file versions.
|
||||
const char sMULTIPLAYTXMGR_BID[] = "$Id$";
|
||||
const char sMULTIPLAYTXMGR_HID[] = MULTIPLAYTXMGR_HID;
|
||||
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: FGMultiplayTxMgr
|
||||
* Description: Constructor.
|
||||
******************************************************************/
|
||||
FGMultiplayTxMgr::FGMultiplayTxMgr() {
|
||||
|
||||
// int iPlayerCnt; // Count of players in player array
|
||||
|
||||
// Initialise private members
|
||||
m_bInitialised = false;
|
||||
mLocalPlayer = NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: ~FGMultiplayTxMgr
|
||||
* Description: Destructor. Closes and deletes objects owned by
|
||||
* this object.
|
||||
******************************************************************/
|
||||
FGMultiplayTxMgr::~FGMultiplayTxMgr() {
|
||||
|
||||
Close();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: init
|
||||
* Description: Initialises multiplayer transmit
|
||||
******************************************************************/
|
||||
bool FGMultiplayTxMgr::init(void) {
|
||||
|
||||
|
||||
string sTxAddress; // Destination address
|
||||
int iTxPort;
|
||||
bool bSuccess = true; // Result of initialisation
|
||||
|
||||
// Initialise object if not already done
|
||||
if (!m_bInitialised) {
|
||||
|
||||
// Set members from property values
|
||||
string sTxAddress = fgGetString("/sim/multiplay/txhost");
|
||||
iTxPort = fgGetInt("/sim/multiplay/txport");
|
||||
|
||||
SG_LOG( SG_NETWORK, SG_INFO, "FGMultiplayTxMgr::init - txaddress= "
|
||||
<< sTxAddress );
|
||||
SG_LOG( SG_NETWORK, SG_INFO, "FGMultiplayTxMgr::init - txport= "
|
||||
<< iTxPort );
|
||||
|
||||
if (iTxPort > 0) {
|
||||
|
||||
|
||||
// Create and open tx socket
|
||||
mDataTxSocket = new netSocket();
|
||||
if (!mDataTxSocket->open(false)) {
|
||||
// Failed to open tx socket
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayTxMgr::init - Failed to create data transmit socket" );
|
||||
bSuccess = false;
|
||||
} else {
|
||||
mDataTxSocket->setBroadcast(true);
|
||||
if (mDataTxSocket->connect(sTxAddress.c_str(), iTxPort) != 0) {
|
||||
// Failed to connect tx socket
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayTxMgr::init - Failed to connect data transmit socket" );
|
||||
bSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a player object for the local player
|
||||
if (bSuccess) {
|
||||
mLocalPlayer = new MPPlayer();
|
||||
if (!mLocalPlayer->Open(fgGetString("/sim/multiplay/rxhost"), fgGetInt("/sim/multiplay/rxport"),
|
||||
fgGetString("/sim/multiplay/callsign"), fgGetString("/sim/model/path"), true)) {
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayTxMgr::init - Failed to create player object for local player" );
|
||||
bSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If Tx port == zero then don't initialise
|
||||
} else {
|
||||
|
||||
SG_LOG( SG_NETWORK, SG_INFO, "FGMultiplayTxMgr::init - Tx Port is zero. Multiplay out disabled." );
|
||||
bSuccess = false;
|
||||
|
||||
}
|
||||
|
||||
// Save manager state
|
||||
m_bInitialised = bSuccess;
|
||||
|
||||
} else {
|
||||
SG_LOG( SG_NETWORK, SG_WARN, "FGMultiplayTxMgr::init - Attempt to init object that is already opened" );
|
||||
bSuccess = false;
|
||||
}
|
||||
|
||||
|
||||
/* Return true if init succeeds */
|
||||
return bSuccess;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: Close
|
||||
* Description: Closes and deletes the local player object. Closes
|
||||
* and deletes the tx socket. Resets the object state to unitialised.
|
||||
******************************************************************/
|
||||
void FGMultiplayTxMgr::Close(void) {
|
||||
|
||||
|
||||
// Delete local player
|
||||
if (mLocalPlayer) {
|
||||
delete mLocalPlayer;
|
||||
mLocalPlayer = NULL;
|
||||
}
|
||||
|
||||
// Delete socket
|
||||
if (mDataTxSocket) {
|
||||
mDataTxSocket->close();
|
||||
delete mDataTxSocket;
|
||||
mDataTxSocket = NULL;
|
||||
}
|
||||
|
||||
m_bInitialised = false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: SendMyPosition
|
||||
* Description: Sends the position data for the local position.
|
||||
******************************************************************/
|
||||
void FGMultiplayTxMgr::SendMyPosition(const sgQuat PlayerOrientation,
|
||||
const sgdVec3 PlayerPosition) {
|
||||
|
||||
T_MsgHdr MsgHdr;
|
||||
T_PositionMsg PosMsg;
|
||||
char sMsg[sizeof(T_MsgHdr) + sizeof(T_PositionMsg)];
|
||||
|
||||
if (m_bInitialised) {
|
||||
mLocalPlayer->SetPosition(PlayerOrientation, PlayerPosition);
|
||||
mLocalPlayer->FillPosMsg(&MsgHdr, &PosMsg);
|
||||
memcpy(sMsg, &MsgHdr, sizeof(T_MsgHdr));
|
||||
memcpy(sMsg + sizeof(T_MsgHdr), &PosMsg, sizeof(T_PositionMsg));
|
||||
mDataTxSocket->send(sMsg, sizeof(T_MsgHdr) + sizeof(T_PositionMsg), 0);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Name: SendTextMessage
|
||||
* Description: Sends a message to the player. The message must
|
||||
* contain a valid and correctly filled out header and optional
|
||||
* message body.
|
||||
******************************************************************/
|
||||
void FGMultiplayTxMgr::SendTextMessage(const string &sMsgText) const {
|
||||
|
||||
// bool bResult = false;
|
||||
T_MsgHdr MsgHdr;
|
||||
T_ChatMsg ChatMsg;
|
||||
unsigned int iNextBlockPosition = 0;
|
||||
char sMsg[sizeof(T_MsgHdr) + sizeof(T_ChatMsg)];
|
||||
|
||||
if (m_bInitialised) {
|
||||
|
||||
mLocalPlayer->FillMsgHdr(&MsgHdr, CHAT_MSG_ID);
|
||||
|
||||
// Divide the text string into blocks that fit in the message
|
||||
// and send the blocks.
|
||||
while (iNextBlockPosition < sMsgText.length()) {
|
||||
strncpy(ChatMsg.sText, sMsgText.substr(iNextBlockPosition, MAX_CHAT_MSG_LEN - 1).c_str(), MAX_CHAT_MSG_LEN);
|
||||
ChatMsg.sText[MAX_CHAT_MSG_LEN - 1] = '\0';
|
||||
memcpy(sMsg, &MsgHdr, sizeof(T_MsgHdr));
|
||||
memcpy(sMsg + sizeof(T_MsgHdr), &ChatMsg, sizeof(T_ChatMsg));
|
||||
mDataTxSocket->send(sMsg, sizeof(T_MsgHdr) + sizeof(T_ChatMsg), 0);
|
||||
iNextBlockPosition += MAX_CHAT_MSG_LEN - 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // FG_MPLAYER_AS
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
// multiplaytxmgr.hxx -- routines for transmitting multiplayer data
|
||||
// for Flghtgear
|
||||
//
|
||||
// Written by Duncan McCreanor, started February 2003.
|
||||
// duncan.mccreanor@airservicesaustralia.com
|
||||
//
|
||||
// Copyright (C) 2003 Airservices Australia
|
||||
//
|
||||
// This program 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.
|
||||
//
|
||||
// This program 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 this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
|
||||
#ifndef MULTIPLAYTXMGR_H
|
||||
#define MULTIPLAYTXMGR_H
|
||||
|
||||
#define MULTIPLAYTXMGR_HID "$Id$"
|
||||
|
||||
|
||||
#include "mpplayer.hxx"
|
||||
#include "mpmessages.hxx"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include STL_STRING
|
||||
SG_USING_STD(string);
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <plib/netSocket.h>
|
||||
|
||||
// Maximum number of players that can exist at any time
|
||||
#define MAX_PLAYERS 10
|
||||
|
||||
/****************************************************************
|
||||
* @version $Id$
|
||||
*
|
||||
* Description: The multiplay tx manager is responsible for
|
||||
* sending data to another player or a multiplayer server.
|
||||
*
|
||||
* The position information for the local player is transmitted
|
||||
* on each call to SendMyPosition.
|
||||
*
|
||||
*******************************************************************/
|
||||
class FGMultiplayTxMgr {
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
FGMultiplayTxMgr();
|
||||
|
||||
/** Destructor. */
|
||||
~FGMultiplayTxMgr();
|
||||
|
||||
/** Initialises the multiplayer transmitter.
|
||||
* @return True if initialisation succeeds, else false
|
||||
*/
|
||||
bool init(void);
|
||||
|
||||
/** Sends the position data for the local player
|
||||
* @param PlayerPosMat4 Transformation matrix for the player's position
|
||||
*/
|
||||
void SendMyPosition(const sgQuat PlayerOrientation, const sgdVec3 PlayerPosition);
|
||||
|
||||
/** Sends a tex chat message.
|
||||
* @param sMsgText Message text to send
|
||||
*/
|
||||
void SendTextMessage(const string &sMsgText) const;
|
||||
|
||||
/** Closes the multiplayer manager. Stops any further player packet processing.
|
||||
*/
|
||||
void Close(void);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/** The local player */
|
||||
MPPlayer *mLocalPlayer;
|
||||
|
||||
/** Socket for sending to the server or another player if playing point to point */
|
||||
netSocket *mDataTxSocket;
|
||||
|
||||
/** True if multiplay transmit is initialised */
|
||||
bool m_bInitialised;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// Tiny XDR implementation for flightgear
|
||||
// written by Oliver Schroeder
|
||||
// released to the puiblic domain
|
||||
// released to the public domain
|
||||
//
|
||||
// This implementation is not complete, but implements
|
||||
// everything we need.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// Tiny XDR implementation for flightgear
|
||||
// written by Oliver Schroeder
|
||||
// released to the puiblic domain
|
||||
// released to the public domain
|
||||
//
|
||||
// This implementation is not complete, but implements
|
||||
// everything we need.
|
||||
|
|
|
@ -107,7 +107,7 @@ bool FGMultiplay::process() {
|
|||
|
||||
if (get_direction() == SG_IO_IN) {
|
||||
|
||||
globals->get_multiplayer_rx_mgr()->ProcessData();
|
||||
globals->get_multiplayer_mgr()->ProcessData();
|
||||
|
||||
} else if (get_direction() == SG_IO_OUT) {
|
||||
|
||||
|
@ -120,7 +120,7 @@ bool FGMultiplay::process() {
|
|||
sgQuat PlayerOrientation;
|
||||
sgMatrixToQuat(PlayerOrientation, posTrans);
|
||||
|
||||
globals->get_multiplayer_tx_mgr()->SendMyPosition(PlayerOrientation, PlayerPosition);
|
||||
globals->get_multiplayer_mgr()->SendMyPosition(PlayerOrientation, PlayerPosition);
|
||||
|
||||
}
|
||||
|
||||
|
@ -137,11 +137,11 @@ bool FGMultiplay::close() {
|
|||
|
||||
if (get_direction() == SG_IO_IN) {
|
||||
|
||||
globals->get_multiplayer_rx_mgr()->Close();
|
||||
globals->get_multiplayer_mgr()->Close();
|
||||
|
||||
} else if (get_direction() == SG_IO_OUT) {
|
||||
|
||||
globals->get_multiplayer_tx_mgr()->Close();
|
||||
// globals->get_multiplayer_mgr()->Close();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -34,8 +34,7 @@
|
|||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Model/acmodel.hxx>
|
||||
#include <MultiPlayer/multiplaytxmgr.hxx>
|
||||
#include <MultiPlayer/multiplayrxmgr.hxx>
|
||||
#include <MultiPlayer/multiplaymgr.hpp>
|
||||
|
||||
#include "protocol.hxx"
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue