]> git.mxchange.org Git - flightgear.git/blob - src/Network/multiplay.cxx
Merge branch 'work4' into next
[flightgear.git] / src / Network / multiplay.cxx
1 // multiplay.cxx -- protocol object for multiplay in Flightgear
2 //
3 // Written by Diarmuid Tyson, started February 2003.
4 // diarmuid.tyson@airservicesaustralia.com
5 //
6 // With addtions by Vivian Meazza, January 2006
7 //
8 // Copyright (C) 2003  Airservices Australia
9 //
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License as
12 // published by the Free Software Foundation; either version 2 of the
13 // License, or (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 // General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23 //
24
25 #ifdef HAVE_CONFIG_H
26 #  include <config.h>
27 #endif
28
29 #include <simgear/compiler.h>
30
31 #include <string>
32
33 #include <iostream>
34 #include <map>
35 #include <string>
36
37 #include <simgear/debug/logstream.hxx>
38 #include <simgear/math/SGMath.hxx>
39
40 #include <FDM/flightProperties.hxx>
41 #include <MultiPlayer/mpmessages.hxx>
42
43 #include "multiplay.hxx"
44
45 using std::string;
46
47
48 // These constants are provided so that the ident command can list file versions.
49 const char sFG_MULTIPLAY_BID[] = "$Id$";
50 const char sFG_MULTIPLAY_HID[] = FG_MULTIPLAY_HID;
51
52
53 /******************************************************************
54 * Name: FGMultiplay
55 * Description: Constructor.  Initialises the protocol and stores
56 * host and port information.
57 ******************************************************************/
58 FGMultiplay::FGMultiplay (const string &dir, const int rate, const string &host, const int port) {
59
60   set_hz(rate);
61
62   set_direction(dir);
63
64   if (get_direction() == SG_IO_IN) {
65
66     fgSetInt("/sim/multiplay/rxport", port);
67     fgSetString("/sim/multiplay/rxhost", host.c_str());
68
69   } else if (get_direction() == SG_IO_OUT) {
70
71     fgSetInt("/sim/multiplay/txport", port);
72     fgSetString("/sim/multiplay/txhost", host.c_str());
73
74   }
75
76 }
77
78
79 /******************************************************************
80 * Name: ~FGMultiplay
81 * Description: Destructor.
82 ******************************************************************/
83 FGMultiplay::~FGMultiplay () {
84 }
85
86
87 /******************************************************************
88 * Name: open
89 * Description: Enables the protocol.
90 ******************************************************************/
91 bool FGMultiplay::open() {
92
93     if ( is_enabled() ) {
94         SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
95                 << "is already in use, ignoring" );
96         return false;
97     }
98
99     set_enabled(true);
100
101     SGPropertyNode* root = globals->get_props();
102
103     /// Build up the id to property map
104     
105     for (unsigned i = 0; i < FGMultiplayMgr::numProperties; ++i) {
106       const char* name = FGMultiplayMgr::sIdPropertyList[i].name;
107       SGPropertyNode* pNode = root->getNode(name);
108       if (pNode)
109         mPropertyMap[FGMultiplayMgr::sIdPropertyList[i].id] = pNode;
110     }
111
112     return is_enabled();
113 }
114
115
116 /******************************************************************
117 * Name: process
118 * Description: Prompts the multiplayer mgr to either send
119 * or receive data over the network
120 ******************************************************************/
121 bool FGMultiplay::process() {
122   using namespace simgear;
123   if (get_direction() == SG_IO_OUT) {
124
125     // check if we have left initialization phase. That will not provide
126     // interresting data, also the freeze in simulation time hurts the
127     // multiplayer clients
128     double sim_time = globals->get_sim_time_sec();
129 //     if (sim_time < 20)
130 //       return true;
131
132     FlightProperties ifce;
133
134     // put together a motion info struct, you will get that later
135     // from FGInterface directly ...
136     FGExternalMotionData motionInfo;
137
138     // The current simulation time we need to update for,
139     // note that the simulation time is updated before calling all the
140     // update methods. Thus it contains the time intervals *end* time.
141     // The FDM is already run, so the states belong to that time.
142     motionInfo.time = sim_time;
143
144     // The typical lag will be the reciprocal of the output frequency
145     double hz = get_hz();
146     if (hz != 0) // I guess we can test a double for exact zero in this case
147       motionInfo.lag = 1/get_hz();
148     else
149       motionInfo.lag = 0.1; //??
150
151     // These are for now converted from lat/lon/alt and euler angles.
152     // But this should change in FGInterface ...
153     double lon = ifce.get_Longitude();
154     double lat = ifce.get_Latitude();
155     // first the aprioriate structure for the geodetic one
156     SGGeod geod = SGGeod::fromRadFt(lon, lat, ifce.get_Altitude());
157     // Convert to cartesion coordinate
158     motionInfo.position = SGVec3d::fromGeod(geod);
159     
160     // The quaternion rotating from the earth centered frame to the
161     // horizontal local frame
162     SGQuatf qEc2Hl = SGQuatf::fromLonLatRad((float)lon, (float)lat);
163     // The orientation wrt the horizontal local frame
164     float heading = ifce.get_Psi();
165     float pitch = ifce.get_Theta();
166     float roll = ifce.get_Phi();
167     SGQuatf hlOr = SGQuatf::fromYawPitchRoll(heading, pitch, roll);
168     // The orientation of the vehicle wrt the earth centered frame
169     motionInfo.orientation = qEc2Hl*hlOr;
170
171     if (!globals->get_subsystem("flight")->is_suspended()) {
172       // velocities
173       motionInfo.linearVel = SG_FEET_TO_METER*SGVec3f(ifce.get_uBody(),
174                                                       ifce.get_vBody(),
175                                                       ifce.get_wBody());
176       motionInfo.angularVel = SGVec3f(ifce.get_P_body(),
177                                       ifce.get_Q_body(),
178                                       ifce.get_R_body());
179       
180       // accels, set that to zero for now.
181       // Angular accelerations are missing from the interface anyway,
182       // linear accelerations are screwed up at least for JSBSim.
183 //  motionInfo.linearAccel = SG_FEET_TO_METER*SGVec3f(ifce.get_U_dot_body(),
184 //                                                    ifce.get_V_dot_body(),
185 //                                                    ifce.get_W_dot_body());
186       motionInfo.linearAccel = SGVec3f::zeros();
187       motionInfo.angularAccel = SGVec3f::zeros();
188     } else {
189       // if the interface is suspendend, prevent the client from
190       // wild extrapolations
191       motionInfo.linearVel = SGVec3f::zeros();
192       motionInfo.angularVel = SGVec3f::zeros();
193       motionInfo.linearAccel = SGVec3f::zeros();
194       motionInfo.angularAccel = SGVec3f::zeros();
195     }
196
197     // now send the properties
198     PropertyMap::iterator it;
199     for (it = mPropertyMap.begin(); it != mPropertyMap.end(); ++it) {
200       FGPropertyData* pData = new FGPropertyData;
201       pData->id = it->first;
202       pData->type = it->second->getType();
203       
204       switch (pData->type) {
205         case props::INT:
206         case props::LONG:
207         case props::BOOL:
208           pData->int_value = it->second->getIntValue();
209           break;
210         case props::FLOAT:
211         case props::DOUBLE:
212           pData->float_value = it->second->getFloatValue();
213           break;
214         case props::STRING:
215         case props::UNSPECIFIED:
216           {
217             // FIXME: We assume unspecified are strings for the moment.
218
219             const char* cstr = it->second->getStringValue();
220             int len = strlen(cstr);
221             
222             if (len > 0)
223             {            
224               pData->string_value = new char[len + 1];
225               strcpy(pData->string_value, cstr);
226             }
227             else
228             {
229               // Size 0 - ignore
230               pData->string_value = 0;            
231             }
232
233             //cout << " Sending property " << pData->id << " " << pData->type << " " <<  pData->string_value << "\n";
234             break;        
235           }
236         default:
237           // FIXME Currently default to a float. 
238           //cout << "Unknown type when iterating through props: " << pData->type << "\n";
239           pData->float_value = it->second->getFloatValue();
240           break;
241       }
242       
243       motionInfo.properties.push_back(pData);
244     }
245
246     FGMultiplayMgr* mpmgr = globals->get_multiplayer_mgr();
247     mpmgr->SendMyPosition(motionInfo);
248     
249     // Now remove the data
250     std::vector<FGPropertyData*>::const_iterator propIt;
251     std::vector<FGPropertyData*>::const_iterator propItEnd;
252     propIt = motionInfo.properties.begin();
253     propItEnd = motionInfo.properties.end();
254
255     //cout << "Deleting data\n";
256
257     while (propIt != propItEnd)
258     {
259       delete *propIt;
260       propIt++;
261     }    
262   }
263
264   return true;
265 }
266
267
268 /******************************************************************
269 * Name: close
270 * Description:  Closes the multiplayer mgrs to stop any further
271 * network processing
272 ******************************************************************/
273 bool FGMultiplay::close() {
274
275   FGMultiplayMgr *mgr = globals->get_multiplayer_mgr();
276
277   if (mgr == 0) {
278     return false;
279   }
280
281   if (get_direction() == SG_IO_IN) {
282
283     mgr->Close();
284
285   } else if (get_direction() == SG_IO_OUT) {
286
287     mgr->Close();
288
289   }
290
291   return true;
292 }
293