1
0
Fork 0

Oliver Schroeder:

This is mainly an intermediate patch. I've restructured the network code.
This commit is contained in:
ehofman 2005-10-30 18:01:51 +00:00
parent bc703b2bd3
commit eed55b48b7
17 changed files with 780 additions and 1085 deletions

View file

@ -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
////////////////////////////////////////////////////////////////////////

View file

@ -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 () {

View file

@ -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

View file

@ -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

View file

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

View file

@ -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

View file

@ -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

View 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

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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.

View file

@ -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();
}

View file

@ -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"