#include <algorithm>
#include <cstring>
#include <errno.h>
-#include <osg/Math> // isNaN
#include <simgear/misc/stdint.hxx>
#include <simgear/timing/timestamp.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/props/props.hxx>
+#include <simgear/structure/commands.hxx>
#include <AIModel/AIManager.hxx>
#include <AIModel/AIMultiplayer.hxx>
#include <Main/fg_props.hxx>
+#include <Network/RemoteXMLRequest.hxx>
+#include <Network/HTTPClient.hxx>
#include "multiplaymgr.hxx"
#include "mpmessages.hxx"
#include <FDM/flightProperties.hxx>
#define MAX_PACKET_SIZE 1200
#define MAX_TEXT_SIZE 128
-// These constants are provided so that the ident
-// command can list file versions
-const char sMULTIPLAYMGR_BID[] = "$Id$";
-const char sMULTIPLAYMGR_HID[] = MULTIPLAYTXMGR_HID;
-
struct IdPropertyList {
unsigned id;
const char* name;
{1400, "scenery/events", simgear::props::STRING},
+ {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},
+
{10001, "sim/multiplay/transmission-freq-hz", simgear::props::STRING},
{10002, "sim/multiplay/chat", simgear::props::STRING},
case props::DOUBLE:
{
float val = XDR_decode_float(*xdr);
- if (osg::isNaN(val))
+ if (SGMisc<float>::isNaN(val))
return false;
xdr++;
break;
FGMultiplayMgr* _multiplay;
};
+//////////////////////////////////////////////////////////////////////
+//
+// handle command "multiplayer-connect"
+// args:
+// server: servername to connect (mandatory)
+// txport: outgoing port number (default: 5000)
+// 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;
+ }
+
+ 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);
+ }
+
+ servername = servername.substr(0, servername.find_first_of(' '));
+ fgSetString("/sim/multiplay/txhost", servername);
+ self->reinit();
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// handle command "multiplayer-disconnect"
+// disconnect args:
+// 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;
+ }
+
+ fgSetString("/sim/multiplay/txhost", "");
+ self->reinit();
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// handle command "multiplayer-refreshserverlist"
+// refreshserverlist args:
+// none
+//
+//////////////////////////////////////////////////////////////////////
+static bool do_multiplayer_refreshserverlist(const SGPropertyNode * arg) {
+ FGMultiplayMgr * self = (FGMultiplayMgr*) globals->get_subsystem("mp");
+ if (!self) {
+ SG_LOG(SG_NETWORK, SG_WARN, "Multiplayer subsystem not available.");
+ return false;
+ }
+
+ FGHTTPClient* http = static_cast<FGHTTPClient*>(globals->get_subsystem("http"));
+ if (!http) {
+ SG_LOG(SG_IO, SG_ALERT,
+ "do_multiplayer.refreshserverlist: HTTP client not running");
+ return false;
+ }
+
+ string url(
+ fgGetString("/sim/multiplay/serverlist-url",
+ "http://liveries.flightgear.org/mpstatus/mpservers.xml"));
+
+ if (url.empty()) {
+ SG_LOG(SG_IO, SG_ALERT,
+ "do_multiplayer.refreshserverlist: no URL given");
+ return false;
+ }
+
+ SGPropertyNode *targetnode = fgGetNode("/sim/multiplay/server-list", true);
+ SGPropertyNode *completeNode = fgGetNode("/sim/multiplay/got-servers", true);
+ SGPropertyNode *failureNode = fgGetNode("/sim/multiplay/get-servers-failure", true);
+ RemoteXMLRequest* req = new RemoteXMLRequest(url, targetnode);
+ req->setCompletionProp(completeNode);
+ req->setFailedProp(failureNode);
+ completeNode->setBoolValue(false);
+ failureNode->setBoolValue(false);
+ http->makeRequest(req);
+ return true;
+}
+
//////////////////////////////////////////////////////////////////////
//
// MultiplayMgr constructor
mInitialised = false;
mHaveServer = false;
mListener = NULL;
+ 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);
} // FGMultiplayMgr::FGMultiplayMgr()
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
FGMultiplayMgr::~FGMultiplayMgr()
{
-
+ globals->get_commands()->removeCommand("multiplayer-connect");
+ globals->get_commands()->removeCommand("multiplayer-disconnect");
+ globals->get_commands()->removeCommand("multiplayer-refreshserverlist");
} // FGMultiplayMgr::~FGMultiplayMgr()
//////////////////////////////////////////////////////////////////////
return;
}
- fgSetBool("/sim/multiplay/online", false);
-
- if (!fgGetBool("/sim/ai/enabled"))
- {
- SG_LOG(SG_NETWORK, SG_ALERT,
- "Cannot enable multiplayer mode: AI subsystem is disabled (to enable start with '--enable-ai-models').");
- return;
- }
+ SGPropertyNode* propOnline = fgGetNode("/sim/multiplay/online", true);
+ propOnline->setBoolValue(false);
+ propOnline->setAttribute(SGPropertyNode::PRESERVE, true);
//////////////////////////////////////////////////
// Set members from property values
mTimeUntilSend = 0.0;
mCallsign = fgGetString("/sim/multiplay/callsign");
+ fgGetNode("/sim/multiplay/callsign", true)->setAttribute(SGPropertyNode::PRESERVE, true);
+
if ((!txAddress.empty()) && (txAddress!="0")) {
mServer.set(txAddress.c_str(), txPort);
if (strncmp (mServer.getHost(), "0.0.0.0", 8) == 0) {
if (rxPort <= 0)
rxPort = txPort;
} else {
- SG_LOG(SG_NETWORK, SG_ALERT, "Cannot enable multiplayer mode: missing a valid server address.");
+ SG_LOG(SG_NETWORK, SG_INFO, "FGMultiplayMgr - multiplayer mode disabled (no MP server specificed).");
return;
}
mInitialised = true;
SG_LOG(SG_NETWORK, SG_ALERT, "Multiplayer mode active!");
+
+ if (!fgGetBool("/sim/ai/enabled"))
+ {
+ // multiplayer depends on AI module
+ fgSetBool("/sim/ai/enabled", true);
+ }
} // FGMultiplayMgr::init()
//////////////////////////////////////////////////////////////////////
{
// check for corrupted data (NaNs)
bool isCorrupted = false;
- isCorrupted |= ((osg::isNaN(motionInfo.time )) ||
- (osg::isNaN(motionInfo.lag )) ||
+ isCorrupted |= ((SGMisc<double>::isNaN(motionInfo.time )) ||
+ (SGMisc<double>::isNaN(motionInfo.lag )) ||
(osg::isNaN(motionInfo.orientation(3) )));
for (unsigned i = 0; (i < 3)&&(!isCorrupted); ++i)
{
motionInfo.orientation.getAngleAxis(angleAxis);
for (unsigned i = 0 ; i < 3; ++i)
PosMsg->orientation[i] = XDR_encode_float (angleAxis(i));
- for (unsigned i = 0 ; i < 3; ++i)
- PosMsg->linearVel[i] = XDR_encode_float (motionInfo.linearVel(i));
- for (unsigned i = 0 ; i < 3; ++i)
- PosMsg->angularVel[i] = XDR_encode_float (motionInfo.angularVel(i));
- for (unsigned i = 0 ; i < 3; ++i)
- PosMsg->linearAccel[i] = XDR_encode_float (motionInfo.linearAccel(i));
- for (unsigned i = 0 ; i < 3; ++i)
- PosMsg->angularAccel[i] = XDR_encode_float (motionInfo.angularAccel(i));
-
+ if (fgGetBool("/sim/crashed",true))
+ {
+ for (unsigned i = 0 ; i < 3; ++i)
+ {
+ // no speed or acceleration sent when crashed, for better mp patch
+ PosMsg->linearVel[i] = XDR_encode_float (0.0);
+ PosMsg->angularVel[i] = XDR_encode_float (0.0);
+ PosMsg->linearAccel[i] = XDR_encode_float (0.0);
+ PosMsg->angularAccel[i] = XDR_encode_float (0.0);
+ }
+ }
+ else
+ {
+ //including speed up time in velocity and acceleration
+ double timeAccel = fgGetDouble("/sim/speed-up");
+ for (unsigned i = 0 ; i < 3; ++i)
+ PosMsg->linearVel[i] = XDR_encode_float (motionInfo.linearVel(i) * timeAccel);
+ for (unsigned i = 0 ; i < 3; ++i)
+ PosMsg->angularVel[i] = XDR_encode_float (motionInfo.angularVel(i) * timeAccel);
+ for (unsigned i = 0 ; i < 3; ++i)
+ PosMsg->linearAccel[i] = XDR_encode_float (motionInfo.linearAccel(i) * timeAccel * timeAccel);
+ for (unsigned i = 0 ; i < 3; ++i)
+ PosMsg->angularAccel[i] = XDR_encode_float (motionInfo.angularAccel(i) * timeAccel * timeAccel);
+ }
xdr_data_t* ptr = msgBuf.properties();
std::vector<FGPropertyData*>::const_iterator it;
it = motionInfo.properties.begin();