diff --git a/src/MultiPlayer/mpmessages.hxx b/src/MultiPlayer/mpmessages.hxx index 38e7fea58..5f07bb05e 100644 --- a/src/MultiPlayer/mpmessages.hxx +++ b/src/MultiPlayer/mpmessages.hxx @@ -55,6 +55,7 @@ const uint32_t PROTO_VER = 0x00010001; // 1.1 #define OLD_PROP_MSG_ID 5 #define RESET_DATA_ID 6 #define POS_DATA_ID 7 +#define MP_2017_DATA_ID 8 // XDR demands 4 byte alignment, but some compilers use8 byte alignment // so it's safe to let the overall size of a network message be a @@ -70,7 +71,7 @@ struct T_MsgHdr { xdr_data_t Version; // Protocoll version xdr_data_t MsgId; // Message identifier xdr_data_t MsgLen; // absolute length of message - xdr_data_t ReplyAddress; // (player's receiver address + xdr_data_t RequestedRangeNm; // obsolete field (ReplyAddress) reused to request a range to fgms xdr_data_t ReplyPort; // player's receiver port char Callsign[MAX_CALLSIGN_LEN]; // Callsign used by the player }; diff --git a/src/MultiPlayer/multiplaymgr.cxx b/src/MultiPlayer/multiplaymgr.cxx index 823614571..8f855a68d 100644 --- a/src/MultiPlayer/multiplaymgr.cxx +++ b/src/MultiPlayer/multiplaymgr.cxx @@ -59,195 +59,370 @@ using namespace std; #define MAX_PACKET_SIZE 1200 #define MAX_TEXT_SIZE 128 +/* + * With the MP2017(V2) protocol it should be possible to transmit using a different type/encoding than the property has, + * so it should be possible to transmit a bool as + */ +enum TransmissionType { + TT_ASIS = 0, // transmit as defined in the property. This is the default + TT_BOOL = simgear::props::BOOL, + TT_INT = simgear::props::INT, + TT_FLOAT = simgear::props::FLOAT, + TT_STRING = simgear::props::STRING, + TT_SHORTINT = 0x100, + TT_SHORT_FLOAT_NORM = 0x101, // -1 .. 1 encoded into a short int (16 bit) + TT_SHORT_FLOAT_1 = 0x102, //range -3276.7 .. 3276.7 float encoded into a short int (16 bit) + TT_SHORT_FLOAT_2 = 0x103, //range -327.67 .. 327.67 float encoded into a short int (16 bit) + TT_SHORT_FLOAT_3 = 0x104, //range -32.767 .. 32.767 float encoded into a short int (16 bit) + TT_SHORT_FLOAT_4 = 0x105, //range -3.2767 .. 3.2767 float encoded into a short int (16 bit) + TT_BOOLARRAY, + TT_CHAR, +}; +/* + * Definitions for the version of the protocol to use to transmit the items defined in the IdPropertyList + * + * The MP2017(V2) protocol allows for much better packing of strings, new types that are transmitted in 4bytes by transmitting + * with short int (sometimes scaled) for the values (a lot of the properties that are transmitted will pack nicely into 16bits). + * The MP2017(V2) protocol also allows for properties to be transmitted automatically as a different type and the encode/decode will + * take this into consideration. + * The pad magic is used to force older clients to use verifyProperties and as the first property transmitted is short int encoded it + * will cause the rest of the packet to be discarded. This is the section of the packet that contains the properties defined in the list + * here - the basic motion properties remain compatible, so the older client will see just the model, not chat, not animations etc. + */ +const int V1_1_PROP_ID = 1; +const int V1_1_2_PROP_ID = 2; +const int V2_PAD_MAGIC = 0x1face002; + +/* + * definition of properties that are to be transmitted. + * New for 2017.2: + * 1. TransmitAs - this causes the property to be transmitted on the wire using the + * specified format transparently. + * 2. version - the minimum version of the protocol that is required to transmit a property. + * Does not apply to incoming properties - as these will be decoded correctly when received + * 3. Convert; not implemented. Planned to allow property specific conversion rules to be applied + */ struct IdPropertyList { - unsigned id; - const char* name; - simgear::props::Type type; + unsigned id; + const char* name; + simgear::props::Type type; + TransmissionType TransmitAs; + int version; + int(*convert)(int direction, xdr_data_t*, FGPropertyData*); }; static const IdPropertyList* findProperty(unsigned id); - + +/* + * not yet used method to avoid transmitting a string for something that should always have been + * an integer + */ +static int convert_launchbar_state(int direction, xdr_data_t*, FGPropertyData*) +{ + return 0; // no conversion performed +} + // A static map of protocol property id values to property paths, // This should be extendable dynamically for every specific aircraft ... // For now only that static list static const IdPropertyList sIdPropertyList[] = { - {100, "surface-positions/left-aileron-pos-norm", simgear::props::FLOAT}, - {101, "surface-positions/right-aileron-pos-norm", simgear::props::FLOAT}, - {102, "surface-positions/elevator-pos-norm", simgear::props::FLOAT}, - {103, "surface-positions/rudder-pos-norm", simgear::props::FLOAT}, - {104, "surface-positions/flap-pos-norm", simgear::props::FLOAT}, - {105, "surface-positions/speedbrake-pos-norm", simgear::props::FLOAT}, - {106, "gear/tailhook/position-norm", simgear::props::FLOAT}, - {107, "gear/launchbar/position-norm", simgear::props::FLOAT}, - {108, "gear/launchbar/state", simgear::props::STRING}, - {109, "gear/launchbar/holdback-position-norm", simgear::props::FLOAT}, - {110, "canopy/position-norm", simgear::props::FLOAT}, - {111, "surface-positions/wing-pos-norm", simgear::props::FLOAT}, - {112, "surface-positions/wing-fold-pos-norm", simgear::props::FLOAT}, + { 10, "sim/multiplay/protocol-version", simgear::props::INT, TT_SHORTINT, V1_1_PROP_ID, NULL }, + { 100, "surface-positions/left-aileron-pos-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 101, "surface-positions/right-aileron-pos-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 102, "surface-positions/elevator-pos-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 103, "surface-positions/rudder-pos-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 104, "surface-positions/flap-pos-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 105, "surface-positions/speedbrake-pos-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 106, "gear/tailhook/position-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 107, "gear/launchbar/position-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 108, "gear/launchbar/state", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 109, "gear/launchbar/holdback-position-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 110, "canopy/position-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 111, "surface-positions/wing-pos-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 112, "surface-positions/wing-fold-pos-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, - {200, "gear/gear[0]/compression-norm", simgear::props::FLOAT}, - {201, "gear/gear[0]/position-norm", simgear::props::FLOAT}, - {210, "gear/gear[1]/compression-norm", simgear::props::FLOAT}, - {211, "gear/gear[1]/position-norm", simgear::props::FLOAT}, - {220, "gear/gear[2]/compression-norm", simgear::props::FLOAT}, - {221, "gear/gear[2]/position-norm", simgear::props::FLOAT}, - {230, "gear/gear[3]/compression-norm", simgear::props::FLOAT}, - {231, "gear/gear[3]/position-norm", simgear::props::FLOAT}, - {240, "gear/gear[4]/compression-norm", simgear::props::FLOAT}, - {241, "gear/gear[4]/position-norm", simgear::props::FLOAT}, + { 200, "gear/gear[0]/compression-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 201, "gear/gear[0]/position-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 210, "gear/gear[1]/compression-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 211, "gear/gear[1]/position-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 220, "gear/gear[2]/compression-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 221, "gear/gear[2]/position-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 230, "gear/gear[3]/compression-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 231, "gear/gear[3]/position-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 240, "gear/gear[4]/compression-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, + { 241, "gear/gear[4]/position-norm", simgear::props::FLOAT, TT_SHORT_FLOAT_NORM, V1_1_PROP_ID, NULL }, - {300, "engines/engine[0]/n1", simgear::props::FLOAT}, - {301, "engines/engine[0]/n2", simgear::props::FLOAT}, - {302, "engines/engine[0]/rpm", simgear::props::FLOAT}, - {310, "engines/engine[1]/n1", simgear::props::FLOAT}, - {311, "engines/engine[1]/n2", simgear::props::FLOAT}, - {312, "engines/engine[1]/rpm", simgear::props::FLOAT}, - {320, "engines/engine[2]/n1", simgear::props::FLOAT}, - {321, "engines/engine[2]/n2", simgear::props::FLOAT}, - {322, "engines/engine[2]/rpm", simgear::props::FLOAT}, - {330, "engines/engine[3]/n1", simgear::props::FLOAT}, - {331, "engines/engine[3]/n2", simgear::props::FLOAT}, - {332, "engines/engine[3]/rpm", simgear::props::FLOAT}, - {340, "engines/engine[4]/n1", simgear::props::FLOAT}, - {341, "engines/engine[4]/n2", simgear::props::FLOAT}, - {342, "engines/engine[4]/rpm", simgear::props::FLOAT}, - {350, "engines/engine[5]/n1", simgear::props::FLOAT}, - {351, "engines/engine[5]/n2", simgear::props::FLOAT}, - {352, "engines/engine[5]/rpm", simgear::props::FLOAT}, - {360, "engines/engine[6]/n1", simgear::props::FLOAT}, - {361, "engines/engine[6]/n2", simgear::props::FLOAT}, - {362, "engines/engine[6]/rpm", simgear::props::FLOAT}, - {370, "engines/engine[7]/n1", simgear::props::FLOAT}, - {371, "engines/engine[7]/n2", simgear::props::FLOAT}, - {372, "engines/engine[7]/rpm", simgear::props::FLOAT}, - {380, "engines/engine[8]/n1", simgear::props::FLOAT}, - {381, "engines/engine[8]/n2", simgear::props::FLOAT}, - {382, "engines/engine[8]/rpm", simgear::props::FLOAT}, - {390, "engines/engine[9]/n1", simgear::props::FLOAT}, - {391, "engines/engine[9]/n2", simgear::props::FLOAT}, - {392, "engines/engine[9]/rpm", simgear::props::FLOAT}, + { 300, "engines/engine[0]/n1", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 301, "engines/engine[0]/n2", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 302, "engines/engine[0]/rpm", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 310, "engines/engine[1]/n1", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 311, "engines/engine[1]/n2", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 312, "engines/engine[1]/rpm", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 320, "engines/engine[2]/n1", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 321, "engines/engine[2]/n2", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 322, "engines/engine[2]/rpm", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 330, "engines/engine[3]/n1", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 331, "engines/engine[3]/n2", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 332, "engines/engine[3]/rpm", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 340, "engines/engine[4]/n1", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 341, "engines/engine[4]/n2", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 342, "engines/engine[4]/rpm", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 350, "engines/engine[5]/n1", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 351, "engines/engine[5]/n2", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 352, "engines/engine[5]/rpm", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 360, "engines/engine[6]/n1", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 361, "engines/engine[6]/n2", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 362, "engines/engine[6]/rpm", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 370, "engines/engine[7]/n1", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 371, "engines/engine[7]/n2", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 372, "engines/engine[7]/rpm", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 380, "engines/engine[8]/n1", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 381, "engines/engine[8]/n2", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 382, "engines/engine[8]/rpm", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 390, "engines/engine[9]/n1", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 391, "engines/engine[9]/n2", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 392, "engines/engine[9]/rpm", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, - {800, "rotors/main/rpm", simgear::props::FLOAT}, - {801, "rotors/tail/rpm", simgear::props::FLOAT}, - {810, "rotors/main/blade[0]/position-deg", simgear::props::FLOAT}, - {811, "rotors/main/blade[1]/position-deg", simgear::props::FLOAT}, - {812, "rotors/main/blade[2]/position-deg", simgear::props::FLOAT}, - {813, "rotors/main/blade[3]/position-deg", simgear::props::FLOAT}, - {820, "rotors/main/blade[0]/flap-deg", simgear::props::FLOAT}, - {821, "rotors/main/blade[1]/flap-deg", simgear::props::FLOAT}, - {822, "rotors/main/blade[2]/flap-deg", simgear::props::FLOAT}, - {823, "rotors/main/blade[3]/flap-deg", simgear::props::FLOAT}, - {830, "rotors/tail/blade[0]/position-deg", simgear::props::FLOAT}, - {831, "rotors/tail/blade[1]/position-deg", simgear::props::FLOAT}, + { 800, "rotors/main/rpm", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 801, "rotors/tail/rpm", simgear::props::FLOAT, TT_SHORT_FLOAT_1, V1_1_PROP_ID, NULL }, + { 810, "rotors/main/blade[0]/position-deg", simgear::props::FLOAT, TT_SHORT_FLOAT_3, V1_1_PROP_ID, NULL }, + { 811, "rotors/main/blade[1]/position-deg", simgear::props::FLOAT, TT_SHORT_FLOAT_3, V1_1_PROP_ID, NULL }, + { 812, "rotors/main/blade[2]/position-deg", simgear::props::FLOAT, TT_SHORT_FLOAT_3, V1_1_PROP_ID, NULL }, + { 813, "rotors/main/blade[3]/position-deg", simgear::props::FLOAT, TT_SHORT_FLOAT_3, V1_1_PROP_ID, NULL }, + { 820, "rotors/main/blade[0]/flap-deg", simgear::props::FLOAT, TT_SHORT_FLOAT_3, V1_1_PROP_ID, NULL }, + { 821, "rotors/main/blade[1]/flap-deg", simgear::props::FLOAT, TT_SHORT_FLOAT_3, V1_1_PROP_ID, NULL }, + { 822, "rotors/main/blade[2]/flap-deg", simgear::props::FLOAT, TT_SHORT_FLOAT_3, V1_1_PROP_ID, NULL }, + { 823, "rotors/main/blade[3]/flap-deg", simgear::props::FLOAT, TT_SHORT_FLOAT_3, V1_1_PROP_ID, NULL }, + { 830, "rotors/tail/blade[0]/position-deg", simgear::props::FLOAT, TT_SHORT_FLOAT_3, V1_1_PROP_ID, NULL }, + { 831, "rotors/tail/blade[1]/position-deg", simgear::props::FLOAT, TT_SHORT_FLOAT_3, V1_1_PROP_ID, NULL }, - {900, "sim/hitches/aerotow/tow/length", simgear::props::FLOAT}, - {901, "sim/hitches/aerotow/tow/elastic-constant", simgear::props::FLOAT}, - {902, "sim/hitches/aerotow/tow/weight-per-m-kg-m", simgear::props::FLOAT}, - {903, "sim/hitches/aerotow/tow/dist", simgear::props::FLOAT}, - {904, "sim/hitches/aerotow/tow/connected-to-property-node", simgear::props::BOOL}, - {905, "sim/hitches/aerotow/tow/connected-to-ai-or-mp-callsign", simgear::props::STRING}, - {906, "sim/hitches/aerotow/tow/brake-force", simgear::props::FLOAT}, - {907, "sim/hitches/aerotow/tow/end-force-x", simgear::props::FLOAT}, - {908, "sim/hitches/aerotow/tow/end-force-y", simgear::props::FLOAT}, - {909, "sim/hitches/aerotow/tow/end-force-z", simgear::props::FLOAT}, - {930, "sim/hitches/aerotow/is-slave", simgear::props::BOOL}, - {931, "sim/hitches/aerotow/speed-in-tow-direction", simgear::props::FLOAT}, - {932, "sim/hitches/aerotow/open", simgear::props::BOOL}, - {933, "sim/hitches/aerotow/local-pos-x", simgear::props::FLOAT}, - {934, "sim/hitches/aerotow/local-pos-y", simgear::props::FLOAT}, - {935, "sim/hitches/aerotow/local-pos-z", simgear::props::FLOAT}, + { 900, "sim/hitches/aerotow/tow/length", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 901, "sim/hitches/aerotow/tow/elastic-constant", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 902, "sim/hitches/aerotow/tow/weight-per-m-kg-m", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 903, "sim/hitches/aerotow/tow/dist", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 904, "sim/hitches/aerotow/tow/connected-to-property-node", simgear::props::BOOL, TT_ASIS, V1_1_PROP_ID, NULL }, + { 905, "sim/hitches/aerotow/tow/connected-to-ai-or-mp-callsign", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 906, "sim/hitches/aerotow/tow/brake-force", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 907, "sim/hitches/aerotow/tow/end-force-x", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 908, "sim/hitches/aerotow/tow/end-force-y", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 909, "sim/hitches/aerotow/tow/end-force-z", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 930, "sim/hitches/aerotow/is-slave", simgear::props::BOOL, TT_ASIS, V1_1_PROP_ID, NULL }, + { 931, "sim/hitches/aerotow/speed-in-tow-direction", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 932, "sim/hitches/aerotow/open", simgear::props::BOOL, TT_ASIS, V1_1_PROP_ID, NULL }, + { 933, "sim/hitches/aerotow/local-pos-x", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 934, "sim/hitches/aerotow/local-pos-y", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 935, "sim/hitches/aerotow/local-pos-z", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, - {1001, "controls/flight/slats", simgear::props::FLOAT}, - {1002, "controls/flight/speedbrake", simgear::props::FLOAT}, - {1003, "controls/flight/spoilers", simgear::props::FLOAT}, - {1004, "controls/gear/gear-down", simgear::props::FLOAT}, - {1005, "controls/lighting/nav-lights", simgear::props::FLOAT}, - {1006, "controls/armament/station[0]/jettison-all", simgear::props::BOOL}, + { 1001, "controls/flight/slats", simgear::props::FLOAT, TT_SHORT_FLOAT_4, V1_1_PROP_ID, NULL }, + { 1002, "controls/flight/speedbrake", simgear::props::FLOAT, TT_SHORT_FLOAT_4, V1_1_PROP_ID, NULL }, + { 1003, "controls/flight/spoilers", simgear::props::FLOAT, TT_SHORT_FLOAT_4, V1_1_PROP_ID, NULL }, + { 1004, "controls/gear/gear-down", simgear::props::FLOAT, TT_SHORT_FLOAT_4, V1_1_PROP_ID, NULL }, + { 1005, "controls/lighting/nav-lights", simgear::props::FLOAT, TT_SHORT_FLOAT_3, V1_1_PROP_ID, NULL }, + { 1006, "controls/armament/station[0]/jettison-all", simgear::props::BOOL, TT_SHORTINT, V1_1_PROP_ID, NULL }, - {1100, "sim/model/variant", simgear::props::INT}, - {1101, "sim/model/livery/file", simgear::props::STRING}, + { 1100, "sim/model/variant", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 1101, "sim/model/livery/file", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, - {1200, "environment/wildfire/data", simgear::props::STRING}, - {1201, "environment/contrail", simgear::props::INT}, + { 1200, "environment/wildfire/data", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 1201, "environment/contrail", simgear::props::INT, TT_SHORTINT, V1_1_PROP_ID, NULL }, - {1300, "tanker", simgear::props::INT}, + { 1300, "tanker", simgear::props::INT, TT_SHORTINT, V1_1_PROP_ID, NULL }, - {1400, "scenery/events", simgear::props::STRING}, + { 1400, "scenery/events", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, - {1500, "instrumentation/transponder/transmitted-id", simgear::props::INT}, - {1501, "instrumentation/transponder/altitude", simgear::props::INT}, - {1502, "instrumentation/transponder/ident", simgear::props::BOOL}, - {1503, "instrumentation/transponder/inputs/mode", simgear::props::INT}, + { 1500, "instrumentation/transponder/transmitted-id", simgear::props::INT, TT_SHORTINT, V1_1_PROP_ID, NULL }, + { 1501, "instrumentation/transponder/altitude", simgear::props::INT, TT_ASIS, TT_SHORTINT, NULL }, + { 1502, "instrumentation/transponder/ident", simgear::props::BOOL, TT_ASIS, TT_SHORTINT, NULL }, + { 1503, "instrumentation/transponder/inputs/mode", simgear::props::INT, TT_ASIS, TT_SHORTINT, NULL }, - {10001, "sim/multiplay/transmission-freq-hz", simgear::props::STRING}, - {10002, "sim/multiplay/chat", simgear::props::STRING}, + { 10001, "sim/multiplay/transmission-freq-hz", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10002, "sim/multiplay/chat", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, - {10100, "sim/multiplay/generic/string[0]", simgear::props::STRING}, - {10101, "sim/multiplay/generic/string[1]", simgear::props::STRING}, - {10102, "sim/multiplay/generic/string[2]", simgear::props::STRING}, - {10103, "sim/multiplay/generic/string[3]", simgear::props::STRING}, - {10104, "sim/multiplay/generic/string[4]", simgear::props::STRING}, - {10105, "sim/multiplay/generic/string[5]", simgear::props::STRING}, - {10106, "sim/multiplay/generic/string[6]", simgear::props::STRING}, - {10107, "sim/multiplay/generic/string[7]", simgear::props::STRING}, - {10108, "sim/multiplay/generic/string[8]", simgear::props::STRING}, - {10109, "sim/multiplay/generic/string[9]", simgear::props::STRING}, - {10110, "sim/multiplay/generic/string[10]", simgear::props::STRING}, - {10111, "sim/multiplay/generic/string[11]", simgear::props::STRING}, - {10112, "sim/multiplay/generic/string[12]", simgear::props::STRING}, - {10113, "sim/multiplay/generic/string[13]", simgear::props::STRING}, - {10114, "sim/multiplay/generic/string[14]", simgear::props::STRING}, - {10115, "sim/multiplay/generic/string[15]", simgear::props::STRING}, - {10116, "sim/multiplay/generic/string[16]", simgear::props::STRING}, - {10117, "sim/multiplay/generic/string[17]", simgear::props::STRING}, - {10118, "sim/multiplay/generic/string[18]", simgear::props::STRING}, - {10119, "sim/multiplay/generic/string[19]", simgear::props::STRING}, + { 10100, "sim/multiplay/generic/string[0]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10101, "sim/multiplay/generic/string[1]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10102, "sim/multiplay/generic/string[2]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10103, "sim/multiplay/generic/string[3]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10104, "sim/multiplay/generic/string[4]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10105, "sim/multiplay/generic/string[5]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10106, "sim/multiplay/generic/string[6]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10107, "sim/multiplay/generic/string[7]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10108, "sim/multiplay/generic/string[8]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10109, "sim/multiplay/generic/string[9]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10110, "sim/multiplay/generic/string[10]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10111, "sim/multiplay/generic/string[11]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10112, "sim/multiplay/generic/string[12]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10113, "sim/multiplay/generic/string[13]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10114, "sim/multiplay/generic/string[14]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10115, "sim/multiplay/generic/string[15]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10116, "sim/multiplay/generic/string[16]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10117, "sim/multiplay/generic/string[17]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10118, "sim/multiplay/generic/string[18]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, + { 10119, "sim/multiplay/generic/string[19]", simgear::props::STRING, TT_ASIS, V1_1_2_PROP_ID, NULL }, - {10200, "sim/multiplay/generic/float[0]", simgear::props::FLOAT}, - {10201, "sim/multiplay/generic/float[1]", simgear::props::FLOAT}, - {10202, "sim/multiplay/generic/float[2]", simgear::props::FLOAT}, - {10203, "sim/multiplay/generic/float[3]", simgear::props::FLOAT}, - {10204, "sim/multiplay/generic/float[4]", simgear::props::FLOAT}, - {10205, "sim/multiplay/generic/float[5]", simgear::props::FLOAT}, - {10206, "sim/multiplay/generic/float[6]", simgear::props::FLOAT}, - {10207, "sim/multiplay/generic/float[7]", simgear::props::FLOAT}, - {10208, "sim/multiplay/generic/float[8]", simgear::props::FLOAT}, - {10209, "sim/multiplay/generic/float[9]", simgear::props::FLOAT}, - {10210, "sim/multiplay/generic/float[10]", simgear::props::FLOAT}, - {10211, "sim/multiplay/generic/float[11]", simgear::props::FLOAT}, - {10212, "sim/multiplay/generic/float[12]", simgear::props::FLOAT}, - {10213, "sim/multiplay/generic/float[13]", simgear::props::FLOAT}, - {10214, "sim/multiplay/generic/float[14]", simgear::props::FLOAT}, - {10215, "sim/multiplay/generic/float[15]", simgear::props::FLOAT}, - {10216, "sim/multiplay/generic/float[16]", simgear::props::FLOAT}, - {10217, "sim/multiplay/generic/float[17]", simgear::props::FLOAT}, - {10218, "sim/multiplay/generic/float[18]", simgear::props::FLOAT}, - {10219, "sim/multiplay/generic/float[19]", simgear::props::FLOAT}, + { 10200, "sim/multiplay/generic/float[0]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10201, "sim/multiplay/generic/float[1]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10202, "sim/multiplay/generic/float[2]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10203, "sim/multiplay/generic/float[3]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10204, "sim/multiplay/generic/float[4]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10205, "sim/multiplay/generic/float[5]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10206, "sim/multiplay/generic/float[6]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10207, "sim/multiplay/generic/float[7]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10208, "sim/multiplay/generic/float[8]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10209, "sim/multiplay/generic/float[9]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10210, "sim/multiplay/generic/float[10]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10211, "sim/multiplay/generic/float[11]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10212, "sim/multiplay/generic/float[12]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10213, "sim/multiplay/generic/float[13]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10214, "sim/multiplay/generic/float[14]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10215, "sim/multiplay/generic/float[15]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10216, "sim/multiplay/generic/float[16]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10217, "sim/multiplay/generic/float[17]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10218, "sim/multiplay/generic/float[18]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10219, "sim/multiplay/generic/float[19]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + + { 10220, "sim/multiplay/generic/float[20]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10221, "sim/multiplay/generic/float[21]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10222, "sim/multiplay/generic/float[22]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10223, "sim/multiplay/generic/float[23]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10224, "sim/multiplay/generic/float[24]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10225, "sim/multiplay/generic/float[25]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10226, "sim/multiplay/generic/float[26]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10227, "sim/multiplay/generic/float[27]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10228, "sim/multiplay/generic/float[28]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10229, "sim/multiplay/generic/float[29]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10230, "sim/multiplay/generic/float[30]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10231, "sim/multiplay/generic/float[31]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10232, "sim/multiplay/generic/float[32]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10233, "sim/multiplay/generic/float[33]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10234, "sim/multiplay/generic/float[34]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10235, "sim/multiplay/generic/float[35]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10236, "sim/multiplay/generic/float[36]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10237, "sim/multiplay/generic/float[37]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10238, "sim/multiplay/generic/float[38]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10239, "sim/multiplay/generic/float[39]", simgear::props::FLOAT, TT_ASIS, V1_1_PROP_ID, NULL }, + + { 10300, "sim/multiplay/generic/int[0]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10301, "sim/multiplay/generic/int[1]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10302, "sim/multiplay/generic/int[2]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10303, "sim/multiplay/generic/int[3]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10304, "sim/multiplay/generic/int[4]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10305, "sim/multiplay/generic/int[5]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10306, "sim/multiplay/generic/int[6]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10307, "sim/multiplay/generic/int[7]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10308, "sim/multiplay/generic/int[8]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10309, "sim/multiplay/generic/int[9]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10310, "sim/multiplay/generic/int[10]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10311, "sim/multiplay/generic/int[11]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10312, "sim/multiplay/generic/int[12]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10313, "sim/multiplay/generic/int[13]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10314, "sim/multiplay/generic/int[14]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10315, "sim/multiplay/generic/int[15]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10316, "sim/multiplay/generic/int[16]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10317, "sim/multiplay/generic/int[17]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10318, "sim/multiplay/generic/int[18]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + { 10319, "sim/multiplay/generic/int[19]", simgear::props::INT, TT_ASIS, V1_1_PROP_ID, NULL }, + + { 10500, "sim/multiplay/generic/short[0]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10501, "sim/multiplay/generic/short[1]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10502, "sim/multiplay/generic/short[2]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10503, "sim/multiplay/generic/short[3]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10504, "sim/multiplay/generic/short[4]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10505, "sim/multiplay/generic/short[5]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10506, "sim/multiplay/generic/short[6]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10507, "sim/multiplay/generic/short[7]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10508, "sim/multiplay/generic/short[8]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10509, "sim/multiplay/generic/short[9]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10510, "sim/multiplay/generic/short[10]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10511, "sim/multiplay/generic/short[11]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10512, "sim/multiplay/generic/short[12]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10513, "sim/multiplay/generic/short[13]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10514, "sim/multiplay/generic/short[14]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10515, "sim/multiplay/generic/short[15]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10516, "sim/multiplay/generic/short[16]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10517, "sim/multiplay/generic/short[17]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10518, "sim/multiplay/generic/short[18]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10519, "sim/multiplay/generic/short[19]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10520, "sim/multiplay/generic/short[20]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10521, "sim/multiplay/generic/short[21]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10522, "sim/multiplay/generic/short[22]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10523, "sim/multiplay/generic/short[23]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10524, "sim/multiplay/generic/short[24]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10525, "sim/multiplay/generic/short[25]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10526, "sim/multiplay/generic/short[26]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10527, "sim/multiplay/generic/short[27]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10528, "sim/multiplay/generic/short[28]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10529, "sim/multiplay/generic/short[29]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10520, "sim/multiplay/generic/short[20]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10521, "sim/multiplay/generic/short[21]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10522, "sim/multiplay/generic/short[22]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10523, "sim/multiplay/generic/short[23]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10524, "sim/multiplay/generic/short[24]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10525, "sim/multiplay/generic/short[25]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10526, "sim/multiplay/generic/short[26]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10527, "sim/multiplay/generic/short[27]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10528, "sim/multiplay/generic/short[28]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10529, "sim/multiplay/generic/short[29]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10530, "sim/multiplay/generic/short[30]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10531, "sim/multiplay/generic/short[31]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10532, "sim/multiplay/generic/short[32]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10533, "sim/multiplay/generic/short[33]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10534, "sim/multiplay/generic/short[34]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10535, "sim/multiplay/generic/short[35]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10536, "sim/multiplay/generic/short[36]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10537, "sim/multiplay/generic/short[37]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10538, "sim/multiplay/generic/short[38]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10539, "sim/multiplay/generic/short[39]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10540, "sim/multiplay/generic/short[40]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10541, "sim/multiplay/generic/short[41]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10542, "sim/multiplay/generic/short[42]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10543, "sim/multiplay/generic/short[43]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10544, "sim/multiplay/generic/short[44]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10545, "sim/multiplay/generic/short[45]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10546, "sim/multiplay/generic/short[46]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10547, "sim/multiplay/generic/short[47]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10548, "sim/multiplay/generic/short[48]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10549, "sim/multiplay/generic/short[49]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10550, "sim/multiplay/generic/short[50]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10551, "sim/multiplay/generic/short[51]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10552, "sim/multiplay/generic/short[52]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10553, "sim/multiplay/generic/short[53]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10554, "sim/multiplay/generic/short[54]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10555, "sim/multiplay/generic/short[55]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10556, "sim/multiplay/generic/short[56]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10557, "sim/multiplay/generic/short[57]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10558, "sim/multiplay/generic/short[58]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10559, "sim/multiplay/generic/short[59]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10560, "sim/multiplay/generic/short[60]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10561, "sim/multiplay/generic/short[61]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10562, "sim/multiplay/generic/short[62]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10563, "sim/multiplay/generic/short[63]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10564, "sim/multiplay/generic/short[64]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10565, "sim/multiplay/generic/short[65]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10566, "sim/multiplay/generic/short[66]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10567, "sim/multiplay/generic/short[67]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10568, "sim/multiplay/generic/short[68]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10569, "sim/multiplay/generic/short[69]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10570, "sim/multiplay/generic/short[70]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10571, "sim/multiplay/generic/short[71]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10572, "sim/multiplay/generic/short[72]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10573, "sim/multiplay/generic/short[73]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10574, "sim/multiplay/generic/short[74]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10575, "sim/multiplay/generic/short[75]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10576, "sim/multiplay/generic/short[76]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10577, "sim/multiplay/generic/short[77]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10578, "sim/multiplay/generic/short[78]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, + { 10579, "sim/multiplay/generic/short[79]", simgear::props::INT, TT_SHORTINT, V1_1_2_PROP_ID, NULL }, - {10300, "sim/multiplay/generic/int[0]", simgear::props::INT}, - {10301, "sim/multiplay/generic/int[1]", simgear::props::INT}, - {10302, "sim/multiplay/generic/int[2]", simgear::props::INT}, - {10303, "sim/multiplay/generic/int[3]", simgear::props::INT}, - {10304, "sim/multiplay/generic/int[4]", simgear::props::INT}, - {10305, "sim/multiplay/generic/int[5]", simgear::props::INT}, - {10306, "sim/multiplay/generic/int[6]", simgear::props::INT}, - {10307, "sim/multiplay/generic/int[7]", simgear::props::INT}, - {10308, "sim/multiplay/generic/int[8]", simgear::props::INT}, - {10309, "sim/multiplay/generic/int[9]", simgear::props::INT}, - {10310, "sim/multiplay/generic/int[10]", simgear::props::INT}, - {10311, "sim/multiplay/generic/int[11]", simgear::props::INT}, - {10312, "sim/multiplay/generic/int[12]", simgear::props::INT}, - {10313, "sim/multiplay/generic/int[13]", simgear::props::INT}, - {10314, "sim/multiplay/generic/int[14]", simgear::props::INT}, - {10315, "sim/multiplay/generic/int[15]", simgear::props::INT}, - {10316, "sim/multiplay/generic/int[16]", simgear::props::INT}, - {10317, "sim/multiplay/generic/int[17]", simgear::props::INT}, - {10318, "sim/multiplay/generic/int[18]", simgear::props::INT}, - {10319, "sim/multiplay/generic/int[19]", simgear::props::INT} }; - -const unsigned int numProperties = (sizeof(sIdPropertyList) - / sizeof(sIdPropertyList[0])); +/* + * For the 2017.x version 2 protocol the properties are sent in two partitions, + * the first of these is a V1 protocol packet (which should be fine with all clients), and a V2 partition + * which will contain the newly supported shortint and fixed string encoding schemes. + * This is to possibly allow for easier V1/V2 conversion - as the packet can simply be truncated at the + * first V2 property based on ID. + */ +const int MAX_PARTITIONS = 2; +const unsigned int numProperties = (sizeof(sIdPropertyList) / sizeof(sIdPropertyList[0])); // Look up a property ID using binary search. namespace @@ -364,9 +539,8 @@ public: { _multiplay->setPropertiesChanged(); } - private: - FGMultiplayMgr* _multiplay; + FGMultiplayMgr* _multiplay; }; ////////////////////////////////////////////////////////////////////// @@ -378,32 +552,32 @@ private: // rxport: incoming port number (default: 5000) ////////////////////////////////////////////////////////////////////// static bool do_multiplayer_connect(const SGPropertyNode * arg) { - FGMultiplayMgr * self = (FGMultiplayMgr*) globals->get_subsystem("mp"); - if (!self) { - SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available."); - return false; - } + FGMultiplayMgr * self = (FGMultiplayMgr*) globals->get_subsystem("mp"); + if (!self) { + SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available."); + return false; + } - string servername = arg->getStringValue("servername", ""); - if (servername.empty()) { - SG_LOG(SG_NETWORK, SG_WARN, - "do_multiplayer.connect: no server name given, command ignored."); - return false; - } - int port = arg->getIntValue("rxport", -1); - if (port > 0 && port <= 0xffff) { - fgSetInt("/sim/multiplay/rxport", port); - } + string servername = arg->getStringValue("servername", ""); + if (servername.empty()) { + SG_LOG(SG_NETWORK, SG_WARN, + "do_multiplayer.connect: no server name given, command ignored."); + return false; + } + int port = arg->getIntValue("rxport", -1); + if (port > 0 && port <= 0xffff) { + fgSetInt("/sim/multiplay/rxport", port); + } - port = arg->getIntValue("txport", -1); - if (port > 0 && port <= 0xffff) { - fgSetInt("/sim/multiplay/txport", port); - } + port = arg->getIntValue("txport", -1); + if (port > 0 && port <= 0xffff) { + fgSetInt("/sim/multiplay/txport", port); + } - servername = servername.substr(0, servername.find_first_of(' ')); - fgSetString("/sim/multiplay/txhost", servername); - self->reinit(); - return true; + servername = servername.substr(0, servername.find_first_of(' ')); + fgSetString("/sim/multiplay/txhost", servername); + self->reinit(); + return true; } ////////////////////////////////////////////////////////////////////// @@ -413,15 +587,15 @@ static bool do_multiplayer_connect(const SGPropertyNode * arg) { // none ////////////////////////////////////////////////////////////////////// static bool do_multiplayer_disconnect(const SGPropertyNode * arg) { - FGMultiplayMgr * self = (FGMultiplayMgr*) globals->get_subsystem("mp"); - if (!self) { - SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available."); - return false; - } + FGMultiplayMgr * self = (FGMultiplayMgr*) globals->get_subsystem("mp"); + if (!self) { + SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available."); + return false; + } - fgSetString("/sim/multiplay/txhost", ""); - self->reinit(); - return true; + fgSetString("/sim/multiplay/txhost", ""); + self->reinit(); + return true; } ////////////////////////////////////////////////////////////////////// @@ -500,6 +674,11 @@ FGMultiplayMgr::FGMultiplayMgr() globals->get_commands()->addCommand("multiplayer-connect", do_multiplayer_connect); globals->get_commands()->addCommand("multiplayer-disconnect", do_multiplayer_disconnect); globals->get_commands()->addCommand("multiplayer-refreshserverlist", do_multiplayer_refreshserverlist); + pXmitLen = fgGetNode("/sim/multiplay/last-xmit-packet-len", true); + pProtocolVersion = fgGetNode("/sim/multiplay/protocol-version", true); + pMultiPlayDebugLevel = fgGetNode("/sim/multiplay/debug-level", true); + pMultiPlayRange = fgGetNode("/sim/multiplay/visibility-range-nm", true); + pMultiPlayRange->setIntValue(100); } // FGMultiplayMgr::FGMultiplayMgr() ////////////////////////////////////////////////////////////////////// @@ -604,7 +783,7 @@ FGMultiplayMgr::init (void) mPropertiesChanged = true; mListener = new MPPropertyListener(this); globals->get_props()->addChangeListener(mListener, false); - + fgSetBool("/sim/multiplay/online", true); mInitialised = true; @@ -780,6 +959,18 @@ FGMultiplayMgr::SendMyPosition(const FGExternalMotionData& motionInfo) static unsigned msgLen = 0; T_PositionMsg* PosMsg = msgBuf.posMsg(); + /* + * This is to provide a level of compatibility with the new V2 packets. + * By setting padding it will force older clients to use verify properties which will + * bail out if there are any unknown props + * MP2017(V2) (for V1 clients) will always have an unknown property because V2 transmits + * the protocol version as the very first property as a shortint. + */ + if (getProtocolToUse() > 1) + PosMsg->pad = XDR_encode_int32(V2_PAD_MAGIC); + else + PosMsg->pad = 0; + strncpy(PosMsg->Model, fgGetString("/sim/model/path"), MAX_MODEL_NAME_LEN); PosMsg->Model[MAX_MODEL_NAME_LEN - 1] = '\0'; if (fgGetBool("/sim/freeze/replay-state", true)&& @@ -831,130 +1022,279 @@ FGMultiplayMgr::SendMyPosition(const FGExternalMotionData& motionInfo) PosMsg->angularAccel[i] = XDR_encode_float (motionInfo.angularAccel(i) * timeAccel * timeAccel); } xdr_data_t* ptr = msgBuf.properties(); - std::vector::const_iterator it; - it = motionInfo.properties.begin(); - //cout << "OUTPUT PROPERTIES\n"; + xdr_data_t* data = ptr; + xdr_data_t* msgEnd = msgBuf.propsEnd(); - while (it != motionInfo.properties.end()) { + int protocolVersion = getProtocolToUse(); - if (ptr + 2 >= msgEnd) - { - SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer packet truncated prop id: " << (*it)->id); - break; - } + //if (pMultiPlayDebugLevel->getIntValue()) + // msgBuf.zero(); - // First element is the ID. Write it out when we know we have room for - // the whole property. - xdr_data_t id = XDR_encode_uint32((*it)->id); - // The actual data representation depends on the type - switch ((*it)->type) { - case simgear::props::INT: - case simgear::props::BOOL: - case simgear::props::LONG: - *ptr++ = id; - *ptr++ = XDR_encode_uint32((*it)->int_value); - //cout << "Prop:" << (*it)->id << " " << (*it)->type << " "<< (*it)->int_value << "\n"; - break; - case simgear::props::FLOAT: - case simgear::props::DOUBLE: - *ptr++ = id; - *ptr++ = XDR_encode_float((*it)->float_value); - //cout << "Prop:" << (*it)->id << " " << (*it)->type << " "<< (*it)->float_value << "\n"; - break; - case simgear::props::STRING: - case simgear::props::UNSPECIFIED: - { - // String is complicated. It consists of - // The length of the string - // The string itself - // Padding to the nearest 4-bytes. - const char* lcharptr = (*it)->string_value; - - if (lcharptr != 0) + for (int partition = 1; partition <= protocolVersion; partition++) + { + std::vector::const_iterator it = motionInfo.properties.begin(); + while (it != motionInfo.properties.end()) { + const struct IdPropertyList* propDef = mPropertyDefinition[(*it)->id]; + if (propDef->version == partition || propDef->version > getProtocolToUse()) { - // Add the length - ////cout << "String length: " << strlen(lcharptr) << "\n"; - uint32_t len = strlen(lcharptr); - if (len >= MAX_TEXT_SIZE) - { - len = MAX_TEXT_SIZE - 1; - SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer property truncated at MAX_TEXT_SIZE in string " << (*it)->id); - } - - // XXX This should not be using 4 bytes per character! - // If there's not enough room for this property, drop it - // on the floor. - if (ptr + 2 + ((len + 3) & ~3) >= msgEnd) - { - SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer property not sent (no room) string " << (*it)->id); - goto escape; - } - //cout << "String length unint32: " << len << "\n"; - *ptr++ = id; - *ptr++ = XDR_encode_uint32(len); - if (len != 0) - { - // Now the text itself - // XXX This should not be using 4 bytes per character! - int lcount = 0; - while ((*lcharptr != '\0') && (lcount < MAX_TEXT_SIZE)) + if (ptr + 2 >= msgEnd) { - if (ptr + 2 >= msgEnd) - { - SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer packet truncated in string " << (*it)->id << " lcount " << lcount); + SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer packet truncated prop id: " << (*it)->id << ": " << propDef->name); break; - } - *ptr++ = XDR_encode_int8(*lcharptr); - lcharptr++; - lcount++; - } - //cout << "Prop:" << (*it)->id << " " << (*it)->type << " " << len << " " << (*it)->string_value; - - // Now pad if required - while ((lcount % 4) != 0) - { - if (ptr + 2 >= msgEnd) - { - SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer packet truncated in string " << (*it)->id << " lcount " << lcount); - break; - } - *ptr++ = XDR_encode_int8(0); - lcount++; - //cout << "0"; } - //cout << "\n"; - } + // First element is the ID. Write it out when we know we have room for + // the whole property. + xdr_data_t id = XDR_encode_uint32((*it)->id); + + + /* + * 2017.2 protocol has the ability to transmit as a different type (to save space), so + * process this when using this protocol (protocolVersion 2) or later + */ + int transmit_type = (*it)->type; + + if (propDef->TransmitAs != TT_ASIS && protocolVersion > 1) + { + transmit_type = propDef->TransmitAs; + } + + if (pMultiPlayDebugLevel->getIntValue() & 2) + SG_LOG(SG_NETWORK, SG_INFO, + "[SEND] pt " << partition << + ": buf[" << (ptr - data)*sizeof(*ptr) + << "] id=" << (*it)->id << " type " << transmit_type); + + // The actual data representation depends on the type + switch (transmit_type) { + case TT_SHORTINT: + { + *ptr++ = XDR_encode_shortints32((*it)->id, (*it)->int_value); + break; + } + case TT_SHORT_FLOAT_1: + { + short value = get_scaled_short((*it)->float_value, 10.0); + *ptr++ = XDR_encode_shortints32((*it)->id, value); + break; + } + case TT_SHORT_FLOAT_2: + { + short value = get_scaled_short((*it)->float_value, 100.0); + *ptr++ = XDR_encode_shortints32((*it)->id, value); + break; + } + case TT_SHORT_FLOAT_3: + { + short value = get_scaled_short((*it)->float_value, 1000.0); + *ptr++ = XDR_encode_shortints32((*it)->id, value); + break; + } + case TT_SHORT_FLOAT_4: + { + short value = get_scaled_short((*it)->float_value, 10000.0); + *ptr++ = XDR_encode_shortints32((*it)->id, value); + break; + } + + case TT_SHORT_FLOAT_NORM: + { + short value = get_scaled_short((*it)->float_value, 32767.0); + *ptr++ = XDR_encode_shortints32((*it)->id, value); + break; + } + + case simgear::props::INT: + case simgear::props::BOOL: + case simgear::props::LONG: + *ptr++ = id; + *ptr++ = XDR_encode_uint32((*it)->int_value); + break; + case simgear::props::FLOAT: + case simgear::props::DOUBLE: + *ptr++ = id; + *ptr++ = XDR_encode_float((*it)->float_value); + break; + case simgear::props::STRING: + case simgear::props::UNSPECIFIED: + { + if (protocolVersion > 1) + { + // New string encoding: + // xdr[0] : ID length packed into 32 bit containing two shorts. + // xdr[1..len/4] The string itself (char[length]) + const char* lcharptr = (*it)->string_value; + + if (lcharptr != 0) + { + uint32_t len = strlen(lcharptr); + + if (len >= MAX_TEXT_SIZE) + { + len = MAX_TEXT_SIZE - 1; + SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer property truncated at MAX_TEXT_SIZE in string " << (*it)->id); + } + + char *encodeStart = (char*)ptr; + char *msgEndbyte = (char*)msgEnd; + + if (encodeStart + 2 + len >= msgEndbyte) + { + SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer property not sent (no room) string " << (*it)->id); + goto escape; + } + + *ptr++ = XDR_encode_shortints32((*it)->id, len); + encodeStart = (char*)ptr; + if (len != 0) + { + int lcount = 0; + while (*lcharptr && (lcount < MAX_TEXT_SIZE)) + { + if (encodeStart + 2 >= msgEndbyte) + { + SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer packet truncated in string " << (*it)->id << " lcount " << lcount); + break; + } + *encodeStart++ = *lcharptr++; + lcount++; + } + } + ptr = (xdr_data_t*)encodeStart; + } + else + { + // empty string, just send the id and a zero length + *ptr++ = id; + *ptr++ = XDR_encode_uint32(0); + } + } + else { + + // String is complicated. It consists of + // The length of the string + // The string itself + // Padding to the nearest 4-bytes. + const char* lcharptr = (*it)->string_value; + + if (lcharptr != 0) + { + // Add the length + ////cout << "String length: " << strlen(lcharptr) << "\n"; + uint32_t len = strlen(lcharptr); + if (len >= MAX_TEXT_SIZE) + { + len = MAX_TEXT_SIZE - 1; + SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer property truncated at MAX_TEXT_SIZE in string " << (*it)->id); + } + + // XXX This should not be using 4 bytes per character! + // If there's not enough room for this property, drop it + // on the floor. + if (ptr + 2 + ((len + 3) & ~3) >= msgEnd) + { + SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer property not sent (no room) string " << (*it)->id); + goto escape; + } + //cout << "String length unint32: " << len << "\n"; + *ptr++ = id; + *ptr++ = XDR_encode_uint32(len); + if (len != 0) + { + // Now the text itself + // XXX This should not be using 4 bytes per character! + int lcount = 0; + while ((*lcharptr != '\0') && (lcount < MAX_TEXT_SIZE)) + { + if (ptr + 2 >= msgEnd) + { + SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer packet truncated in string " << (*it)->id << " lcount " << lcount); + break; + } + *ptr++ = XDR_encode_int8(*lcharptr); + lcharptr++; + lcount++; + } + // Now pad if required + while ((lcount % 4) != 0) + { + if (ptr + 2 >= msgEnd) + { + SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer packet truncated in string " << (*it)->id << " lcount " << lcount); + break; + } + *ptr++ = XDR_encode_int8(0); + lcount++; + } + } + } + else + { + // Nothing to encode + *ptr++ = id; + *ptr++ = XDR_encode_uint32(0); + } + } + } + break; + + default: + *ptr++ = id; + *ptr++ = XDR_encode_float((*it)->float_value);; + break; + } } - else - { - // Nothing to encode - *ptr++ = id; - *ptr++ = XDR_encode_uint32(0); - //cout << "Prop:" << (*it)->id << " " << (*it)->type << " 0\n"; - } - } - break; - - default: - //cout << " Unknown Type: " << (*it)->type << "\n"; - *ptr++ = id; - *ptr++ = XDR_encode_float((*it)->float_value);; - //cout << "Prop:" << (*it)->id << " " << (*it)->type << " "<< (*it)->float_value << "\n"; - break; - } - - ++it; + ++it; + } } - escape: + escape: msgLen = reinterpret_cast(ptr) - msgBuf.Msg; + FillMsgHdr(msgBuf.msgHdr(), POS_DATA_ID, msgLen); + + /* + * Informational: + * Save the last packet length sent, and + * if the property is set then dump the packet length to the console. + * ---------------------------- + * This should be sufficient for rudimentary debugging (in order of useful ness) + * 1. loopback your own craft. fantastic for resolving animations and property transmission issues. + * 2. see what properties are being sent + * 3. see how much space it takes up + * 4. dump the packet as it goes out + * 5. dump incoming packets + */ + pXmitLen->setIntValue(msgLen); // 2. store the size of the properties as transmitted + + if (pMultiPlayDebugLevel->getIntValue() & 2) // and dump it to the console + { + SG_LOG(SG_NETWORK, SG_INFO, + "[SEND] Packet len " << msgLen); + } + if (pMultiPlayDebugLevel->getIntValue() & 4) // 4. hexdump the packet + SG_LOG_HEXDUMP(SG_NETWORK, SG_INFO, data, (ptr - data) * sizeof(*ptr)); + /* + * simple loopback of ourselves - to enable easy MP debug for model developers; see (1) above + */ + if (pMultiPlayDebugLevel->getIntValue() & 1) + { + long stamp = SGTimeStamp::now().getSeconds(); + ProcessPosMsg(msgBuf, mServer, stamp); + } } - if (msgLen>0) + if (msgLen > 0) mSocket->sendto(msgBuf.Msg, msgLen, 0, &mServer); SG_LOG(SG_NETWORK, SG_BULK, "FGMultiplayMgr::SendMyPosition"); } // FGMultiplayMgr::SendMyPosition() +short FGMultiplayMgr::get_scaled_short(double v, double scale) +{ + float nv = v * scale; + if (nv >= 32767) return 32767; + if (nv <= -32767) return -32767; + short rv = (short)nv; + return rv; +} ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// @@ -1055,16 +1395,16 @@ FGMultiplayMgr::update(double dt) if (RecvStatus<0) { #ifdef _WIN32 - if (::WSAGetLastError() != WSAEWOULDBLOCK) // this is normal on a receive when there is no data - { - // with Winsock the error will not be the actual problem. - SG_LOG(SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::MP_ProcessData - Unable to receive data. WSAGetLastError=" << ::WSAGetLastError()); - } + if (::WSAGetLastError() != WSAEWOULDBLOCK) // this is normal on a receive when there is no data + { + // with Winsock the error will not be the actual problem. + SG_LOG(SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::MP_ProcessData - Unable to receive data. WSAGetLastError=" << ::WSAGetLastError()); + } #else - SG_LOG(SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::MP_ProcessData - Unable to receive data. " - << strerror(errno) << "(errno " << errno << ")"); + SG_LOG(SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::MP_ProcessData - Unable to receive data. " + << strerror(errno) << "(errno " << errno << ")"); #endif - break; + break; } // status is positive: bytes received @@ -1138,25 +1478,26 @@ FGMultiplayMgr::update(double dt) void FGMultiplayMgr::Send() { - using namespace simgear; - - findProperties(); - - // smooth the send rate, by adjusting based on the 'remainder' time, which - // is how -ve mTimeUntilSend is. Watch for large values and ignore them, - // however. + using namespace simgear; + + findProperties(); + + // smooth the send rate, by adjusting based on the 'remainder' time, which + // is how -ve mTimeUntilSend is. Watch for large values and ignore them, + // however. if ((mTimeUntilSend < 0.0) && (fabs(mTimeUntilSend) < mDt)) { - mTimeUntilSend = mDt + mTimeUntilSend; - } else { - mTimeUntilSend = mDt; + mTimeUntilSend = mDt + mTimeUntilSend; + } + else { + mTimeUntilSend = mDt; } double sim_time = globals->get_sim_time_sec(); -// static double lastTime = 0.0; - - // SG_LOG(SG_GENERAL, SG_INFO, "actual dt=" << sim_time - lastTime); -// lastTime = sim_time; - + // static double lastTime = 0.0; + + // SG_LOG(SG_GENERAL, SG_INFO, "actual dt=" << sim_time - lastTime); + // lastTime = sim_time; + FlightProperties ifce; // put together a motion info struct, you will get that later @@ -1178,7 +1519,7 @@ FGMultiplayMgr::Send() SGGeod geod = SGGeod::fromRadFt(lon, lat, ifce.get_Altitude()); // Convert to cartesion coordinate motionInfo.position = SGVec3d::fromGeod(geod); - + // The quaternion rotating from the earth centered frame to the // horizontal local frame SGQuatf qEc2Hl = SGQuatf::fromLonLatRad((float)lon, (float)lat); @@ -1191,80 +1532,84 @@ FGMultiplayMgr::Send() motionInfo.orientation = qEc2Hl*hlOr; if (!globals->get_subsystem("flight")->is_suspended()) { - // velocities - motionInfo.linearVel = SG_FEET_TO_METER*SGVec3f(ifce.get_uBody(), - ifce.get_vBody(), - ifce.get_wBody()); - motionInfo.angularVel = SGVec3f(ifce.get_P_body(), - ifce.get_Q_body(), - ifce.get_R_body()); - - // accels, set that to zero for now. - // Angular accelerations are missing from the interface anyway, - // linear accelerations are screwed up at least for JSBSim. -// motionInfo.linearAccel = SG_FEET_TO_METER*SGVec3f(ifce.get_U_dot_body(), -// ifce.get_V_dot_body(), -// ifce.get_W_dot_body()); - motionInfo.linearAccel = SGVec3f::zeros(); - motionInfo.angularAccel = SGVec3f::zeros(); - } else { - // if the interface is suspendend, prevent the client from - // wild extrapolations - motionInfo.linearVel = SGVec3f::zeros(); - motionInfo.angularVel = SGVec3f::zeros(); - motionInfo.linearAccel = SGVec3f::zeros(); - motionInfo.angularAccel = SGVec3f::zeros(); + // velocities + motionInfo.linearVel = SG_FEET_TO_METER*SGVec3f(ifce.get_uBody(), + ifce.get_vBody(), + ifce.get_wBody()); + motionInfo.angularVel = SGVec3f(ifce.get_P_body(), + ifce.get_Q_body(), + ifce.get_R_body()); + + // accels, set that to zero for now. + // Angular accelerations are missing from the interface anyway, + // linear accelerations are screwed up at least for JSBSim. + // motionInfo.linearAccel = SG_FEET_TO_METER*SGVec3f(ifce.get_U_dot_body(), + // ifce.get_V_dot_body(), + // ifce.get_W_dot_body()); + motionInfo.linearAccel = SGVec3f::zeros(); + motionInfo.angularAccel = SGVec3f::zeros(); + } + else { + // if the interface is suspendend, prevent the client from + // wild extrapolations + motionInfo.linearVel = SGVec3f::zeros(); + motionInfo.angularVel = SGVec3f::zeros(); + motionInfo.linearAccel = SGVec3f::zeros(); + motionInfo.angularAccel = SGVec3f::zeros(); } - // now send the properties PropertyMap::iterator it; for (it = mPropertyMap.begin(); it != mPropertyMap.end(); ++it) { - FGPropertyData* pData = new FGPropertyData; - pData->id = it->first; - pData->type = findProperty(pData->id)->type; - - switch (pData->type) { + FGPropertyData* pData = new FGPropertyData; + pData->id = it->first; + pData->type = findProperty(pData->id)->type; + + switch (pData->type) { + case TT_SHORTINT: + case TT_SHORT_FLOAT_1: + case TT_SHORT_FLOAT_2: + case TT_SHORT_FLOAT_3: + case TT_SHORT_FLOAT_4: + case TT_SHORT_FLOAT_NORM: case props::INT: case props::LONG: case props::BOOL: - pData->int_value = it->second->getIntValue(); - break; + pData->int_value = it->second->getIntValue(); + break; case props::FLOAT: case props::DOUBLE: - pData->float_value = it->second->getFloatValue(); - break; + pData->float_value = it->second->getFloatValue(); + break; case props::STRING: case props::UNSPECIFIED: - { + { // FIXME: We assume unspecified are strings for the moment. const char* cstr = it->second->getStringValue(); int len = strlen(cstr); - + if (len > 0) - { - pData->string_value = new char[len + 1]; - strcpy(pData->string_value, cstr); + { + pData->string_value = new char[len + 1]; + strcpy(pData->string_value, cstr); } else { - // Size 0 - ignore - pData->string_value = 0; + // Size 0 - ignore + pData->string_value = 0; } //cout << " Sending property " << pData->id << " " << pData->type << " " << pData->string_value << "\n"; - break; - } + break; + } default: - // FIXME Currently default to a float. - //cout << "Unknown type when iterating through props: " << pData->type << "\n"; - pData->float_value = it->second->getFloatValue(); - break; - } - - motionInfo.properties.push_back(pData); + // FIXME Currently default to a float. + //cout << "Unknown type when iterating through props: " << pData->type << "\n"; + pData->float_value = it->second->getFloatValue(); + break; + } + motionInfo.properties.push_back(pData); } - SendMyPosition(motionInfo); } @@ -1276,77 +1621,107 @@ FGMultiplayMgr::Send() ////////////////////////////////////////////////////////////////////// void FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg, - const simgear::IPAddress& SenderAddress, long stamp) + const simgear::IPAddress& SenderAddress, long stamp) { - const T_MsgHdr* MsgHdr = Msg.msgHdr(); - if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + sizeof(T_PositionMsg)) { - SG_LOG( SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::MP_ProcessData - " - << "Position message received with insufficient data" ); - return; - } - const T_PositionMsg* PosMsg = Msg.posMsg(); - FGExternalMotionData motionInfo; - motionInfo.time = XDR_decode_double(PosMsg->time); - motionInfo.lag = XDR_decode_double(PosMsg->lag); - for (unsigned i = 0; i < 3; ++i) - motionInfo.position(i) = XDR_decode_double(PosMsg->position[i]); - SGVec3f angleAxis; - for (unsigned i = 0; i < 3; ++i) - angleAxis(i) = XDR_decode_float(PosMsg->orientation[i]); - motionInfo.orientation = SGQuatf::fromAngleAxis(angleAxis); - for (unsigned i = 0; i < 3; ++i) - motionInfo.linearVel(i) = XDR_decode_float(PosMsg->linearVel[i]); - for (unsigned i = 0; i < 3; ++i) - motionInfo.angularVel(i) = XDR_decode_float(PosMsg->angularVel[i]); - for (unsigned i = 0; i < 3; ++i) - motionInfo.linearAccel(i) = XDR_decode_float(PosMsg->linearAccel[i]); - for (unsigned i = 0; i < 3; ++i) - motionInfo.angularAccel(i) = XDR_decode_float(PosMsg->angularAccel[i]); + const T_MsgHdr* MsgHdr = Msg.msgHdr(); + if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + sizeof(T_PositionMsg)) { + SG_LOG(SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::MP_ProcessData - " + << "Position message received with insufficient data"); + return; + } + const T_PositionMsg* PosMsg = Msg.posMsg(); + FGExternalMotionData motionInfo; + motionInfo.time = XDR_decode_double(PosMsg->time); + motionInfo.lag = XDR_decode_double(PosMsg->lag); + for (unsigned i = 0; i < 3; ++i) + motionInfo.position(i) = XDR_decode_double(PosMsg->position[i]); + SGVec3f angleAxis; + for (unsigned i = 0; i < 3; ++i) + angleAxis(i) = XDR_decode_float(PosMsg->orientation[i]); + motionInfo.orientation = SGQuatf::fromAngleAxis(angleAxis); + for (unsigned i = 0; i < 3; ++i) + motionInfo.linearVel(i) = XDR_decode_float(PosMsg->linearVel[i]); + for (unsigned i = 0; i < 3; ++i) + motionInfo.angularVel(i) = XDR_decode_float(PosMsg->angularVel[i]); + for (unsigned i = 0; i < 3; ++i) + motionInfo.linearAccel(i) = XDR_decode_float(PosMsg->linearAccel[i]); + for (unsigned i = 0; i < 3; ++i) + motionInfo.angularAccel(i) = XDR_decode_float(PosMsg->angularAccel[i]); - // sanity check: do not allow injection of corrupted data (NaNs) - if (!isSane(motionInfo)) - { + // sanity check: do not allow injection of corrupted data (NaNs) + if (!isSane(motionInfo)) + { // drop this message, keep old position until receiving valid data SG_LOG(SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::ProcessPosMsg - " - << "Position message with invalid data (NaN) received from " - << MsgHdr->Callsign); + << "Position message with invalid data (NaN) received from " + << MsgHdr->Callsign); return; - } + } - //cout << "INPUT MESSAGE\n"; + //cout << "INPUT MESSAGE\n"; - // There was a bug in 1.9.0 and before: T_PositionMsg was 196 bytes - // on 32 bit architectures and 200 bytes on 64 bit, and this - // structure is put directly on the wire. By looking at the padding, - // we can sort through the mess, mostly: - // If padding is 0 (which is not a valid property type), then the - // message was produced by a new client or an old 64 bit client that - // happened to have 0 on the stack; - // Else if the property list starting with the padding word is - // well-formed, then the client is probably an old 32 bit client and - // we'll go with that; - // Else it is an old 64-bit client and properties start after the - // padding. - // There is a chance that we could be fooled by garbage in the - // padding looking like a valid property, so verifyProperties() is - // strict about the validity of the property values. - const xdr_data_t* xdr = Msg.properties(); - if (PosMsg->pad != 0) { - if (verifyProperties(&PosMsg->pad, Msg.propsRecvdEnd())) - xdr = &PosMsg->pad; - else if (!verifyProperties(xdr, Msg.propsRecvdEnd())) - goto noprops; - } - while (xdr < Msg.propsRecvdEnd()) { - // simgear::props::Type type = simgear::props::UNSPECIFIED; - - // First element is always the ID - unsigned id = XDR_decode_uint32(*xdr); - //cout << pData->id << " "; - xdr++; - - // Check the ID actually exists and get the type - const IdPropertyList* plist = findProperty(id); + // There was a bug in 1.9.0 and before: T_PositionMsg was 196 bytes + // on 32 bit architectures and 200 bytes on 64 bit, and this + // structure is put directly on the wire. By looking at the padding, + // we can sort through the mess, mostly: + // If padding is 0 (which is not a valid property type), then the + // message was produced by a new client or an old 64 bit client that + // happened to have 0 on the stack; + // Else if the property list starting with the padding word is + // well-formed, then the client is probably an old 32 bit client and + // we'll go with that; + // Else it is an old 64-bit client and properties start after the + // padding. + // There is a chance that we could be fooled by garbage in the + // padding looking like a valid property, so verifyProperties() is + // strict about the validity of the property values. + const xdr_data_t* xdr = Msg.properties(); + const xdr_data_t* data = xdr; + int MsgLenBytes = Msg.Header.MsgLen; + + /* + * with V2 we use the pad to forcefully invoke older clients to verify (and discard) + * our new protocol. + * This will preserve the position info but not transmit the properties; which is about + * the most reasonable compromise we can have + */ + if (PosMsg->pad != 0 && XDR_decode_int32(PosMsg->pad) != V2_PAD_MAGIC) { + if (verifyProperties(&PosMsg->pad, Msg.propsRecvdEnd())) + xdr = &PosMsg->pad; + else if (!verifyProperties(xdr, Msg.propsRecvdEnd())) + goto noprops; + } + while (xdr < Msg.propsRecvdEnd()) { + // First element is always the ID + unsigned id = XDR_decode_uint32(*xdr); + + /* + * As we can detect a short int encoded value (by the upper word being non-zero) we can + * do the decode here; set the id correctly, extract the integer and set the flag. + * This can then be picked up by the normal processing based on the flag + */ + int int_value = 0; + bool short_int_encoded = false; + if (id & 0xffff0000) + { + int v1, v2; + XDR_decode_shortints32(*xdr, v1, v2); + int_value = v2; + id = v1; + short_int_encoded = true; + } + + if (pMultiPlayDebugLevel->getIntValue() & 8) + SG_LOG(SG_NETWORK, SG_INFO, + "[RECV] add " << std::hex << xdr + << std::dec << + ": buf[" << ((char*)xdr) - ((char*)data) + << "] id=" << id + << " SIenc " << short_int_encoded); + + // Check the ID actually exists and get the type + const IdPropertyList* plist = findProperty(id); + xdr++; if (plist) { @@ -1358,19 +1733,67 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg, case simgear::props::INT: case simgear::props::BOOL: case simgear::props::LONG: - pData->int_value = XDR_decode_uint32(*xdr); - xdr++; + if (short_int_encoded) + { + pData->int_value = int_value; + pData->type = simgear::props::INT; + } + else + { + pData->int_value = XDR_decode_uint32(*xdr); + xdr++; + } //cout << pData->int_value << "\n"; break; case simgear::props::FLOAT: case simgear::props::DOUBLE: - pData->float_value = XDR_decode_float(*xdr); - xdr++; - //cout << pData->float_value << "\n"; + if (short_int_encoded) + { + switch (plist->TransmitAs) + { + case TT_SHORT_FLOAT_1: + pData->float_value = (double)int_value / 10.0; + break; + case TT_SHORT_FLOAT_2: + pData->float_value = (double)int_value / 100.0; + break; + case TT_SHORT_FLOAT_3: + pData->float_value = (double)int_value / 1000.0; + break; + case TT_SHORT_FLOAT_4: + pData->float_value = (double)int_value / 10000.0; + break; + case TT_SHORT_FLOAT_NORM: + pData->float_value = (double)int_value / 32767.0; + break; + default: + break; + } + } + else + { + pData->float_value = XDR_decode_float(*xdr); + xdr++; + } break; case simgear::props::STRING: case simgear::props::UNSPECIFIED: { + // if the string is using short int encoding then it is in the new format. + if (short_int_encoded) + { + uint32_t length = int_value; + pData->string_value = new char[length + 1]; + + char *cptr = (char*)xdr; + for (unsigned i = 0; i < length; i++) + { + pData->string_value[i] = *cptr++; + } + pData->string_value[length] = '\0'; + xdr = (xdr_data_t*)cptr; + } + else { // String is complicated. It consists of // The length of the string // The string itself @@ -1387,7 +1810,6 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg, { pData->string_value[i] = (char) XDR_decode_int8(*xdr); xdr++; - //cout << pData->string_value[i]; } pData->string_value[length] = '\0'; @@ -1401,6 +1823,7 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg, } //cout << "\n"; } + } break; default: @@ -1418,6 +1841,7 @@ FGMultiplayMgr::ProcessPosMsg(const FGMultiplayMgr::MsgBuf& Msg, SG_LOG(SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::ProcessPosMsg - " "message from " << MsgHdr->Callsign << " has unknown property id " << id); + // At this point the packet must be considered to be unreadable // as we have no way of knowing the length of this property (it could be a string) break; @@ -1477,12 +1901,12 @@ FGMultiplayMgr::FillMsgHdr(T_MsgHdr *MsgHdr, int MsgId, unsigned _len) len = sizeof(T_MsgHdr); break; } - MsgHdr->Magic = XDR_encode_uint32(MSG_MAGIC); - MsgHdr->Version = XDR_encode_uint32(PROTO_VER); - MsgHdr->MsgId = XDR_encode_uint32(MsgId); - MsgHdr->MsgLen = XDR_encode_uint32(len); - MsgHdr->ReplyAddress = 0; // Are obsolete, keep them for the server for - MsgHdr->ReplyPort = 0; // now + MsgHdr->Magic = XDR_encode_uint32(MSG_MAGIC); + MsgHdr->Version = XDR_encode_uint32(PROTO_VER); + MsgHdr->MsgId = XDR_encode_uint32(MsgId); + MsgHdr->MsgLen = XDR_encode_uint32(len); + MsgHdr->RequestedRangeNm = XDR_encode_shortints32(0,pMultiPlayRange->getIntValue()); + MsgHdr->ReplyPort = 0; strncpy(MsgHdr->Callsign, mCallsign.c_str(), MAX_CALLSIGN_LEN); MsgHdr->Callsign[MAX_CALLSIGN_LEN - 1] = '\0'; } @@ -1542,6 +1966,7 @@ FGMultiplayMgr::findProperties() } mPropertyMap[id] = pNode; + mPropertyDefinition[id] = &sIdPropertyList[i]; SG_LOG(SG_NETWORK, SG_DEBUG, "activating MP property:" << pNode->getPath()); } } diff --git a/src/MultiPlayer/multiplaymgr.hxx b/src/MultiPlayer/multiplaymgr.hxx index 69c9975cf..a2ad31ef8 100644 --- a/src/MultiPlayer/multiplaymgr.hxx +++ b/src/MultiPlayer/multiplaymgr.hxx @@ -31,6 +31,8 @@ #define MULTIPLAYTXMGR_HID "$Id$" +const int MIN_MP_PROTOCOL_VERSION = 1; +const int MAX_MP_PROTOCOL_VERSION = 2; #include #include @@ -70,11 +72,20 @@ private: { mPropertiesChanged = true; } - + int getProtocolToUse() + { + int protocolVersion = pProtocolVersion->getIntValue(); + if (protocolVersion >= MIN_MP_PROTOCOL_VERSION && protocolVersion <= MAX_MP_PROTOCOL_VERSION) + return protocolVersion; + else + return MIN_MP_PROTOCOL_VERSION; + } + void findProperties(); void Send(); void SendMyPosition(const FGExternalMotionData& motionInfo); + short get_scaled_short(double v, double scale); union MsgBuf; FGAIMultiplayer* addMultiplayer(const std::string& callsign, @@ -100,8 +111,16 @@ private: // and the property nodes typedef std::map > PropertyMap; PropertyMap mPropertyMap; - + SGPropertyNode *pProtocolVersion; + SGPropertyNode *pXmitLen; + SGPropertyNode *pMultiPlayDebugLevel; + SGPropertyNode *pMultiPlayRange; + + typedef std::map PropertyDefinitionMap; + PropertyDefinitionMap mPropertyDefinition; + bool mPropertiesChanged; + MPPropertyListener* mListener; double mDt; // reciprocal of /sim/multiplay/tx-rate-hz diff --git a/src/MultiPlayer/tiny_xdr.cxx b/src/MultiPlayer/tiny_xdr.cxx index e8f292141..1f9c12a9b 100644 --- a/src/MultiPlayer/tiny_xdr.cxx +++ b/src/MultiPlayer/tiny_xdr.cxx @@ -73,6 +73,38 @@ XDR_encode_int32 ( const int32_t & n_Val ) return (SWAP32(static_cast (n_Val))); } +/* + * Safely convert from an int into a short. Anything outside the bounds of a short will + * simply be the max/min value of short (+/- 32767) + */ +static short XDR_convert_int_to_short(int v1) +{ + if (v1 < -32767) + v1 = -32767; + + if (v1 > 32767) + v1 = 32767; + + return (short)v1; +} + +/* + * Pack two 16bit shorts into a 32 bit int. By convention v1 is packed in the highword + */ +xdr_data_t XDR_encode_shortints32(const int v1, const int v2) +{ + return XDR_encode_uint32(((XDR_convert_int_to_short(v1) << 16) & 0xffff0000) | ((XDR_convert_int_to_short(v2)) & 0xffff)); +} +/* Decode packed shorts into two ints. V1 in the highword ($V1..V2..)*/ +void XDR_decode_shortints32(const xdr_data_t & n_Val, int &v1, int &v2) +{ + int _v1 = XDR_decode_int32(n_Val); + short s2 = (short)(_v1 & 0xffff); + short s1 = (short)(_v1 >> 16); + v1 = s1; + v2 = s2; +} + xdr_data_t XDR_encode_uint32 ( const uint32_t & n_Val ) { diff --git a/src/MultiPlayer/tiny_xdr.hxx b/src/MultiPlayer/tiny_xdr.hxx index 7c66a8479..3161989ea 100644 --- a/src/MultiPlayer/tiny_xdr.hxx +++ b/src/MultiPlayer/tiny_xdr.hxx @@ -54,6 +54,9 @@ xdr_data2_t XDR_encode_uint64 ( const uint64_t & n_Val ); int64_t XDR_decode_int64 ( const xdr_data2_t & n_Val ); uint64_t XDR_decode_uint64 ( const xdr_data2_t & n_Val ); +xdr_data_t XDR_encode_shortints32(const int v1, const int v2); +void XDR_decode_shortints32(const xdr_data_t & n_Val, int &v1, int &v2); + ////////////////////////////////////////////////// // // FIXME: #1 these funtions must be fixed for