]> git.mxchange.org Git - flightgear.git/blob - src/Network/multiplay.cxx
- rename fgcommand "set-mouse" to "set-cursor"
[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 STL_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/flight.hxx>
41 #include <MultiPlayer/mpmessages.hxx>
42
43 #include "multiplay.hxx"
44
45 SG_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     unsigned i = 0;
105     while (FGMultiplayMgr::sIdPropertyList[i].name) {
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       ++i;
111     }
112
113     return is_enabled();
114 }
115
116
117 /******************************************************************
118 * Name: process
119 * Description: Prompts the multiplayer mgr to either send
120 * or receive data over the network
121 ******************************************************************/
122 bool FGMultiplay::process() {
123
124   if (get_direction() == SG_IO_OUT) {
125
126     // check if we have left initialization phase. That will not provide
127     // interresting data, also the freeze in simulation time hurts the
128     // multiplayer clients
129     double sim_time = globals->get_sim_time_sec();
130 //     if (sim_time < 20)
131 //       return true;
132
133     FGInterface *ifce = cur_fdm_state;
134
135     // put together a motion info struct, you will get that later
136     // from FGInterface directly ...
137     FGExternalMotionData motionInfo;
138
139     // The current simulation time we need to update for,
140     // note that the simulation time is updated before calling all the
141     // update methods. Thus it contains the time intervals *end* time.
142     // The FDM is already run, so the states belong to that time.
143     motionInfo.time = sim_time;
144
145     // The typical lag will be the reciprocal of the output frequency
146     double hz = get_hz();
147     if (hz != 0) // I guess we can test a double for exact zero in this case
148       motionInfo.lag = 1/get_hz();
149     else
150       motionInfo.lag = 0.1; //??
151
152     // These are for now converted from lat/lon/alt and euler angles.
153     // But this should change in FGInterface ...
154     double lon = ifce->get_Longitude();
155     double lat = ifce->get_Latitude();
156     // first the aprioriate structure for the geodetic one
157     SGGeod geod = SGGeod::fromRadFt(lon, lat, ifce->get_Altitude());
158     // Convert to cartesion coordinate
159     motionInfo.position = SGVec3d::fromGeod(geod);
160     
161     // The quaternion rotating from the earth centered frame to the
162     // horizontal local frame
163     SGQuatf qEc2Hl = SGQuatf::fromLonLatRad((float)lon, (float)lat);
164     // The orientation wrt the horizontal local frame
165     float heading = ifce->get_Psi();
166     float pitch = ifce->get_Theta();
167     float roll = ifce->get_Phi();
168     SGQuatf hlOr = SGQuatf::fromYawPitchRoll(heading, pitch, roll);
169     // The orientation of the vehicle wrt the earth centered frame
170     motionInfo.orientation = qEc2Hl*hlOr;
171
172     if (!ifce->is_suspended()) {
173       // velocities
174       motionInfo.linearVel = SG_FEET_TO_METER*SGVec3f(ifce->get_U_body(),
175                                                       ifce->get_V_body(),
176                                                       ifce->get_W_body());
177       motionInfo.angularVel = SGVec3f(ifce->get_P_body(),
178                                       ifce->get_Q_body(),
179                                       ifce->get_R_body());
180       
181       // accels, set that to zero for now.
182       // Angular accelerations are missing from the interface anyway,
183       // linear accelerations are screwed up at least for JSBSim.
184 //  motionInfo.linearAccel = SG_FEET_TO_METER*SGVec3f(ifce->get_U_dot_body(),
185 //                                                    ifce->get_V_dot_body(),
186 //                                                    ifce->get_W_dot_body());
187       motionInfo.linearAccel = SGVec3f::zeros();
188       motionInfo.angularAccel = SGVec3f::zeros();
189     } else {
190       // if the interface is suspendend, prevent the client from
191       // wild extrapolations
192       motionInfo.linearVel = SGVec3f::zeros();
193       motionInfo.angularVel = SGVec3f::zeros();
194       motionInfo.linearAccel = SGVec3f::zeros();
195       motionInfo.angularAccel = SGVec3f::zeros();
196     }
197
198     // now send the properties
199     PropertyMap::iterator it;
200     for (it = mPropertyMap.begin(); it != mPropertyMap.end(); ++it) {
201       FGPropertyData* pData = new FGPropertyData;
202       pData->id = it->first;
203       pData->type = it->second->getType();
204       
205       switch (pData->type) {
206         case SGPropertyNode::INT:        
207         case SGPropertyNode::LONG:       
208         case SGPropertyNode::BOOL:
209           pData->int_value = it->second->getIntValue();
210           break;
211         case SGPropertyNode::FLOAT:
212         case SGPropertyNode::DOUBLE:
213           pData->float_value = it->second->getFloatValue();
214           break;
215         case SGPropertyNode::STRING:
216         case SGPropertyNode::UNSPECIFIED:
217           {
218             // FIXME: We assume unspecified are strings for the moment.
219
220             const char* cstr = it->second->getStringValue();
221             int len = strlen(cstr);
222             
223             if (len > 0)
224             {            
225               pData->string_value = new char[len + 1];
226               strcpy(pData->string_value, cstr);
227             }
228             else
229             {
230               // Size 0 - ignore
231               pData->string_value = 0;            
232             }
233
234             //cout << " Sending property " << pData->id << " " << pData->type << " " <<  pData->string_value << "\n";
235             break;        
236           }
237         default:
238           // FIXME Currently default to a float. 
239           //cout << "Unknown type when iterating through props: " << pData->type << "\n";
240           pData->float_value = it->second->getFloatValue();
241           break;
242       }
243       
244       motionInfo.properties.push_back(pData);
245     }
246
247     FGMultiplayMgr* mpmgr = globals->get_multiplayer_mgr();
248     mpmgr->SendMyPosition(motionInfo);
249     
250     // Now remove the data
251     std::vector<FGPropertyData*>::const_iterator propIt;
252     std::vector<FGPropertyData*>::const_iterator propItEnd;
253     propIt = motionInfo.properties.begin();
254     propItEnd = motionInfo.properties.end();
255
256     //cout << "Deleting data\n";
257
258     while (propIt != propItEnd)
259     {
260       delete *propIt;
261       propIt++;
262     }    
263   }
264
265   return true;
266 }
267
268
269 /******************************************************************
270 * Name: close
271 * Description:  Closes the multiplayer mgrs to stop any further
272 * network processing
273 ******************************************************************/
274 bool FGMultiplay::close() {
275
276   FGMultiplayMgr *mgr = globals->get_multiplayer_mgr();
277
278   if (mgr == 0) {
279     return false;
280   }
281
282   if (get_direction() == SG_IO_IN) {
283
284     mgr->Close();
285
286   } else if (get_direction() == SG_IO_OUT) {
287
288     mgr->Close();
289
290   }
291
292   return true;
293 }
294