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