#include <simgear/structure/event_mgr.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/timing/sg_time.hxx>
-#include <simgear/io/HTTPRequest.hxx>
+#include <Network/RemoteXMLRequest.hxx>
#include <FDM/flight.hxx>
#include <GUI/gui.h>
#include <GUI/dialog.hxx>
#include <Aircraft/replay.hxx>
#include <Scenery/scenery.hxx>
+#include <Scenery/tilemgr.hxx>
#include <Scripting/NasalSys.hxx>
#include <Sound/sample_queue.hxx>
#include <Airports/xmlloader.hxx>
#include <Network/HTTPClient.hxx>
#include <Viewer/viewmgr.hxx>
-#include <Viewer/viewer.hxx>
+#include <Viewer/view.hxx>
#include <Environment/presets.hxx>
+#include <Navaids/NavDataCache.hxx>
#include "fg_init.hxx"
#include "fg_io.hxx"
# include <google/profiler.h>
#endif
+#if defined(HAVE_QT)
+#include <GUI/QtLauncher.hxx>
+#endif
+
using std::string;
using std::ifstream;
using std::ofstream;
static bool
do_reset (const SGPropertyNode * arg)
{
- fgReInitSubsystems();
+ fgResetIdleState();
return true;
}
+
+/**
+ * Change aircraft
+ */
+static bool
+do_switch_aircraft (const SGPropertyNode * arg)
+{
+ fgSetString("/sim/aircraft", arg->getStringValue("aircraft"));
+ // start a reset
+ fgResetIdleState();
+ return true;
+}
+
+/**
+ */
+static bool
+do_reposition (const SGPropertyNode * arg)
+{
+ fgStartReposition();
+ return true;
+}
+
/**
* Built-in command: replay the FDR buffer
*/
static bool
do_pause (const SGPropertyNode * arg)
{
+ bool forcePause = arg->getBoolValue("force-pause", false );
+ bool forcePlay = arg->getBoolValue("force-play", false );
+
bool paused = fgGetBool("/sim/freeze/master",true) || fgGetBool("/sim/freeze/clock",true);
+
+ if(forcePause) paused = false;
+ if(forcePlay) paused = true;
+
if (paused && (fgGetInt("/sim/freeze/replay-state",0)>0))
{
do_replay(NULL);
fgSetBool("/sim/freeze/clock",!paused);
}
- SGPropertyNode_ptr args(new SGPropertyNode);
- args->setStringValue("id", "sim-pause");
- if (!paused) {
- args->setStringValue("label", "Simulation is paused");
- globals->get_commands()->execute("show-message", args);
- } else {
- globals->get_commands()->execute("clear-message", args);
- }
-
+ syncPausePopupState();
return true;
}
static bool
do_load (const SGPropertyNode * arg)
{
- string file = arg->getStringValue("file", "fgfs.sav");
- if (file.size() < 4 || file.substr(file.size() - 4) != ".sav")
- file += ".sav";
+ SGPath file(arg->getStringValue("file", "fgfs.sav"));
+
+ if (file.extension() != "sav")
+ file.concat(".sav");
- if (!fgValidatePath(file.c_str(), false)) {
+ std::string validated_path = fgValidatePath(file, false);
+ if (validated_path.empty()) {
SG_LOG(SG_IO, SG_ALERT, "load: reading '" << file << "' denied "
"(unauthorized access)");
return false;
}
- ifstream input(file.c_str());
+ ifstream input(validated_path.c_str());
if (input.good() && fgLoadFlight(input)) {
input.close();
SG_LOG(SG_INPUT, SG_INFO, "Restored flight from " << file);
static bool
do_save (const SGPropertyNode * arg)
{
- string file = arg->getStringValue("file", "fgfs.sav");
- if (file.size() < 4 || file.substr(file.size() - 4) != ".sav")
- file += ".sav";
+ SGPath file(arg->getStringValue("file", "fgfs.sav"));
- if (!fgValidatePath(file.c_str(), false)) {
+ if (file.extension() != "sav")
+ file.concat(".sav");
+
+ std::string validated_path = fgValidatePath(file, true);
+ if (validated_path.empty()) {
SG_LOG(SG_IO, SG_ALERT, "save: writing '" << file << "' denied "
"(unauthorized access)");
return false;
bool write_all = arg->getBoolValue("write-all", false);
SG_LOG(SG_INPUT, SG_INFO, "Saving flight");
- ofstream output(file.c_str());
+ ofstream output(validated_path.c_str());
if (output.good() && fgSaveFlight(output, write_all)) {
output.close();
SG_LOG(SG_INPUT, SG_INFO, "Saved flight to " << file);
/**
* Reload the materials definition
*/
- static bool
- do_materials_reload (const SGPropertyNode * arg)
- {
- SG_LOG(SG_INPUT, SG_INFO, "Reloading Materials");
- SGMaterialLib* new_matlib = new SGMaterialLib;
- SGPath mpath( globals->get_fg_root() );
- mpath.append( fgGetString("/sim/rendering/materials-file") );
- bool loaded = new_matlib->load(globals->get_fg_root(),
+static bool
+do_materials_reload (const SGPropertyNode * arg)
+{
+ SG_LOG(SG_INPUT, SG_INFO, "Reloading Materials");
+ SGMaterialLib* new_matlib = new SGMaterialLib;
+ SGPath mpath( globals->get_fg_root() );
+ mpath.append( fgGetString("/sim/rendering/materials-file") );
+ bool loaded = new_matlib->load(globals->get_fg_root(),
mpath.str(),
globals->get_props());
-
- if ( ! loaded ) {
+
+ if ( ! loaded ) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Error loading materials file " << mpath.str() );
return false;
- }
-
- globals->set_matlib(new_matlib);
- return true;
- }
-
-
-#if 0
-These do_set_(some-environment-parameters) are deprecated and no longer
-useful/functional - Torsten Dreyer, January 2011
-/**
- * Set the sea level outside air temperature and assigning that to all
- * boundary and aloft environment layers.
- */
-static bool
-do_set_sea_level_degc ( double temp_sea_level_degc)
-{
- SGPropertyNode *node, *child;
-
- // boundary layers
- node = fgGetNode( "/environment/config/boundary" );
- if ( node != NULL ) {
- int i = 0;
- while ( ( child = node->getNode( "entry", i ) ) != NULL ) {
- child->setDoubleValue( "temperature-sea-level-degc",
- temp_sea_level_degc );
- ++i;
- }
- }
-
- // aloft layers
- node = fgGetNode( "/environment/config/aloft" );
- if ( node != NULL ) {
- int i = 0;
- while ( ( child = node->getNode( "entry", i ) ) != NULL ) {
- child->setDoubleValue( "temperature-sea-level-degc",
- temp_sea_level_degc );
- ++i;
- }
- }
-
- return true;
-}
-
-static bool
-do_set_sea_level_degc (const SGPropertyNode * arg)
-{
- return do_set_sea_level_degc( arg->getDoubleValue("temp-degc", 15.0) );
-}
-
-
-/**
- * Set the outside air temperature at the "current" altitude by first
- * calculating the corresponding sea level temp, and assigning that to
- * all boundary and aloft environment layers.
- */
-static bool
-do_set_oat_degc (const SGPropertyNode * arg)
-{
- double oat_degc = arg->getDoubleValue("temp-degc", 15.0);
- // check for an altitude specified in the arguments, otherwise use
- // current aircraft altitude.
- const SGPropertyNode *altitude_ft = arg->getChild("altitude-ft");
- if ( altitude_ft == NULL ) {
- altitude_ft = fgGetNode("/position/altitude-ft");
- }
-
- FGEnvironment dummy; // instantiate a dummy so we can leech a method
- dummy.set_elevation_ft( altitude_ft->getDoubleValue() );
- dummy.set_temperature_degc( oat_degc );
- return do_set_sea_level_degc( dummy.get_temperature_sea_level_degc());
-}
-
-/**
- * Set the sea level outside air dewpoint and assigning that to all
- * boundary and aloft environment layers.
- */
-static bool
-do_set_dewpoint_sea_level_degc (double dewpoint_sea_level_degc)
-{
-
- SGPropertyNode *node, *child;
-
- // boundary layers
- node = fgGetNode( "/environment/config/boundary" );
- if ( node != NULL ) {
- int i = 0;
- while ( ( child = node->getNode( "entry", i ) ) != NULL ) {
- child->setDoubleValue( "dewpoint-sea-level-degc",
- dewpoint_sea_level_degc );
- ++i;
- }
- }
-
- // aloft layers
- node = fgGetNode( "/environment/config/aloft" );
- if ( node != NULL ) {
- int i = 0;
- while ( ( child = node->getNode( "entry", i ) ) != NULL ) {
- child->setDoubleValue( "dewpoint-sea-level-degc",
- dewpoint_sea_level_degc );
- ++i;
- }
- }
+ }
+ globals->set_matlib(new_matlib);
+ FGTileMgr* tileManager = static_cast<FGTileMgr*>(globals->get_subsystem("tile-manager"));
+ tileManager->materialLibChanged();
+
return true;
}
-static bool
-do_set_dewpoint_sea_level_degc (const SGPropertyNode * arg)
-{
- return do_set_dewpoint_sea_level_degc(arg->getDoubleValue("dewpoint-degc", 5.0));
-}
-
-/**
- * Set the outside air dewpoint at the "current" altitude by first
- * calculating the corresponding sea level dewpoint, and assigning
- * that to all boundary and aloft environment layers.
- */
-static bool
-do_set_dewpoint_degc (const SGPropertyNode * arg)
-{
- double dewpoint_degc = arg->getDoubleValue("dewpoint-degc", 5.0);
-
- // check for an altitude specified in the arguments, otherwise use
- // current aircraft altitude.
- const SGPropertyNode *altitude_ft = arg->getChild("altitude-ft");
- if ( altitude_ft == NULL ) {
- altitude_ft = fgGetNode("/position/altitude-ft");
- }
-
- FGEnvironment dummy; // instantiate a dummy so we can leech a method
- dummy.set_elevation_ft( altitude_ft->getDoubleValue() );
- dummy.set_dewpoint_degc( dewpoint_degc );
- return do_set_dewpoint_sea_level_degc(dummy.get_dewpoint_sea_level_degc());
-}
-#endif
-
/**
* Built-in command: toggle a bool property value.
*
return openBrowser(path);
}
+static bool
+do_open_launcher(const SGPropertyNode *)
+{
+#if defined(HAVE_QT)
+ bool ok = flightgear::runInAppLauncherDialog();
+ if (ok) {
+ // start a full reset
+ fgResetIdleState();
+ }
+ return ok;
+#else
+ return false;
+#endif
+}
+
/**
* Apply a value in the active XML-configured dialog.
*
return true;
}
-/**
- * Built-in command: play an audio message (i.e. a wav file) This is
- * fire and forget. Call this once per message and it will get dumped
- * into a queue. Messages are played sequentially so they do not
- * overlap.
- */
-static bool
-do_play_audio_sample (const SGPropertyNode * arg)
-{
- SGSoundMgr *smgr = globals->get_soundmgr();
- if (!smgr) {
- SG_LOG(SG_GENERAL, SG_WARN, "play-audio-sample: sound-manager not running");
- return false;
- }
-
- string path = arg->getStringValue("path");
- string file = arg->getStringValue("file");
- float volume = arg->getFloatValue("volume");
- // cout << "playing " << path << " / " << file << endl;
- try {
- static FGSampleQueue *queue = 0;
- if ( !queue ) {
- queue = new FGSampleQueue(smgr, "chatter");
- queue->tie_to_listener();
- }
-
- SGSoundSample *msg = new SGSoundSample(file.c_str(), path);
- msg->set_volume( volume );
- queue->add( msg );
-
- return true;
-
- } catch (const sg_io_exception&) {
- SG_LOG(SG_GENERAL, SG_ALERT, "play-audio-sample: "
- "failed to load" << path << '/' << file);
- return false;
- }
-}
-
/**
* Built-in command: commit presets (read from in /sim/presets/)
*/
do_presets_commit (const SGPropertyNode * arg)
{
if (fgGetBool("/sim/initialized", false)) {
- fgReInitSubsystems();
+ fgResetIdleState();
} else {
// Nasal can trigger this during initial init, which confuses
// the logic in ReInitSubsystems, since initial state has not been
}
}
- if (!fgValidatePath(file.c_str(), false)) {
+ std::string validated_path = fgValidatePath(file, false);
+ if (validated_path.empty()) {
SG_LOG(SG_IO, SG_ALERT, "loadxml: reading '" << file.str() << "' denied "
- "(unauthorized access)");
+ "(unauthorized directory - authorization no longer follows symlinks; to authorize reading additional directories, add them to --fg-aircraft)");
return false;
}
targetnode = const_cast<SGPropertyNode *>(arg)->getNode("data", true);
try {
- readProperties(file.c_str(), targetnode, true);
+ readProperties(validated_path.c_str(), targetnode, true);
} catch (const sg_exception &e) {
SG_LOG(SG_IO, SG_WARN, "loadxml: " << e.getFormattedMessage());
return false;
return true;
}
-class RemoteXMLRequest : public simgear::HTTP::Request
-{
-public:
- SGPropertyNode_ptr _complete;
- SGPropertyNode_ptr _status;
- SGPropertyNode_ptr _failed;
- SGPropertyNode_ptr _target;
- string propsData;
- mutable string _requestBody;
- int _requestBodyLength;
- string _method;
-
- RemoteXMLRequest(const std::string& url, SGPropertyNode* targetNode) :
- simgear::HTTP::Request(url),
- _target(targetNode),
- _requestBodyLength(-1),
- _method("GET")
- {
- }
-
- void setCompletionProp(SGPropertyNode_ptr p)
- {
- _complete = p;
- }
-
- void setStatusProp(SGPropertyNode_ptr p)
- {
- _status = p;
- }
-
- void setFailedProp(SGPropertyNode_ptr p)
- {
- _failed = p;
- }
-
- void setRequestData(const SGPropertyNode* body)
- {
- _method = "POST";
- std::stringstream buf;
- writeProperties(buf, body, true);
- _requestBody = buf.str();
- _requestBodyLength = _requestBody.size();
- }
-
- virtual std::string method() const
- {
- return _method;
- }
-protected:
- virtual int requestBodyLength() const
- {
- return _requestBodyLength;
- }
-
- virtual void getBodyData(char* s, int& count) const
- {
- int toRead = std::min(count, (int) _requestBody.size());
- memcpy(s, _requestBody.c_str(), toRead);
- count = toRead;
- _requestBody = _requestBody.substr(count);
- }
-
- virtual std::string requestBodyType() const
- {
- return "application/xml";
- }
-
- virtual void gotBodyData(const char* s, int n)
- {
- propsData += string(s, n);
- }
-
- virtual void failed()
- {
- SG_LOG(SG_IO, SG_INFO, "network level failure in RemoteXMLRequest");
- if (_failed) {
- _failed->setBoolValue(true);
- }
- }
-
- virtual void responseComplete()
- {
- simgear::HTTP::Request::responseComplete();
-
- int response = responseCode();
- bool failed = false;
- if (response == 200) {
- try {
- const char* buffer = propsData.c_str();
- readProperties(buffer, propsData.size(), _target, true);
- } catch (const sg_exception &e) {
- SG_LOG(SG_IO, SG_WARN, "parsing XML from remote, failed: " << e.getFormattedMessage());
- failed = true;
- response = 406; // 'not acceptable', anything better?
- }
- } else {
- failed = true;
- }
- // now the response data is output, signal Nasal / listeners
- if (_complete) _complete->setBoolValue(true);
- if (_status) _status->setIntValue(response);
- if (_failed && failed) _failed->setBoolValue(true);
- }
-};
-
-
static bool
do_load_xml_from_url(const SGPropertyNode * arg)
{
RemoteXMLRequest* req = new RemoteXMLRequest(url, targetnode);
if (arg->hasChild("body"))
- req->setRequestData(arg->getChild("body"));
+ req->setBodyData(arg->getChild("body"));
// connect up optional reporting properties
if (arg->hasValue("complete"))
if (file.extension() != "xml")
file.concat(".xml");
- if (!fgValidatePath(file.c_str(), true)) {
+ std::string validated_path = fgValidatePath(file, true);
+ if (validated_path.empty()) {
SG_LOG(SG_IO, SG_ALERT, "savexml: writing to '" << file.str() << "' denied "
- "(unauthorized access)");
+ "(unauthorized directory - authorization no longer follows symlinks)");
return false;
}
return false;
try {
- writeProperties (file.c_str(), sourcenode, true);
+ writeProperties (validated_path.c_str(), sourcenode, true);
} catch (const sg_exception &e) {
SG_LOG(SG_IO, SG_WARN, "savexml: " << e.getFormattedMessage());
return false;
}
+static bool
+do_set_scenery_paths(const SGPropertyNode* arg)
+{
+ globals->clear_fg_scenery();
+
+ std::string terrasyncPath(fgGetString("/sim/terrasync/scenery-dir"));
+ bool seenTerrasyncPath = false;
+
+ simgear::PropertyList paths = arg->getChildren("path");
+ for (size_t i = 0; i < paths.size(); ++i) {
+ std::string s = paths[i]->getStringValue();
+ if (s == terrasyncPath) {
+ seenTerrasyncPath = true;
+ }
+
+ globals->append_fg_scenery(s);
+ }
+
+ if (fgGetBool("/sim/terrasync/enabled") && !seenTerrasyncPath) {
+ globals->append_fg_scenery(terrasyncPath);
+ }
+
+ if (paths.empty()) {
+ // no scenery paths set *at all*, use the data in FG_ROOT
+ SGPath root(globals->get_fg_root());
+ root.append("Scenery");
+ globals->append_fg_scenery(root.str());
+ }
+
+ return true;
+}
+
////////////////////////////////////////////////////////////////////////
// Command setup.
////////////////////////////////////////////////////////////////////////
{ "nasal", do_nasal },
{ "exit", do_exit },
{ "reset", do_reset },
+ { "reposition", do_reposition },
+ { "switch-aircraft", do_switch_aircraft },
{ "pause", do_pause },
{ "load", do_load },
{ "save", do_save },
{ "open-browser", do_open_browser },
{ "gui-redraw", do_gui_redraw },
{ "add-model", do_add_model },
- { "play-audio-sample", do_play_audio_sample },
{ "presets-commit", do_presets_commit },
{ "log-level", do_log_level },
{ "replay", do_replay },
+ { "open-launcher", do_open_launcher },
/*
{ "decrease-visibility", do_decrease_visibility },
{ "increase-visibility", do_increase_visibility },
{ "print-visible-scene", do_print_visible_scene_info },
{ "reload-shaders", do_reload_shaders },
{ "reload-materials", do_materials_reload },
-
+ { "set-scenery-paths", do_set_scenery_paths },
+
{ "profiler-start", do_profiler_start },
{ "profiler-stop", do_profiler_stop },