1 // mpplayer.cxx -- routines for a player within a multiplayer Flightgear
3 // Written by Duncan McCreanor, started February 2003.
4 // duncan.mccreanor@airservicesaustralia.com
6 // Copyright (C) 2003 Airservices Australia
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /******************************************************************
27 * Description: Provides a container for a player in a multiplayer
28 * game. The players network address, model, callsign and positoin
29 * are held. When the player is created and open called, the player's
30 * model is loaded onto the scene. The position transform matrix
31 * is updated by calling SetPosition. When Draw is called the
32 * elapsed time since the last update is checked. If the model
33 * position information has been updated in the last TIME_TO_LIVE
34 * seconds then the model position is updated on the scene.
36 ******************************************************************/
38 #include "mpplayer.hxx"
43 # include <sys/socket.h>
44 # include <netinet/in.h>
45 # include <arpa/inet.h>
47 #include <plib/netSocket.h>
50 #include <Main/globals.hxx>
51 #include <Model/loader.hxx>
52 #include <Scenery/scenery.hxx>
55 // These constants are provided so that the ident command can list file versions.
56 const char sMPPLAYER_BID[] = "$Id$";
57 const char sMPPLAYER_HID[] = MPPLAYER_HID;
60 /******************************************************************
62 * Description: Constructor.
63 ******************************************************************/
64 MPPlayer::MPPlayer() {
66 // Initialise private members
67 m_bInitialised = false;
69 m_PlayerAddress.set("localhost", 0);
76 /******************************************************************
78 * Description: Destructor.
79 ******************************************************************/
80 MPPlayer::~MPPlayer() {
87 /******************************************************************
89 * Description: Initialises class.
90 ******************************************************************/
91 bool MPPlayer::Open(const string &sAddress, const int &iPort, const string &sCallsign, const string &sModelName, bool bLocalPlayer) {
95 if (!m_bInitialised) {
97 m_PlayerAddress.set(sAddress.c_str(), iPort);
98 m_sCallsign = sCallsign;
99 m_sModelName = sModelName;
100 m_bLocalPlayer = bLocalPlayer;
102 // If the player is remote then load the model
109 m_bInitialised = bSuccess;
112 SG_LOG( SG_NETWORK, SG_ALERT, "MPPlayer::Open - Attempt to open an already open player connection." );
117 /* Return true if open succeeds */
123 /******************************************************************
125 * Description: Resets the object.
126 ******************************************************************/
127 void MPPlayer::Close(void) {
129 // Remove the model from the game
130 if (m_bInitialised && !m_bLocalPlayer) {
132 // Disconnect the model from the transform, then the transform from the scene.
133 m_ModelTrans->removeKid(m_Model);
134 globals->get_scenery()->get_aircraft_branch()->removeKid( m_ModelTrans);
136 // Flush the model loader so that it erases the model from its list of
138 globals->get_model_loader()->flush();
140 // Assume that plib/ssg deletes the model and transform as their
141 // refcounts should be zero.
145 m_bInitialised = false;
148 m_sCallsign = "none";
153 /******************************************************************
155 * Description: Updates position data held for this player and resets
156 * the last update time.
157 ******************************************************************/
158 void MPPlayer::SetPosition(const sgMat4 PlayerPosMat4) {
161 // Save the position matrix and update time
162 if (m_bInitialised) {
163 sgCopyMat4(m_ModelPos, PlayerPosMat4);
172 /******************************************************************
174 * Description: Updates the position for the player's model
175 * The state of the player's data is returned.
176 ******************************************************************/
177 MPPlayer::TPlayerDataState MPPlayer::Draw(void) {
179 MPPlayer::TPlayerDataState eResult = PLAYER_DATA_NOT_AVAILABLE;
181 sgCoord sgPlayerCoord;
183 if (m_bInitialised && !m_bLocalPlayer) {
184 if ((time(NULL) - m_LastUpdate < TIME_TO_LIVE)) {
185 // Peform an update if it has changed since the last update
188 // Transform and update player model
189 sgSetCoord( &sgPlayerCoord, m_ModelPos);
190 m_ModelTrans->setTransform( &sgPlayerCoord );
192 eResult = PLAYER_DATA_AVAILABLE;
194 // Clear the updated flag so that the position data
195 // is only available if it has changed
199 // Data has not been updated for some time.
201 eResult = PLAYER_DATA_EXPIRED;
211 /******************************************************************
213 * Description: Returns the player's callsign.
214 ******************************************************************/
215 string MPPlayer::Callsign(void) const {
222 /******************************************************************
223 * Name: CompareCallsign
224 * Description: Returns true if the player's callsign matches
225 * the given callsign.
226 ******************************************************************/
227 bool MPPlayer::CompareCallsign(const char *sCallsign) const {
229 return (m_sCallsign == sCallsign);
234 /******************************************************************
236 * Description: Loads the player's aircraft model.
237 ******************************************************************/
238 void MPPlayer::LoadModel(void) {
241 m_ModelTrans = new ssgTransform;
244 m_Model = globals->get_model_loader()->load_model(m_sModelName);
245 m_Model->clrTraversalMaskBits( SSGTRAV_HOT );
247 // Add model to transform
248 m_ModelTrans->addKid( m_Model );
250 // Optimise model and transform
251 ssgFlatten( m_Model );
252 ssgStripify( m_ModelTrans );
254 // Place on scene under aircraft branch
255 globals->get_scenery()->get_aircraft_branch()->addKid( m_ModelTrans );
261 /******************************************************************
263 * Description: Populates the header and data for a position message.
264 ******************************************************************/
265 void MPPlayer::FillPosMsg(T_MsgHdr *MsgHdr, T_PositionMsg *PosMsg) {
267 FillMsgHdr(MsgHdr, POS_DATA_ID);
269 strncpy(PosMsg->sModel, m_sModelName.c_str(), MAX_MODEL_NAME_LEN);
270 PosMsg->sModel[MAX_MODEL_NAME_LEN - 1] = '\0';
271 sgCopyMat4(PosMsg->PlayerPos, m_ModelPos);
277 /******************************************************************
279 * Description: Populates the header of a multiplayer message.
280 ******************************************************************/
281 void MPPlayer::FillMsgHdr(T_MsgHdr *MsgHdr, const int iMsgId) {
283 struct in_addr address;
285 MsgHdr->MsgId = iMsgId;
289 MsgHdr->iMsgLen = sizeof(T_MsgHdr) + sizeof(T_ChatMsg);
292 MsgHdr->iMsgLen = sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
295 MsgHdr->iMsgLen = sizeof(T_MsgHdr);
299 address.s_addr = inet_addr( m_PlayerAddress.getHost() );
300 MsgHdr->lReplyAddress = address.s_addr;
302 MsgHdr->iReplyPort = m_PlayerAddress.getPort();
304 strncpy(MsgHdr->sCallsign, m_sCallsign.c_str(), MAX_CALLSIGN_LEN);
305 MsgHdr->sCallsign[MAX_CALLSIGN_LEN - 1] = '\0';