38#include <simgear/debug/logstream.hxx>
39#include <simgear/math/sg_random.hxx>
40#include <simgear/misc/sg_dir.hxx>
41#include <simgear/misc/stdint.hxx>
42#include <simgear/misc/strutils.hxx>
43#include <simgear/props/props.hxx>
44#include <simgear/props/props_io.hxx>
45#include <simgear/structure/commands.hxx>
46#include <simgear/structure/event_mgr.hxx>
47#include <simgear/timing/timestamp.hxx>
62#if defined(_MSC_VER) || defined(__MINGW32__)
68#define MAX_PACKET_SIZE 1200
69#define MAX_TEXT_SIZE 768
180 if (
p &&
p->string_value)
182 if (!strcmp(
"Engaged",
p->string_value))
184 else if (!strcmp(
"Launching",
p->string_value))
186 else if (!strcmp(
"Completed",
p->string_value))
188 else if (!strcmp(
"Disengaged",
p->string_value))
205 const char *stringvalue =
"";
208 case 0: stringvalue =
"Engaged";
break;
209 case 1: stringvalue =
"Launching";
break;
210 case 2: stringvalue =
"Completed";
break;
211 case 3: stringvalue =
"Disengaged";
break;
215 if (
p->string_value &&
p->type == simgear::props::STRING)
216 delete[]
p->string_value;
217 p->string_value =
new char[strlen(stringvalue) + 1];
218 strcpy(
p->string_value, stringvalue);
219 p->type = simgear::props::STRING;
302 { 900,
"sim/hitches/aerotow/tow/length", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
303 { 901,
"sim/hitches/aerotow/tow/elastic-constant", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
304 { 902,
"sim/hitches/aerotow/tow/weight-per-m-kg-m", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
305 { 903,
"sim/hitches/aerotow/tow/dist", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
306 { 904,
"sim/hitches/aerotow/tow/connected-to-property-node", simgear::props::BOOL,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
307 { 905,
"sim/hitches/aerotow/tow/connected-to-ai-or-mp-callsign", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
308 { 906,
"sim/hitches/aerotow/tow/break-force", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
309 { 907,
"sim/hitches/aerotow/tow/end-force-x", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
310 { 908,
"sim/hitches/aerotow/tow/end-force-y", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
311 { 909,
"sim/hitches/aerotow/tow/end-force-z", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
312 { 930,
"sim/hitches/aerotow/is-slave", simgear::props::BOOL,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
313 { 931,
"sim/hitches/aerotow/speed-in-tow-direction", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
314 { 932,
"sim/hitches/aerotow/open", simgear::props::BOOL,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
315 { 933,
"sim/hitches/aerotow/local-pos-x", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
316 { 934,
"sim/hitches/aerotow/local-pos-y", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
317 { 935,
"sim/hitches/aerotow/local-pos-z", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
324 { 1006,
"controls/armament/station[0]/jettison-all", simgear::props::BOOL,
TT_SHORTINT,
V1_1_PROP_ID, NULL, NULL },
336 { 1500,
"instrumentation/transponder/transmitted-id", simgear::props::INT,
TT_SHORTINT,
V1_1_PROP_ID, NULL, NULL },
337 { 1501,
"instrumentation/transponder/altitude", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
339 { 1503,
"instrumentation/transponder/inputs/mode", simgear::props::INT,
TT_SHORTINT,
V1_1_PROP_ID, NULL, NULL },
343 { 10001,
"sim/multiplay/transmission-freq-hz", simgear::props::STRING,
TT_NOSEND,
V1_1_2_PROP_ID, NULL, NULL },
346 { 10100,
"sim/multiplay/generic/string[0]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
347 { 10101,
"sim/multiplay/generic/string[1]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
348 { 10102,
"sim/multiplay/generic/string[2]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
349 { 10103,
"sim/multiplay/generic/string[3]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
350 { 10104,
"sim/multiplay/generic/string[4]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
351 { 10105,
"sim/multiplay/generic/string[5]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
352 { 10106,
"sim/multiplay/generic/string[6]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
353 { 10107,
"sim/multiplay/generic/string[7]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
354 { 10108,
"sim/multiplay/generic/string[8]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
355 { 10109,
"sim/multiplay/generic/string[9]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
356 { 10110,
"sim/multiplay/generic/string[10]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
357 { 10111,
"sim/multiplay/generic/string[11]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
358 { 10112,
"sim/multiplay/generic/string[12]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
359 { 10113,
"sim/multiplay/generic/string[13]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
360 { 10114,
"sim/multiplay/generic/string[14]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
361 { 10115,
"sim/multiplay/generic/string[15]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
362 { 10116,
"sim/multiplay/generic/string[16]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
363 { 10117,
"sim/multiplay/generic/string[17]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
364 { 10118,
"sim/multiplay/generic/string[18]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
365 { 10119,
"sim/multiplay/generic/string[19]", simgear::props::STRING,
TT_ASIS,
V1_1_2_PROP_ID, NULL, NULL },
367 { 10200,
"sim/multiplay/generic/float[0]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
368 { 10201,
"sim/multiplay/generic/float[1]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
369 { 10202,
"sim/multiplay/generic/float[2]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
370 { 10203,
"sim/multiplay/generic/float[3]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
371 { 10204,
"sim/multiplay/generic/float[4]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
372 { 10205,
"sim/multiplay/generic/float[5]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
373 { 10206,
"sim/multiplay/generic/float[6]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
374 { 10207,
"sim/multiplay/generic/float[7]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
375 { 10208,
"sim/multiplay/generic/float[8]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
376 { 10209,
"sim/multiplay/generic/float[9]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
377 { 10210,
"sim/multiplay/generic/float[10]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
378 { 10211,
"sim/multiplay/generic/float[11]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
379 { 10212,
"sim/multiplay/generic/float[12]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
380 { 10213,
"sim/multiplay/generic/float[13]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
381 { 10214,
"sim/multiplay/generic/float[14]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
382 { 10215,
"sim/multiplay/generic/float[15]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
383 { 10216,
"sim/multiplay/generic/float[16]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
384 { 10217,
"sim/multiplay/generic/float[17]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
385 { 10218,
"sim/multiplay/generic/float[18]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
386 { 10219,
"sim/multiplay/generic/float[19]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
388 { 10220,
"sim/multiplay/generic/float[20]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
389 { 10221,
"sim/multiplay/generic/float[21]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
390 { 10222,
"sim/multiplay/generic/float[22]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
391 { 10223,
"sim/multiplay/generic/float[23]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
392 { 10224,
"sim/multiplay/generic/float[24]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
393 { 10225,
"sim/multiplay/generic/float[25]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
394 { 10226,
"sim/multiplay/generic/float[26]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
395 { 10227,
"sim/multiplay/generic/float[27]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
396 { 10228,
"sim/multiplay/generic/float[28]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
397 { 10229,
"sim/multiplay/generic/float[29]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
398 { 10230,
"sim/multiplay/generic/float[30]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
399 { 10231,
"sim/multiplay/generic/float[31]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
400 { 10232,
"sim/multiplay/generic/float[32]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
401 { 10233,
"sim/multiplay/generic/float[33]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
402 { 10234,
"sim/multiplay/generic/float[34]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
403 { 10235,
"sim/multiplay/generic/float[35]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
404 { 10236,
"sim/multiplay/generic/float[36]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
405 { 10237,
"sim/multiplay/generic/float[37]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
406 { 10238,
"sim/multiplay/generic/float[38]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
407 { 10239,
"sim/multiplay/generic/float[39]", simgear::props::FLOAT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
409 { 10300,
"sim/multiplay/generic/int[0]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
410 { 10301,
"sim/multiplay/generic/int[1]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
411 { 10302,
"sim/multiplay/generic/int[2]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
412 { 10303,
"sim/multiplay/generic/int[3]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
413 { 10304,
"sim/multiplay/generic/int[4]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
414 { 10305,
"sim/multiplay/generic/int[5]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
415 { 10306,
"sim/multiplay/generic/int[6]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
416 { 10307,
"sim/multiplay/generic/int[7]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
417 { 10308,
"sim/multiplay/generic/int[8]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
418 { 10309,
"sim/multiplay/generic/int[9]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
419 { 10310,
"sim/multiplay/generic/int[10]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
420 { 10311,
"sim/multiplay/generic/int[11]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
421 { 10312,
"sim/multiplay/generic/int[12]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
422 { 10313,
"sim/multiplay/generic/int[13]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
423 { 10314,
"sim/multiplay/generic/int[14]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
424 { 10315,
"sim/multiplay/generic/int[15]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
425 { 10316,
"sim/multiplay/generic/int[16]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
426 { 10317,
"sim/multiplay/generic/int[17]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
427 { 10318,
"sim/multiplay/generic/int[18]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
428 { 10319,
"sim/multiplay/generic/int[19]", simgear::props::INT,
TT_ASIS,
V1_1_PROP_ID, NULL, NULL },
697 struct ComparePropertyId
702 return lhs.
id < rhs.
id;
709 bool operator()(
unsigned id,
719 std::pair<const IdPropertyList*, const IdPropertyList*> result
721 ComparePropertyId());
722 if (result.first == result.second) {
742 switch (plist->
type) {
752 if (SGMisc<float>::isNaN(val))
758 case props::UNSPECIFIED:
774 while ((length % 4) != 0)
807 _multiplay->setPropertiesChanged();
827 if (filter_base == 1)
828 return property_id >= 10002
830 || (property_id >= 1500 && property_id < 1600);
832 return property_id >= filter_base
834 || (property_id >= 1500 && property_id < 1600);
848 SG_LOG(SG_NETWORK, SG_WARN,
"Multiplayer subsystem not available.");
852 string servername = arg->getStringValue(
"servername",
"");
853 if (servername.empty()) {
854 SG_LOG(SG_NETWORK, SG_WARN,
855 "do_multiplayer.connect: no server name given, command ignored.");
858 int port = arg->getIntValue(
"rxport", -1);
859 if (port > 0 && port <= 0xffff) {
860 fgSetInt(
"/sim/multiplay/rxport", port);
863 port = arg->getIntValue(
"txport", -1);
864 if (port > 0 && port <= 0xffff) {
865 fgSetInt(
"/sim/multiplay/txport", port);
868 servername = servername.substr(0, servername.find_first_of(
' '));
883 SG_LOG(SG_NETWORK, SG_WARN,
"Multiplayer subsystem not available.");
907 SG_LOG(SG_NETWORK, SG_WARN,
"Multiplayer subsystem not available.");
915 MyMPServerResolver () :
922 _completeNode->setBoolValue (
false);
923 _failureNode->setBoolValue (
false);
926 ~MyMPServerResolver ()
933 SG_LOG(SG_NETWORK, SG_DEBUG,
"MyMPServerResolver: trigger success");
934 _completeNode->setBoolValue (
true);
940 SG_LOG(SG_NETWORK, SG_DEBUG,
"MyMPServerResolver: trigger failure");
941 _failureNode->setBoolValue (
true);
946 SGPropertyNode *_completeNode =
fgGetNode (
"/sim/multiplay/got-servers",
true);
947 SGPropertyNode *_failureNode =
fgGetNode (
"/sim/multiplay/get-servers-failure",
true);
950 MyMPServerResolver * mpServerResolver =
new MyMPServerResolver ();
951 mpServerResolver->run ();
965 SG_LOG(SG_NETWORK, SG_WARN,
"Multiplayer subsystem not available.");
970 std::string authority = arg->getStringValue(
"atc");
972 if (authority.empty()) {
973 std::string
name = arg->getStringValue(
"property");
975 SGPropertyNode* pNode =
globals->get_props()->getNode(
name);
976 if (!pNode) {
return false; }
977 authority = pNode->getStringValue();
981 if (self->getCPDLC()) {
982 return self->getCPDLC()->connect(authority);
991 SG_LOG(SG_NETWORK, SG_WARN,
"Multiplayer subsystem not available.");
996 std::string message = arg->getStringValue(
"message");
998 if (message.empty()) {
999 std::string
name = arg->getStringValue(
"property");
1000 if (!
name.empty()) {
1001 SGPropertyNode* pNode =
globals->get_props()->getNode(
name);
1002 if (!pNode) {
return false; }
1003 message = pNode->getStringValue();
1006 if (self->getCPDLC()) {
1007 return self->getCPDLC()->send(message);
1016 SG_LOG(SG_NETWORK, SG_WARN,
"Multiplayer subsystem not available.");
1027 SG_LOG(SG_NETWORK, SG_WARN,
"Multiplayer subsystem not available.");
1042 mPropertiesChanged =
false;
1043 mInitialised =
false;
1044 mHaveServer =
false;
1056 pXmitLen =
fgGetNode(
"/sim/multiplay/last-xmit-packet-len",
true);
1057 pProtocolVersion =
fgGetNode(
"/sim/multiplay/protocol-version",
true);
1058 pMultiPlayDebugLevel =
fgGetNode(
"/sim/multiplay/debug-level",
true);
1059 pMultiPlayTransmitPropertyBase =
fgGetNode(
"/sim/multiplay/transmit-filter-property-base",
true);
1060 pMultiPlayRange =
fgGetNode(
"/sim/multiplay/visibility-range-nm",
true);
1061 pMultiPlayRange->setIntValue(100);
1062 pReplayState =
fgGetNode(
"/sim/replay/replay-state",
true);
1063 pLogRawSpeedMultiplayer =
fgGetNode(
"/sim/replay/log-raw-speed-multiplayer",
true);
1076 globals->get_commands()->removeCommand(
"multiplayer-connect");
1077 globals->get_commands()->removeCommand(
"multiplayer-disconnect");
1078 globals->get_commands()->removeCommand(
"multiplayer-refreshserverlist");
1080 globals->get_commands()->removeCommand(
"cpdlc-connect");
1081 globals->get_commands()->removeCommand(
"cpdlc-send");
1082 globals->get_commands()->removeCommand(
"cpdlc-next-message");
1083 globals->get_commands()->removeCommand(
"cpdlc-disconnect");
1099 SG_LOG(SG_NETWORK, SG_WARN,
"FGMultiplayMgr::init - already initialised");
1103 SGPropertyNode* propOnline =
fgGetNode(
"/sim/multiplay/online",
true);
1104 propOnline->setBoolValue(
false);
1105 propOnline->setAttribute(SGPropertyNode::PRESERVE,
true);
1110 short rxPort =
fgGetInt(
"/sim/multiplay/rxport");
1111 string rxAddress =
fgGetString(
"/sim/multiplay/rxhost");
1112 short txPort =
fgGetInt(
"/sim/multiplay/txport", 5000);
1113 string txAddress =
fgGetString(
"/sim/multiplay/txhost");
1114 bool broadcast =
fgGetBool(
"/sim/multiplay/broadcast");
1116 int txRateHz =
fgGetInt(
"/sim/multiplay/tx-rate-hz", 10);
1121 mDt = 1.0 / txRateHz;
1122 mNextTransmitTime = sg_random() * mDt;
1123 SG_LOG(SG_NETWORK, SG_DEBUG,
"initial MP time: " << mNextTransmitTime);
1125 mCallsign =
fgGetString(
"/sim/multiplay/callsign");
1126 fgGetNode(
"/sim/multiplay/callsign",
true)->setAttribute(SGPropertyNode::PRESERVE,
true);
1128 if ((!txAddress.empty()) && (txAddress!=
"0")) {
1129 mServer.set(txAddress.c_str(), txPort);
1130 if (strncmp (mServer.getHost(),
"0.0.0.0", 8) == 0) {
1131 mHaveServer =
false;
1132 SG_LOG(SG_NETWORK, SG_ALERT,
1133 "Cannot enable multiplayer mode: resolving MP server address '"
1134 << txAddress <<
"' failed.");
1137 SG_LOG(SG_NETWORK, SG_INFO,
"FGMultiplayMgr - have server");
1143 SG_LOG(SG_NETWORK, SG_INFO,
"FGMultiplayMgr - multiplayer mode disabled (no MP server specified).");
1148 SG_LOG(SG_NETWORK, SG_ALERT,
1149 "Cannot enable multiplayer mode: No receiver port specified.");
1152 if (mCallsign.empty())
1153 mCallsign =
"JohnDoe";
1154 SG_LOG(SG_NETWORK,SG_INFO,
"FGMultiplayMgr::init-txaddress= "<<txAddress);
1155 SG_LOG(SG_NETWORK,SG_INFO,
"FGMultiplayMgr::init-txport= "<<txPort );
1156 SG_LOG(SG_NETWORK,SG_INFO,
"FGMultiplayMgr::init-rxaddress="<<rxAddress );
1157 SG_LOG(SG_NETWORK,SG_INFO,
"FGMultiplayMgr::init-rxport= "<<rxPort);
1158 SG_LOG(SG_NETWORK,SG_INFO,
"FGMultiplayMgr::init-callsign= "<<mCallsign);
1160 mSocket.reset(
new simgear::Socket());
1161 if (!mSocket->open(
false)) {
1162 SG_LOG( SG_NETWORK, SG_ALERT,
1163 "Cannot enable multiplayer mode: creating data socket failed." );
1166 mSocket->setBlocking(
false);
1168 mSocket->setBroadcast(
true);
1170 if (mSocket->bind(rxAddress.c_str(), rxPort) != 0) {
1171 SG_LOG( SG_NETWORK, SG_ALERT,
1172 "Cannot enable multiplayer mode: binding receive socket failed. "
1173 << strerror(errno) <<
"(errno " << errno <<
")");
1177 mPropertiesChanged =
true;
1179 globals->get_props()->addChangeListener(mListener,
false);
1181 fgSetBool(
"/sim/multiplay/online",
true);
1182 mInitialised =
true;
1185 SG_LOG(SG_NETWORK, SG_MANDATORY_INFO,
"Multiplayer mode active");
1197 SG_LOG(SG_NETWORK, SG_DEBUG,
"Creating socket to MP IRC service " + host +
" on port " + port);
1199 _mpirc = std::make_unique<IRCConnection>(
MPIRC_NICK_PREFIX + mCallsign, host, port);
1200 _mpirc->setupProperties(
"/network/mpirc/");
1202 _cpdlc = std::make_unique<CPDLCManager>(_mpirc.get());
1215 fgSetBool(
"/sim/multiplay/online",
false);
1217 if (mSocket.get()) {
1222 MultiPlayerMap::iterator it = mMultiPlayerMap.begin(),
1223 end = mMultiPlayerMap.end();
1224 for (; it != end; ++it) {
1225 it->second->setDie(
true);
1227 mMultiPlayerMap.clear();
1230 globals->get_props()->removeChangeListener(mListener);
1235 mInitialised =
false;
1237 if (_cpdlc) _cpdlc->disconnect();
1238 if (_mpirc) _mpirc->quit();
1265 memset(&
Msg, 0,
sizeof(
Msg));
1334 bool isCorrupted =
false;
1335 isCorrupted |= ((SGMisc<double>::isNaN(motionInfo.
time )) ||
1336 (SGMisc<double>::isNaN(motionInfo.
lag )) ||
1338 for (
unsigned i = 0; (
i < 3)&&(!isCorrupted); ++
i)
1340 isCorrupted |= ((osg::isNaN(motionInfo.
position(
i) ))||
1347 return !isCorrupted;
1353 int protocolToUse = getProtocolToUse();
1354 int transmitFilterPropertyBase = pMultiPlayTransmitPropertyBase->getIntValue();
1355 if ((! mInitialised) || (! mHaveServer))
1358 if (! mHaveServer) {
1359 SG_LOG( SG_NETWORK, SG_DEBUG,
"FGMultiplayMgr::SendMyPosition - no server");
1363 if (!isSane(motionInfo))
1367 SG_LOG(SG_NETWORK, SG_ALERT,
"FGMultiplayMgr::SendMyPosition - "
1368 <<
"Local data is invalid (NaN). Data not transmitted.");
1373 static unsigned msgLen = 0;
1374 T_PositionMsg* PosMsg = msgBuf.
posMsg();
1383 if (protocolToUse > 1)
1390 if (
fgGetBool(
"/sim/freeze/replay-state",
true)&&
1391 fgGetBool(
"/sim/multiplay/freeze-on-replay",
true))
1394 for (
unsigned i = 0 ;
i < 3; ++
i)
1408 for (
unsigned i = 0 ;
i < 3; ++
i)
1412 for (
unsigned i = 0 ;
i < 3; ++
i)
1416 for (
unsigned i = 0 ;
i < 3; ++
i)
1429 for (
unsigned i = 0 ;
i < 3; ++
i)
1431 for (
unsigned i = 0 ;
i < 3; ++
i)
1433 for (
unsigned i = 0 ;
i < 3; ++
i)
1435 for (
unsigned i = 0 ;
i < 3; ++
i)
1446 memset(&boolBuffer, 0,
sizeof(boolBuffer));
1460 std::vector<FGPropertyData*>::const_iterator it = motionInfo.
properties.begin();
1462 switch (mPropertyDefinition[(*it)->id]->TransmitAs) {
1465 struct BoolArrayBuffer *boolBuf =
nullptr;
1469 boolBuf = &boolBuffer[buffer_block];
1474 int bitidx = (*it)->id - boolBuf->
propertyId;
1475 if ((*it)->int_value)
1486 for (
int partition = 1; partition <= protocolToUse; partition++)
1488 std::vector<FGPropertyData*>::const_iterator it = motionInfo.
properties.begin();
1490 const struct IdPropertyList* propDef = mPropertyDefinition[(*it)->id];
1505 if (transmitFilterPropertyBase && !
IsIncludedInPacket(transmitFilterPropertyBase, propDef->
id))
1516 if ( (propDef->
version & 0xffff) == partition || (propDef->
version & 0xffff) > protocolToUse)
1518 if (ptr + 2 >= msgEnd)
1520 SG_LOG(SG_NETWORK, SG_ALERT,
"Multiplayer packet truncated prop id: " << (*it)->id <<
": " << propDef->
name);
1533 int transmit_type = (*it)->type;
1542 if (pMultiPlayDebugLevel->getIntValue() & 2)
1543 SG_LOG(SG_NETWORK, SG_INFO,
1544 "[SEND] pt " << partition <<
1545 ": buf[" << (ptr - data) *
sizeof(*ptr)
1546 <<
"] id=" << (*it)->id <<
" type " << transmit_type);
1555 switch (transmit_type) {
1565 short value = get_scaled_short((*it)->float_value, 10.0);
1571 short value = get_scaled_short((*it)->float_value, 100.0);
1577 short value = get_scaled_short((*it)->float_value, 1000.0);
1583 short value = get_scaled_short((*it)->float_value, 10000.0);
1590 short value = get_scaled_short((*it)->float_value, 32767.0);
1600 SG_LOG(SG_NETWORK, SG_WARN,
"Unexpected prop id with type TT_BOOLARRAY: " << (*it)->id);
1604 if (!boolBuffer[boolIdx].propertyId)
1610 if (ptr + 2 >= msgEnd)
1612 SG_LOG(SG_NETWORK, SG_ALERT,
"Multiplayer packet truncated prop id: " << boolBuffer[boolIdx].propertyId <<
": multiplay/generic/bools[" << boolIdx * 30 <<
"]");
1617 boolBuffer[boolIdx].propertyId = 0;
1620 case simgear::props::INT:
1621 case simgear::props::BOOL:
1622 case simgear::props::LONG:
1626 case simgear::props::FLOAT:
1627 case simgear::props::DOUBLE:
1631 case simgear::props::STRING:
1632 case simgear::props::UNSPECIFIED:
1634 if (protocolToUse > 1)
1639 const char* lcharptr = (*it)->string_value;
1643 uint32_t len = strlen(lcharptr);
1648 SG_LOG(SG_NETWORK, SG_ALERT,
"Multiplayer property truncated at MAX_TEXT_SIZE in string " << (*it)->id);
1651 char *encodeStart = (
char*)ptr;
1652 char *msgEndbyte = (
char*)msgEnd;
1654 if (encodeStart + 2 + len >= msgEndbyte)
1656 SG_LOG(SG_NETWORK, SG_ALERT,
"Multiplayer property not sent (no room) string " << (*it)->id);
1661 encodeStart = (
char*)ptr;
1667 if (encodeStart + 2 >= msgEndbyte)
1669 SG_LOG(SG_NETWORK, SG_ALERT,
"Multiplayer packet truncated in string " << (*it)->id <<
" lcount " << lcount);
1672 *encodeStart++ = *lcharptr++;
1691 const char* lcharptr = (*it)->string_value;
1697 uint32_t len = strlen(lcharptr);
1701 SG_LOG(SG_NETWORK, SG_ALERT,
"Multiplayer property truncated at MAX_TEXT_SIZE in string " << (*it)->id);
1707 if (ptr + 2 + ((len + 3) & ~3) >= msgEnd)
1709 SG_LOG(SG_NETWORK, SG_ALERT,
"Multiplayer property not sent (no room) string " << (*it)->id);
1722 if (ptr + 2 >= msgEnd)
1724 SG_LOG(SG_NETWORK, SG_ALERT,
"Multiplayer packet truncated in string " << (*it)->id <<
" lcount " << lcount);
1732 while ((lcount % 4) != 0)
1734 if (ptr + 2 >= msgEnd)
1736 SG_LOG(SG_NETWORK, SG_ALERT,
"Multiplayer packet truncated in string " << (*it)->id <<
" lcount " << lcount);
1766 msgLen =
reinterpret_cast<char*
>(ptr) - msgBuf.Msg;
1781 pXmitLen->setIntValue(msgLen);
1783 if (pMultiPlayDebugLevel->getIntValue() & 2)
1785 SG_LOG(SG_NETWORK, SG_INFO,
1786 "[SEND] Packet len " << msgLen);
1788 if (pMultiPlayDebugLevel->getIntValue() & 4)
1789 SG_LOG_HEXDUMP(SG_NETWORK, SG_INFO, data, (ptr - data) *
sizeof(*ptr));
1793 if (pMultiPlayDebugLevel->getIntValue() & 1)
1795 long stamp = SGTimeStamp::now().getSeconds();
1796 ProcessPosMsg(msgBuf, mServer, stamp);
1800 mSocket->sendto(msgBuf.Msg, msgLen, 0, &mServer);
1801 SG_LOG(SG_NETWORK, SG_BULK,
"FGMultiplayMgr::SendMyPosition");
1804short FGMultiplayMgr::get_scaled_short(
double v,
double scale)
1806 float nv = v *
scale;
1807 if (nv >= 32767)
return 32767;
1808 if (nv <= -32767)
return -32767;
1809 short rv = (short)nv;
1825 if (!mInitialised || !mHaveServer)
1834 unsigned iNextBlockPosition = 0;
1838 while (iNextBlockPosition < MsgText.length()) {
1839 strncpy (ChatMsg.
Text,
1843 memcpy (Msg, &MsgHdr,
sizeof(
T_MsgHdr));
1860int FGMultiplayMgr::GetMsgNetwork(MsgBuf& msgBuf, simgear::IPAddress& SenderAddress)
1871 int RecvStatus = mSocket->recvfrom(msgBuf.Msg,
sizeof(msgBuf.Msg), 0,
1876 if (RecvStatus == 0)
1882 if ((RecvStatus < 0)&&
1883 ((errno == EAGAIN) || (errno == 0)))
1892 if (::WSAGetLastError() != WSAEWOULDBLOCK)
1895 SG_LOG(SG_NETWORK, SG_INFO,
"FGMultiplayMgr::MP_ProcessData - Unable to receive data. WSAGetLastError=" << ::WSAGetLastError());
1898 SG_LOG(SG_NETWORK, SG_DEBUG,
"FGMultiplayMgr::MP_ProcessData - Unable to receive data. "
1899 << strerror(errno) <<
"(errno " << errno <<
")");
1904 T_MsgHdr* MsgHdr = msgBuf.msgHdr();
1920int FGMultiplayMgr::GetMsg(MsgBuf& msgBuf, simgear::IPAddress& SenderAddress)
1922 if (pReplayState->getIntValue()) {
1928 if (mReplayMessageQueue.empty()) {
1932 int RecvStatus = GetMsgNetwork(msgBuf, SenderAddress);
1933 if (RecvStatus == 0) {
1940 std::shared_ptr<std::vector<char>> data(
new std::vector<char>(RecvStatus));
1941 memcpy( &data->front(), msgBuf.Msg, RecvStatus);
1942 mRecordMessageQueue.push_back(data);
1956 mReplayMessageQueue.pop_front();
1962 SG_LOG(SG_NETWORK, SG_BULK,
1964 <<
". num remaining messages=" << mReplayMessageQueue.size());
1971 int length = GetMsgNetwork(msgBuf, SenderAddress);
1975 std::shared_ptr<std::vector<char>> data(
new std::vector<char>(length));
1976 memcpy( &data->front(), msgBuf.Msg, length);
1977 mRecordMessageQueue.push_back(data);
1999 long stamp = SGTimeStamp::now().getSeconds();
2005 const double mpTime =
globals->get_subsystem<
TimeManager>()->getMPProtocolClockSec();
2009 if ((mpTime >= mNextTransmitTime) || (mpTime < (mNextTransmitTime - 2.0 * mDt))) {
2020 simgear::IPAddress SenderAddress;
2021 int RecvStatus = GetMsg(msgBuf, SenderAddress);
2022 if (RecvStatus == 0) {
2026 bytes = (ssize_t) RecvStatus;
2027 if (bytes <=
static_cast<ssize_t
>(
sizeof(
T_MsgHdr))) {
2028 SG_LOG( SG_NETWORK, SG_INFO,
"FGMultiplayMgr::MP_ProcessData - "
2029 <<
"received message with insufficient data" );
2038 SG_LOG(SG_NETWORK, SG_INFO,
"FGMultiplayMgr::MP_ProcessData - "
2039 <<
"message has invalid magic number!" );
2043 SG_LOG(SG_NETWORK, SG_INFO,
"FGMultiplayMgr::MP_ProcessData - "
2044 <<
"message has invalid protocol number!" );
2047 if (
static_cast<ssize_t
>(MsgHdr->
MsgLen) != bytes) {
2048 SG_LOG(SG_NETWORK, SG_INFO,
"FGMultiplayMgr::MP_ProcessData - "
2049 <<
"message from " << MsgHdr->
Callsign <<
" has invalid length!");
2053 if (pMultiPlayDebugLevel->getIntValue() & 16)
2054 SG_LOG_HEXDUMP(SG_NETWORK, SG_INFO, msgBuf.
Msg, MsgHdr->
MsgLen);
2059 switch (MsgHdr->
MsgId) {
2061 ProcessChatMsg(msgBuf, SenderAddress);
2064 ProcessPosMsg(msgBuf, SenderAddress, stamp);
2072 SG_LOG(SG_NETWORK, SG_INFO,
"FGMultiplayMgr::MP_ProcessData - "
2073 <<
"Unknown message Id received: " << MsgHdr->
MsgId );
2076 }
while (bytes > 0);
2079 MultiPlayerMap::iterator it = mMultiPlayerMap.begin();
2080 while (it != mMultiPlayerMap.end()) {
2081 if (it->second->getLastTimestamp() + 10 < stamp) {
2082 std::string
name = it->first;
2083 it->second->setDie(
true);
2084 mMultiPlayerMap.erase(it);
2085 it = mMultiPlayerMap.upper_bound(
name);
2101 SG_LOG(SG_NETWORK, SG_DEBUG,
"Clearing all motion info");
2102 for (
auto it: mMultiPlayerMap) {
2103 it.second->clearMotionInfo();
2107void FGMultiplayMgr::Send(
double mpTime)
2115 mNextTransmitTime += floor(1.0 + (mpTime - mNextTransmitTime) / mDt) * mDt;
2127 motionInfo.
time = mpTime;
2128 motionInfo.
lag = mDt;
2135 SGGeod geod = SGGeod::fromRadFt(lon, lat, ifce.
get_Altitude());
2137 motionInfo.
position = SGVec3d::fromGeod(geod);
2141 SGQuatf qEc2Hl = SGQuatf::fromLonLatRad((
float)lon, (
float)lat);
2143 float heading = ifce.
get_Psi();
2146 SGQuatf hlOr = SGQuatf::fromYawPitchRoll(heading, pitch, roll);
2171 motionInfo.
linearVel = SGVec3f::zeros();
2177 PropertyMap::iterator it;
2178 for (it = mPropertyMap.begin(); it != mPropertyMap.end(); ++it) {
2179 FGPropertyData* pData =
new FGPropertyData;
2180 pData->
id = it->first;
2183 switch (
static_cast<int>(pData->
type)) {
2193 pData->
int_value = it->second->getIntValue();
2200 case props::UNSPECIFIED:
2204 string cstr = it->second->getStringValue();
2205 size_t len = cstr.length();
2229 SendMyPosition(motionInfo);
2240 const simgear::IPAddress& SenderAddress,
long stamp)
2242 const T_MsgHdr* MsgHdr = Msg.
msgHdr();
2243 if (MsgHdr->
MsgLen <
sizeof(T_MsgHdr) +
sizeof(T_PositionMsg)) {
2244 SG_LOG(SG_NETWORK, SG_DEBUG,
"FGMultiplayMgr::MP_ProcessData - "
2245 <<
"Position message received with insufficient data");
2248 const T_PositionMsg* PosMsg = Msg.
posMsg();
2249 FGExternalMotionData motionInfo;
2250 int fallback_model_index = 0;
2253 for (
unsigned i = 0;
i < 3; ++
i)
2256 for (
unsigned i = 0;
i < 3; ++
i)
2258 motionInfo.
orientation = SGQuatf::fromAngleAxis(angleAxis);
2259 for (
unsigned i = 0;
i < 3; ++
i)
2261 for (
unsigned i = 0;
i < 3; ++
i)
2263 for (
unsigned i = 0;
i < 3; ++
i)
2265 for (
unsigned i = 0;
i < 3; ++
i)
2269 if (!isSane(motionInfo))
2272 SG_LOG(SG_NETWORK, SG_DEBUG,
"FGMultiplayMgr::ProcessPosMsg - "
2273 <<
"Position message with invalid data (NaN) received from "
2320 bool short_int_encoded =
false;
2321 if (
id & 0xffff0000)
2327 short_int_encoded =
true;
2330 if (pMultiPlayDebugLevel->getIntValue() & 8)
2331 SG_LOG(SG_NETWORK, SG_INFO,
2332 "[RECV] add " << std::hex << xdr
2334 ": buf[" << ((
char*)xdr) - ((
char*)data)
2336 <<
" SIenc " << short_int_encoded);
2343 FGPropertyData* pData =
new FGPropertyData;
2357 switch (pData->
type) {
2358 case simgear::props::BOOL:
2366 bool first_bool =
true;
2368 for (
int bitidx = 0; bitidx <= 30; bitidx++)
2371 const IdPropertyList* plistBool =
findProperty(
id + bitidx);
2378 pData =
new FGPropertyData;
2380 pData->
id =
id + bitidx;
2381 pData->
int_value = (val & (1 << bitidx)) != 0;
2382 pData->
type = simgear::props::BOOL;
2392 case simgear::props::INT:
2393 case simgear::props::LONG:
2394 if (short_int_encoded)
2397 pData->
type = simgear::props::INT;
2406 case simgear::props::FLOAT:
2407 case simgear::props::DOUBLE:
2408 if (short_int_encoded)
2437 case simgear::props::STRING:
2438 case simgear::props::UNSPECIFIED:
2441 if (short_int_encoded)
2443 uint32_t length = int_value;
2446 char *cptr = (
char*)xdr;
2447 for (
unsigned i = 0;
i < length;
i++)
2467 for (
unsigned i = 0;
i < length;
i++)
2476 while ((length % 4) != 0)
2489 SG_LOG(SG_NETWORK, SG_DEBUG,
"Unknown Prop type " << pData->
id <<
" " << pData->
type);
2500 fallback_model_index = pData->
int_value;
2501 SG_LOG(SG_NETWORK, SG_DEBUG,
"Found Fallback model index in message " << fallback_model_index);
2508 SG_LOG(SG_NETWORK, SG_DEBUG,
"FGMultiplayMgr::ProcessPosMsg - "
2509 "message from " << MsgHdr->
Callsign <<
" has unknown property id "
2520 mp = addMultiplayer(MsgHdr->
Callsign, PosMsg->
Model, fallback_model_index);
2528 string callsign = pLogRawSpeedMultiplayer->getStringValue();
2529 if (!callsign.empty() && callsign ==
string(MsgHdr->
Callsign)) {
2530 static SGVec3d s_pos_prev;
2531 static double s_simtime_prev = -1;
2533 double dt = motionInfo.
time - s_simtime_prev;
2534 if (s_simtime_prev != -1 && dt > 0) {
2535 double distance = length(pos - s_pos_prev);
2536 double speed = distance / dt;
2537 SGPropertyNode* n =
fgGetNode(
"/sim/replay/log-raw-speed-multiplayer-values",
true );
2538 n = n->addChild(
"value");
2539 n->setDoubleValue(speed);
2540 SG_LOG(SG_GENERAL, SG_DEBUG,
"Multiplayer aircraft callsign=" << callsign <<
":"
2541 <<
" motionInfo.time=" << motionInfo.
time
2543 <<
" distance=" << distance
2544 <<
" speed=" << speed
2545 <<
" s_pos_prev=" << s_pos_prev
2547 <<
" n->getPath()=" << n->getPath(
true )
2550 s_simtime_prev = motionInfo.
time;
2559 if (mRecordMessageQueue.empty()) {
2563 auto ret = mRecordMessageQueue.front();
2564 mRecordMessageQueue.pop_front();
2570 mReplayMessageQueue.push_back(message);
2582FGMultiplayMgr::ProcessChatMsg(
const MsgBuf& Msg,
2583 const simgear::IPAddress& SenderAddress)
2585 const T_MsgHdr* MsgHdr = Msg.msgHdr();
2587 SG_LOG( SG_NETWORK, SG_DEBUG,
"FGMultiplayMgr::MP_ProcessData - "
2588 <<
"Chat message received with insufficient data" );
2592 char *chatStr =
new char[MsgHdr->
MsgLen -
sizeof(T_MsgHdr)];
2593 const T_ChatMsg* ChatMsg
2594 =
reinterpret_cast<const T_ChatMsg *
>(Msg.Msg +
sizeof(T_MsgHdr));
2595 strncpy(chatStr, ChatMsg->Text,
2596 MsgHdr->
MsgLen -
sizeof(T_MsgHdr));
2597 chatStr[MsgHdr->
MsgLen -
sizeof(T_MsgHdr) - 1] =
'\0';
2599 SG_LOG (SG_NETWORK, SG_WARN,
"Chat [" << MsgHdr->
Callsign <<
"]"
2607FGMultiplayMgr::FillMsgHdr(
T_MsgHdr *MsgHdr,
int MsgId,
unsigned _len)
2612 len =
sizeof(T_MsgHdr) +
sizeof(T_ChatMsg);
2618 len =
sizeof(T_MsgHdr);
2634static void copy_default(SGPropertyNode* from,
const char* path, SGPropertyNode* to) {
2635 SGPropertyNode* from_ = from->getNode(path);
2637 if (!to->getNode(path)) {
2638 to->setDoubleValue(path, from_->getDoubleValue());
2646 for (
size_t i=0;
i<s.size(); ++
i) {
2648 if (
i==0 && !isalpha(c) && c!=
'_') c =
'_';
2649 if (!isalnum(c) && c!=
'.' && c!=
'_' && c!=
'-') c =
'_';
2656FGMultiplayMgr::addMultiplayer(
const std::string& callsign,
2657 const std::string& modelName,
2658 const int fallback_model_index)
2660 if (0 < mMultiPlayerMap.count(callsign))
2661 return mMultiPlayerMap[callsign].get();
2663 FGAIMultiplayer* mp =
new FGAIMultiplayer;
2664 mp->
setPath(modelName.c_str());
2667 mMultiPlayerMap[callsign] = mp;
2669 auto aiMgr =
globals->get_subsystem<FGAIManager>();
2689 SGPropertyNode_ptr set;
2691 if (simgear::strutils::ends_with(modelName,
".xml")
2692 && simgear::strutils::starts_with(modelName,
"Aircraft/")) {
2694 std::string tail = modelName.substr(strlen(
"Aircraft/"));
2701 fgdata_aircraft.append(
"Aircraft");
2702 dirs.push_back(fgdata_aircraft);
2705 PathList::const_iterator it = std::find_if(dirs.begin(), dirs.end(),
2708 model_file.append(tail);
2709 return model_file.exists();
2712 if (it != dirs.end()) {
2719 std::string model_file_head = it->str() +
'/';
2720 std::string model_file_tail = model_file.str().substr(model_file_head.size());
2721 ssize_t
p = model_file_tail.find(
'/');
2722 std::string aircraft_dir = model_file_head + model_file_tail.substr(0,
p);
2723 simgear::Dir dir(aircraft_dir);
2724 std::vector<SGPath> dir_contents = dir.children(0 ,
"-set.xml");
2728 for (
auto path: dir_contents) {
2737 set =
new SGPropertyNode;
2740 readProperties(path, set);
2742 catch (
const std::exception & ) {
2746 SGPropertyNode* sim_model_path = set->getNode(
"sim/model/path");
2747 if (sim_model_path && sim_model_path->getStringValue() == modelName) {
2760 SGPropertyNode* global_set = mp->
_getProps()->addChild(
"set");
2761 SGPropertyNode* global_sim = global_set->addChild(
"sim");
2762 double sim_chase_distance_m = -25;
2764 SGPropertyNode* sim = set->getChild(
"sim");
2770 SGPropertyNode* sim_chase_distance_node = sim->getChild(
"chase-distance-m");
2771 if (sim_chase_distance_node) {
2772 sim_chase_distance_m = sim_chase_distance_node->getDoubleValue();
2773 if (sim_chase_distance_m > 0) {
2774 sim_chase_distance_m = -sim_chase_distance_m;
2775 SG_LOG(SG_VIEW, SG_ALERT,
2776 "Multiplayer aircraft's " << sim_chase_distance_node->getPath()
2777 <<
" is positive; correcting to: " << sim_chase_distance_m);
2780 SG_LOG(SG_VIEW, SG_DEBUG,
"setting to " << sim_chase_distance_m <<
": " << global_sim->getPath());
2781 global_sim->setDoubleValue(
"chase-distance-m", sim_chase_distance_m);
2783 simgear::PropertyList views = sim->getChildren(
"view");
2784 for (
auto view: views) {
2785 int view_index = view->getIndex();
2786 SGPropertyNode* global_view = global_sim->addChild(
"view", view_index,
false );
2787 assert(global_view->getIndex() == view_index);
2788 SGPropertyNode* config = view->getChild(
"config");
2789 SGPropertyNode* global_config = global_view->addChild(
"config");
2791 int config_children_n = config->nChildren();
2792 for (
int i=0;
i<config_children_n; ++
i) {
2793 SGPropertyNode* node = config->getChild(
i);
2794 global_config->setDoubleValue(node->getNameString(), node->getDoubleValue());
2809 SGPropertyNode* view_1 = global_sim->getNode(
"view", 1);
2810 std::initializer_list<int> views_with_default_z_offset_m = {1, 2, 3, 5, 7};
2811 for (
int j: views_with_default_z_offset_m) {
2812 SGPropertyNode* v = global_sim->getChild(
"view", j);
2814 v = global_sim->addChild(
"view", j,
false );
2816 SGPropertyNode* z_offset_m = v->getChild(
"config/z-offset-m");
2820 v->setDoubleValue(
"config/z-offset-m", sim_chase_distance_m);
2841 if (0 < mMultiPlayerMap.count(callsign))
2842 return mMultiPlayerMap[callsign].get();
2848FGMultiplayMgr::findProperties()
2850 if (!mPropertiesChanged) {
2854 mPropertiesChanged =
false;
2864 if (mPropertyMap.find(
id) != mPropertyMap.end()) {
2868 mPropertyMap[id] = pNode;
2870 SG_LOG(SG_NETWORK, SG_DEBUG,
"activating MP property:" << pNode->getPath());
2877 SGSubsystemMgr::POST_FDM,
2878 {{
"ai-model", SGSubsystemMgr::Dependency::HARD},
2879 {
"flight", SGSubsystemMgr::Dependency::HARD},
2880 {
"mp", SGSubsystemMgr::Dependency::HARD},
2881 {
"time", SGSubsystemMgr::Dependency::HARD}});
Wrap an FDM implementation in a subsystem with standard semantics Notably, deal with the various case...
void setFallbackModelIndex(const int i)
void setCallSign(const std::string &)
SGPropertyNode * _getProps() const
void setPath(const char *model)
void addMotionInfo(FGExternalMotionData &motionInfo, long stamp)
void addPropertyId(unsigned id, const char *name)
PathList get_aircraft_paths() const
SGPropertyNode * get_props()
const SGPath & get_fg_root() const
friend class MPPropertyListener
void update(double dt) override
CPDLCManager * getCPDLC()
FGAIMultiplayer * getMultiplayer(const std::string &callsign)
std::shared_ptr< std::vector< char > > popMessageHistory()
void SendTextMessage(const std::string &sMsgText)
void pushMessageHistory(std::shared_ptr< std::vector< char > > message)
Encapsulate the FDM properties in some getter/setter helpers.
double get_Q_body() const
double get_Latitude() const
double get_Longitude() const
double get_R_body() const
double get_P_body() const
double get_Altitude() const
virtual void childAdded(SGPropertyNode *, SGPropertyNode *)
MPPropertyListener(FGMultiplayMgr *mp)
void setTarget(SGPropertyNode_ptr value)
Set the target property where the server-list gets stored.
void setService(const std::string &value)
Set the service name to use for the query.
void setDnsName(const std::string &value)
Set the dns domain name to query.
virtual void onSuccess()
Handler to be called if the resolver process finishes with success.
void setProtocol(const std::string &value)
Set the protocol name to use for the query.
virtual void onFailure()
Handler to be called if the resolver process terminates with an error.
int fgGetInt(const char *name, int defaultValue)
Get an int value for a property.
std::string fgGetString(const char *name, const char *defaultValue)
Get a string value for a property.
bool fgSetInt(const char *name, int val)
Set an int value for a property.
std::vector< SGPath > PathList
const std::string IRC_DEFAULT_PORT
#define MAX_MODEL_NAME_LEN
#define UNUSABLE_POS_DATA_ID
#define OLD_OLD_POS_DATA_ID
const int BOOLARRAY_BLOCKSIZE
SGSubsystemMgr::Registrant< FGMultiplayMgr > registrantFGMultiplayMgr(SGSubsystemMgr::POST_FDM, {{"ai-model", SGSubsystemMgr::Dependency::HARD}, {"flight", SGSubsystemMgr::Dependency::HARD}, {"mp", SGSubsystemMgr::Dependency::HARD}, {"time", SGSubsystemMgr::Dependency::HARD}})
static xdr_data_t * encode_launchbar_state_for_transmission(const IdPropertyList *propDef, const xdr_data_t *_xdr, FGPropertyData *p)
const int BOOLARRAY_BASE_3
const int BOOLARRAY_START_ID
static const IdPropertyList sIdPropertyList[]
const int BOOLARRAY_BASE_2
static xdr_data_t * decode_received_launchbar_state(const IdPropertyList *propDef, const xdr_data_t *_xdr, FGPropertyData *p)
static const IdPropertyList * findProperty(unsigned id)
const int FALLBACK_MODEL_ID
const int BOOLARRAY_BASE_1
static bool do_multiplayer_refreshserverlist(const SGPropertyNode *arg, SGPropertyNode *root)
static bool do_cpdlc_connect(const SGPropertyNode *arg, SGPropertyNode *root)
static bool do_cpdlc_disconnect(const SGPropertyNode *arg, SGPropertyNode *root)
static void copy_default(SGPropertyNode *from, const char *path, SGPropertyNode *to)
const int EMESARYBRIDGE_BASE
static std::string makeStringPropertyNameSafe(const std::string &s)
static bool do_cpdlc_next_msg(const SGPropertyNode *arg, SGPropertyNode *root)
const int EMESARYBRIDGETYPE_BASE
static bool do_multiplayer_connect(const SGPropertyNode *arg, SGPropertyNode *root)
const unsigned int numProperties
static bool do_cpdlc_send_msg(const SGPropertyNode *arg, SGPropertyNode *root)
const int BOOLARRAY_END_ID
const int MAX_BOOL_BUFFERS
static bool IsIncludedInPacket(int filter_base, int property_id)
static bool do_multiplayer_disconnect(const SGPropertyNode *arg, SGPropertyNode *root)
const int V2_PROP_ID_PROTOCOL
const std::string MPIRC_NICK_PREFIX
const std::string MPIRC_SERVER_HOST_PROPERTY
const std::string MPIRC_SERVER_PORT_PROPERTY
const std::string MPIRC_SERVER_HOST_DEFAULT
void addSentryTag(const char *, const char *)
bool fgGetBool(char const *name, bool def)
Get a bool value for a property.
bool fgSetBool(char const *name, bool val)
Set a bool value for a property.
double fgGetDouble(const char *name, double defaultValue)
Get a double value for a property.
bool fgSetString(char const *name, char const *str)
Set a string value for a property.
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
static void replayMessage(FGReplayInternal &self, double time)
std::vector< FGPropertyData * > properties
simgear::props::Type type
TransmissionType TransmitAs
xdr_data_t *(* encode_for_transmit)(const IdPropertyList *propDef, const xdr_data_t *, FGPropertyData *)
simgear::props::Type type
xdr_data_t *(* decode_received)(const IdPropertyList *propDef, const xdr_data_t *, FGPropertyData *)
xdr_data_t RequestedRangeNm
xdr_data_t angularAccel[3]
xdr_data_t orientation[3]
xdr_data_t linearAccel[3]
xdr_data_t XDR_encode_int32(const int32_t &n_Val)
xdr_data_t XDR_encode_shortints32(const int v1, const int v2)
uint32_t XDR_decode_uint32(const xdr_data_t &n_Val)
double XDR_decode_double(const xdr_data2_t &d_Val)
xdr_data2_t XDR_encode_double(const double &d_Val)
xdr_data_t XDR_encode_int8(const int8_t &n_Val)
int8_t XDR_decode_int8(const xdr_data_t &n_Val)
int32_t XDR_decode_int32(const xdr_data_t &n_Val)
xdr_data_t XDR_encode_float(const float &f_Val)
float XDR_decode_float(const xdr_data_t &f_Val)
void XDR_decode_shortints32(const xdr_data_t &n_Val, int &v1, int &v2)
xdr_data_t XDR_encode_uint32(const uint32_t &n_Val)
The buffer that holds a multi-player message, suitably aligned.
const T_MsgHdr * msgHdr() const
const T_PositionMsg * posMsg() const
const xdr_data_t * propsRecvdEnd() const
xdr_data_t * propsRecvdEnd()
The end of properties actually in the buffer.
const xdr_data_t * propsEnd() const
xdr_data_t * properties()
xdr_data_t * propsEnd()
The end of the properties buffer.
const xdr_data_t * properties() const