1 //////////////////////////////////////////////////////////////////////
3 // mpplayer.cxx -- routines for a player within a multiplayer Flightgear
5 // Written by Duncan McCreanor, started February 2003.
6 // duncan.mccreanor@airservicesaustralia.com
8 // Copyright (C) 2003 Airservices Australia
9 // Copyright (C) 2005 Oliver Schroeder
11 // This program is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU General Public License as
13 // published by the Free Software Foundation; either version 2 of the
14 // License, or (at your option) any later version.
16 // This program is distributed in the hope that it will be useful, but
17 // WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 //////////////////////////////////////////////////////////////////////
33 /******************************************************************
36 * Description: Provides a container for a player in a multiplayer
37 * game. The players network address, model, callsign and positoin
38 * are held. When the player is created and open called, the player's
39 * model is loaded onto the scene. The position transform matrix
40 * is updated by calling SetPosition. When Draw is called the
41 * elapsed time since the last update is checked. If the model
42 * position information has been updated in the last TIME_TO_LIVE
43 * seconds then the model position is updated on the scene.
45 ******************************************************************/
47 #include "mpplayer.hxx"
50 #if !(defined(_MSC_VER) || defined(__MINGW32__))
52 # include <sys/socket.h>
53 # include <netinet/in.h>
54 # include <arpa/inet.h>
56 #include <plib/netSocket.h>
59 #include <simgear/scene/model/modellib.hxx>
60 #include <simgear/scene/model/placementtrans.hxx>
62 #include <Main/globals.hxx>
63 #include <Scenery/scenery.hxx>
66 // These constants are provided so that the ident command can list file versions.
67 const char sMPPLAYER_BID[] = "$Id$";
68 const char sMPPLAYER_HID[] = MPPLAYER_HID;
70 //////////////////////////////////////////////////////////////////////
74 //////////////////////////////////////////////////////////////////////
77 m_Initialised = false;
80 m_PlayerAddress.set("localhost", 0);
81 } // MPPlayer::MPPlayer()
82 //////////////////////////////////////////////////////////////////////
84 /******************************************************************
86 * Description: Destructor.
87 ******************************************************************/
93 /******************************************************************
95 * Description: Initialises class.
96 ******************************************************************/
100 const string &Address,
102 const string &Callsign,
103 const string &ModelName,
111 m_PlayerAddress.set(Address.c_str(), Port);
112 m_Callsign = Callsign;
113 m_ModelName = ModelName;
114 m_LocalPlayer = LocalPlayer;
115 SG_LOG( SG_NETWORK, SG_ALERT, "Initialising " << m_Callsign
116 << " using '" << m_ModelName << "'" );
117 // If the player is remote then load the model
123 SG_LOG( SG_NETWORK, SG_ALERT,
124 "Failed to load remote model '" << ModelName << "'." );
128 m_Initialised = Success;
132 SG_LOG( SG_NETWORK, SG_ALERT, "MPPlayer::Open - "
133 << "Attempt to open an already opened player connection." );
136 /* Return true if open succeeds */
140 /******************************************************************
142 * Description: Resets the object.
143 ******************************************************************/
145 MPPlayer::Close(void)
147 // Remove the model from the game
148 if (m_Initialised && !m_LocalPlayer)
150 // Disconnect the model from the transform,
151 // then the transform from the scene.
152 m_ModelTrans->removeKid(m_Model);
153 globals->get_scenery()->unregister_placement_transform(m_ModelTrans);
154 globals->get_scenery()->get_aircraft_branch()->removeKid( m_ModelTrans);
155 // Flush the model loader so that it erases the model from its list of
157 // globals->get_model_lib()->flush1();
158 // Assume that plib/ssg deletes the model and transform as their
159 // refcounts should be zero.
161 m_Initialised = false;
167 /******************************************************************
169 * Description: Updates position data held for this player and resets
170 * the last update time.
171 ******************************************************************/
173 MPPlayer::SetPosition
175 const sgQuat PlayerOrientation,
176 const sgdVec3 PlayerPosition
179 // Save the position matrix and update time
182 sgdCopyVec3(m_ModelPosition, PlayerPosition);
183 sgCopyVec4(m_ModelOrientation, PlayerOrientation);
189 /******************************************************************
191 * Description: Updates the position for the player's model
192 * The state of the player's data is returned.
193 ******************************************************************/
194 MPPlayer::TPlayerDataState
195 MPPlayer::Draw (void)
197 MPPlayer::TPlayerDataState eResult = PLAYER_DATA_NOT_AVAILABLE;
198 if (m_Initialised && !m_LocalPlayer)
200 if ((time(NULL) - m_LastUpdate < TIME_TO_LIVE))
202 // Peform an update if it has changed since the last update
205 // Transform and update player model
207 sgMakeIdentMat4(orMat);
208 sgQuatToMatrix(orMat, m_ModelOrientation);
209 m_ModelTrans->setTransform(m_ModelPosition, orMat);
210 eResult = PLAYER_DATA_AVAILABLE;
211 // Clear the updated flag so that the position data
212 // is only available if it has changed
217 { // Data has not been updated for some time.
218 eResult = PLAYER_DATA_EXPIRED;
224 /******************************************************************
226 * Description: Returns the player's callsign.
227 ******************************************************************/
229 MPPlayer::Callsign(void) const
234 /******************************************************************
235 * Name: CompareCallsign
236 * Description: Returns true if the player's callsign matches
237 * the given callsign.
238 ******************************************************************/
240 MPPlayer::CompareCallsign(const char *Callsign) const
242 return (m_Callsign == Callsign);
245 /******************************************************************
247 * Description: Loads the player's aircraft model.
248 ******************************************************************/
250 MPPlayer::LoadModel (void)
252 m_ModelTrans = new ssgPlacementTransform;
254 m_Model = globals->get_model_lib()->load_model( globals->get_fg_root(),
255 m_ModelName, globals->get_props(), globals->get_sim_time_sec() );
256 m_Model->clrTraversalMaskBits( SSGTRAV_HOT );
257 // Add model to transform
258 m_ModelTrans->addKid( m_Model );
259 // Place on scene under aircraft branch
260 globals->get_scenery()->get_aircraft_branch()->addKid( m_ModelTrans );
261 globals->get_scenery()->register_placement_transform( m_ModelTrans);
264 /******************************************************************
266 * Description: Populates the header and data for a position message.
267 ******************************************************************/
272 T_PositionMsg *PosMsg
275 FillMsgHdr(MsgHdr, POS_DATA_ID);
276 strncpy(PosMsg->Model, m_ModelName.c_str(), MAX_MODEL_NAME_LEN);
277 PosMsg->Model[MAX_MODEL_NAME_LEN - 1] = '\0';
278 PosMsg->PlayerPosition[0] = XDR_encode_double (m_ModelPosition[0]);
279 PosMsg->PlayerPosition[1] = XDR_encode_double (m_ModelPosition[1]);
280 PosMsg->PlayerPosition[2] = XDR_encode_double (m_ModelPosition[2]);
281 PosMsg->PlayerOrientation[0] = XDR_encode_float (m_ModelOrientation[0]);
282 PosMsg->PlayerOrientation[1] = XDR_encode_float (m_ModelOrientation[1]);
283 PosMsg->PlayerOrientation[2] = XDR_encode_float (m_ModelOrientation[2]);
284 PosMsg->PlayerOrientation[3] = XDR_encode_float (m_ModelOrientation[3]);
287 /******************************************************************
289 * Description: Populates the header of a multiplayer message.
290 ******************************************************************/
298 struct in_addr address;
304 len = sizeof(T_MsgHdr) + sizeof(T_ChatMsg);
307 len = sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
310 len = sizeof(T_MsgHdr);
313 MsgHdr->Magic = XDR_encode_uint32 (MSG_MAGIC);
314 MsgHdr->Version = XDR_encode_uint32 (PROTO_VER);
315 MsgHdr->MsgId = XDR_encode_uint32 (MsgId);
316 MsgHdr->MsgLen = XDR_encode_uint32 (len);
317 // inet_addr returns address in network byte order
318 // no need to encode it
319 MsgHdr->ReplyAddress = inet_addr( m_PlayerAddress.getHost() );
320 MsgHdr->ReplyPort = XDR_encode_uint32 (m_PlayerAddress.getPort());
321 strncpy(MsgHdr->Callsign, m_Callsign.c_str(), MAX_CALLSIGN_LEN);
322 MsgHdr->Callsign[MAX_CALLSIGN_LEN - 1] = '\0';
325 #endif // FG_MPLAYER_AS