+// mpmessages.hxx -- Message definitions for multiplayer communications
+// within a multiplayer 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.
+//
+
#ifndef MPMESSAGES_H
#define MPMESSAGES_H
# include <arpa/inet.h>
#endif
#include <plib/netSocket.h>
+#include <plib/sg.h>
#include <Main/globals.hxx>
#include <Model/loader.hxx>
m_bInitialised = false;
m_LastUpdate = 0;
m_PlayerAddress.set("localhost", 0);
+ m_sCallsign = "none";
}
******************************************************************/
void MPPlayer::Close(void) {
-
// Remove the model from the game
- if (!m_bLocalPlayer) {
- globals->get_scenery()->get_scene_graph()->removeKid(m_ModelSel);
+ if (m_bInitialised && !m_bLocalPlayer) {
+
+ // Disconnect the model from the transform, then the transform from the scene.
+ m_ModelTrans->removeKid(m_Model);
+ 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_loader()->flush();
+
+ // 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";
}
// Save the position matrix and update time
if (m_bInitialised) {
- memcpy(m_ModelPos, PlayerPosMat4, sizeof(sgMat4));
+ sgCopyMat4(m_ModelPos, PlayerPosMat4);
time(&m_LastUpdate);
m_bUpdated = true;
}
/******************************************************************
* Name: Draw
* Description: Updates the position for the player's model
-* The state of the player (old, initialised etc)
-* is returned.
+* The state of the player's data is returned.
******************************************************************/
-int MPPlayer::Draw(void) {
+MPPlayer::TPlayerDataState MPPlayer::Draw(void) {
- int iResult = PLAYER_DATA_NOT_AVAILABLE;
+ MPPlayer::TPlayerDataState eResult = PLAYER_DATA_NOT_AVAILABLE;
sgCoord sgPlayerCoord;
- if (m_bInitialised) {
+ if (m_bInitialised && !m_bLocalPlayer) {
if ((time(NULL) - m_LastUpdate < TIME_TO_LIVE)) {
// Peform an update if it has changed since the last update
if (m_bUpdated) {
// Transform and update player model
- m_ModelSel->select(1);
sgSetCoord( &sgPlayerCoord, m_ModelPos);
m_ModelTrans->setTransform( &sgPlayerCoord );
- iResult = PLAYER_DATA_AVAILABLE;
+ eResult = PLAYER_DATA_AVAILABLE;
// Clear the updated flag so that the position data
// is only available if it has changed
// Data has not been updated for some time.
} else {
- iResult = PLAYER_DATA_EXPIRED;
+ eResult = PLAYER_DATA_EXPIRED;
}
}
- return iResult;
+ return eResult;
}
void MPPlayer::LoadModel(void) {
- m_ModelSel = new ssgSelector;
- m_ModelTrans = new ssgTransform;
+ m_ModelTrans = new ssgTransform;
+
+ // Load the model
+ m_Model = globals->get_model_loader()->load_model(m_sModelName);
+ m_Model->clrTraversalMaskBits( SSGTRAV_HOT );
- ssgEntity *Model = globals->get_model_loader()->load_model(m_sModelName);
- Model->clrTraversalMaskBits( SSGTRAV_HOT );
- m_ModelTrans->addKid( Model );
- m_ModelSel->addKid( m_ModelTrans );
- ssgFlatten( Model );
- ssgStripify( m_ModelSel );
+ // Add model to transform
+ m_ModelTrans->addKid( m_Model );
- globals->get_scenery()->get_scene_graph()->addKid( m_ModelSel );
- globals->get_scenery()->get_scene_graph()->addKid( Model );
+ // Optimise model and transform
+ ssgFlatten( m_Model );
+ ssgStripify( m_ModelTrans );
+
+ // Place on scene under aircraft branch
+ globals->get_scenery()->get_aircraft_branch()->addKid( m_ModelTrans );
}
strncpy(PosMsg->sModel, m_sModelName.c_str(), MAX_MODEL_NAME_LEN);
PosMsg->sModel[MAX_MODEL_NAME_LEN - 1] = '\0';
-
- memcpy(PosMsg->PlayerPos, m_ModelPos, sizeof(sgMat4));
+ sgCopyMat4(PosMsg->PlayerPos, m_ModelPos);
}
/****************************************************************
* @version $Id$
*
-* Description:
+* Description: This class holds information about a player in a
+* multiplayer game. The model for a remote player is loaded and
+* added onto the aircraft branch of the scene on calling Open.
+* The model is unloaded from the scene when Close is called
+* or the object is deleted. The model's positioning transform is
+* updated by calling SetPosition. The updated position transform
+* is applied to the model on the scene by calling Draw.
*
******************************************************************/
// Number of seconds before a player is consider to be lost
#define TIME_TO_LIVE 10
-#define PLAYER_DATA_NOT_AVAILABLE 0
-#define PLAYER_DATA_AVAILABLE 1
-#define PLAYER_DATA_EXPIRED 2
class MPPlayer {
public:
/** Destructor. */
~MPPlayer();
+ /** Enumeration of the states for the player's data */
+ 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
bool Open(const string &sIP, const int &iPort, const string &sCallsign,
const string &sModelName, const bool bLocalPlayer);
- /** Initialises the player count for all instances of this object to zero. */
- static void ResetPlayerCnt(void);
-
/** Closes the player connection */
void Close(void);
/** Transform and place model for player
*/
- int Draw(void);
+ TPlayerDataState Draw(void);
/** Returns the callsign for the player
* @return Aircraft's callsign
*/
bool CompareCallsign(const char *sCallsign) const;
- /** Loads the model of the aircraft */
- void LoadModel(void);
-
/** Populates a position message for the player
* @param MsgHdr Header to be populated
* @param PosMsg Position message to be populated
private:
+ /** Loads the model of the aircraft */
+ void LoadModel(void);
+
/** True if object is initialised */
bool m_bInitialised;
/** Player's callsign */
string m_sCallsign;
- /** Aircraft model for player */
+ /** Aircraft model name for player */
string m_sModelName;
- /** Simgear model selection */
- ssgSelector *m_ModelSel;
+ /** The player's loaded model */
+ ssgEntity *m_Model;
- /** Simgear model transform */
+ /** Model transform */
ssgTransform *m_ModelTrans;
/** True if this player is the local player */
******************************************************************/
void FGMultiplayRxMgr::Update(void) {
- int iPlayerDataState;
+ MPPlayer::TPlayerDataState ePlayerDataState;
int iPlayerId;
for (iPlayerId = 0; iPlayerId < MAX_PLAYERS; iPlayerId++) {
if (m_Player[iPlayerId] != NULL) {
- iPlayerDataState = m_Player[iPlayerId]->Draw();
+ ePlayerDataState = m_Player[iPlayerId]->Draw();
// If the player has not received an update for some
// time then assume that the player has quit.
- if (iPlayerDataState == PLAYER_DATA_EXPIRED) {
+ 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;
}
// Create a player object for the local player
if (bSuccess) {
mLocalPlayer = new MPPlayer();
- if (!mLocalPlayer->Open(fgGetString("/sim/multiplay/rxaddress"), fgGetInt("/sim/multiplay/rxport"),
+ if (!mLocalPlayer->Open(fgGetString("/sim/multiplay/rxhost"), fgGetInt("/sim/multiplay/rxport"),
fgGetString("/sim/multiplay/callsign"), fgGetString("/sim/model/path"), true)) {
cerr << "FGMultiplayTxMgr::init - Failed to create player object for local player" << endl;
bSuccess = false;