]> git.mxchange.org Git - flightgear.git/blob - src/MultiPlayer/mpplayer.cxx
Load ground ATC frequency data, and map all stations by bucket index
[flightgear.git] / src / MultiPlayer / mpplayer.cxx
1 // mpplayer.cxx -- routines for a player within a multiplayer Flightgear
2 //
3 // Written by Duncan McCreanor, started February 2003.
4 // duncan.mccreanor@airservicesaustralia.com
5 //
6 // Copyright (C) 2003  Airservices Australia
7 //
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.
12 //
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.
17 //
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.
21 //
22
23
24 /******************************************************************
25 * $Id$
26 *
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.
35 *
36 ******************************************************************/
37
38 #include "mpplayer.hxx"
39
40 #include <stdlib.h>
41 #include <netdb.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <plib/netSocket.h>
46
47 #include <Main/globals.hxx>
48 #include <Model/loader.hxx>
49 #include <Scenery/scenery.hxx>
50
51
52 // These constants are provided so that the ident command can list file versions.
53 const char sMPPLAYER_BID[] = "$Id$";
54 const char sMPPLAYER_HID[] = MPPLAYER_HID;
55
56
57 /******************************************************************
58 * Name: MPPlayer
59 * Description: Constructor.
60 ******************************************************************/
61 MPPlayer::MPPlayer() {
62
63     // Initialise private members
64     m_bInitialised = false;
65     m_LastUpdate = 0;
66     m_PlayerAddress.set("localhost", 0);
67
68
69 }
70
71
72 /******************************************************************
73 * Name: ~MPPlayer
74 * Description: Destructor.
75 ******************************************************************/
76 MPPlayer::~MPPlayer() {
77
78     Close();
79
80 }
81
82
83 /******************************************************************
84 * Name: Open
85 * Description: Initialises class.
86 ******************************************************************/
87 bool MPPlayer::Open(const string &sAddress, const int &iPort, const string &sCallsign, const string &sModelName, bool bLocalPlayer) {
88
89     bool bSuccess = true;
90
91     if (!m_bInitialised) {
92
93         m_PlayerAddress.set(sAddress.c_str(), iPort);
94         m_sCallsign = sCallsign;
95         m_sModelName = sModelName;
96         m_bLocalPlayer = bLocalPlayer;
97
98         // If the player is remote then load the model
99         if (!bLocalPlayer) {
100
101              LoadModel();
102
103         }
104
105         m_bInitialised = bSuccess;
106
107     } else {
108         cerr << "MPPlayer::Open - Attempt to open an already open player connection." << endl;
109         bSuccess = false;
110     }
111
112
113     /* Return true if open succeeds */
114     return bSuccess;
115
116 }
117
118
119 /******************************************************************
120 * Name: Close
121 * Description: Resets the object.
122 ******************************************************************/
123 void MPPlayer::Close(void) {
124
125
126     // Remove the model from the game
127     if (!m_bLocalPlayer) {
128         globals->get_scenery()->get_scene_graph()->removeKid(m_ModelSel);
129     }
130
131     m_bInitialised = false;
132     m_bUpdated = false;
133     m_LastUpdate = 0;
134
135 }
136
137
138 /******************************************************************
139 * Name: SetPosition
140 * Description: Updates position data held for this player and resets
141 * the last update time.
142 ******************************************************************/
143 void MPPlayer::SetPosition(const sgMat4 PlayerPosMat4) {
144
145
146     // Save the position matrix and update time
147     if (m_bInitialised) {
148         memcpy(m_ModelPos, PlayerPosMat4, sizeof(sgMat4));
149         time(&m_LastUpdate);
150         m_bUpdated = true;
151     }
152
153
154 }
155
156
157 /******************************************************************
158 * Name: Draw
159 * Description: Updates the position for the player's model
160 * The state of the player (old, initialised etc)
161 * is returned.
162 ******************************************************************/
163 int MPPlayer::Draw(void) {
164
165     int iResult = PLAYER_DATA_NOT_AVAILABLE;
166
167     sgCoord sgPlayerCoord;
168
169     if (m_bInitialised) {
170         if ((time(NULL) - m_LastUpdate < TIME_TO_LIVE)) {
171             // Peform an update if it has changed since the last update
172             if (m_bUpdated) {
173
174                 // Transform and update player model
175                 m_ModelSel->select(1);
176                 sgSetCoord( &sgPlayerCoord, m_ModelPos);
177                 m_ModelTrans->setTransform( &sgPlayerCoord );
178
179                 iResult = PLAYER_DATA_AVAILABLE;
180
181                 // Clear the updated flag so that the position data
182                 // is only available if it has changed
183                 m_bUpdated = false;
184             }
185
186         // Data has not been updated for some time.
187         } else {
188             iResult = PLAYER_DATA_EXPIRED;
189         }
190
191     }
192
193     return iResult;
194
195 }
196
197
198 /******************************************************************
199 * Name: Callsign
200 * Description: Returns the player's callsign.
201 ******************************************************************/
202 string MPPlayer::Callsign(void) const {
203
204     return m_sCallsign;
205
206 }
207
208
209 /******************************************************************
210 * Name: CompareCallsign
211 * Description: Returns true if the player's callsign matches
212 * the given callsign.
213 ******************************************************************/
214 bool MPPlayer::CompareCallsign(const char *sCallsign) const {
215
216     return (m_sCallsign == sCallsign);
217
218 }
219
220
221 /******************************************************************
222 * Name: LoadModel
223 * Description: Loads the player's aircraft model.
224 ******************************************************************/
225 void MPPlayer::LoadModel(void) {
226
227
228    m_ModelSel = new ssgSelector;
229    m_ModelTrans = new ssgTransform;
230
231    ssgEntity *Model = globals->get_model_loader()->load_model(m_sModelName);
232    Model->clrTraversalMaskBits( SSGTRAV_HOT );
233    m_ModelTrans->addKid( Model );
234    m_ModelSel->addKid( m_ModelTrans );
235    ssgFlatten( Model );
236    ssgStripify( m_ModelSel );
237
238    globals->get_scenery()->get_scene_graph()->addKid( m_ModelSel );
239    globals->get_scenery()->get_scene_graph()->addKid(  Model );
240
241
242 }
243
244
245 /******************************************************************
246 * Name: FillPosMsg
247 * Description: Populates the header and data for a position message.
248 ******************************************************************/
249 void MPPlayer::FillPosMsg(T_MsgHdr *MsgHdr, T_PositionMsg *PosMsg) {
250
251     FillMsgHdr(MsgHdr, POS_DATA_ID);
252
253     strncpy(PosMsg->sModel, m_sModelName.c_str(), MAX_MODEL_NAME_LEN);
254     PosMsg->sModel[MAX_MODEL_NAME_LEN - 1] = '\0';
255
256     memcpy(PosMsg->PlayerPos, m_ModelPos, sizeof(sgMat4));
257
258
259 }
260
261
262 /******************************************************************
263 * Name: FillMsgHdr
264 * Description: Populates the header of a multiplayer message.
265 ******************************************************************/
266 void MPPlayer::FillMsgHdr(T_MsgHdr *MsgHdr, const int iMsgId) {
267
268     struct in_addr address;
269
270     MsgHdr->MsgId = iMsgId;
271
272     switch (iMsgId) {
273         case CHAT_MSG_ID:
274             MsgHdr->iMsgLen = sizeof(T_MsgHdr) + sizeof(T_ChatMsg);
275             break;
276         case POS_DATA_ID:
277             MsgHdr->iMsgLen = sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
278             break;
279         default:
280             MsgHdr->iMsgLen = sizeof(T_MsgHdr);
281             break;
282     }
283
284     inet_aton(m_PlayerAddress.getHost(), &address);
285     MsgHdr->lReplyAddress = address.s_addr;
286
287     MsgHdr->iReplyPort = m_PlayerAddress.getPort();
288
289     strncpy(MsgHdr->sCallsign, m_sCallsign.c_str(), MAX_CALLSIGN_LEN);
290     MsgHdr->sCallsign[MAX_CALLSIGN_LEN - 1] = '\0';
291
292
293 }
294