]> git.mxchange.org Git - flightgear.git/blobdiff - src/Main/fg_commands.cxx
Fix for the fix: check for a viewer.
[flightgear.git] / src / Main / fg_commands.cxx
index fc70b43f107347eb2c4c6b4fb806d9f32e1000a7..4c0f580b0d87051c9efe8a2927cc25835ea0a2d5 100644 (file)
 #include <simgear/structure/exception.hxx>
 #include <simgear/structure/commands.hxx>
 #include <simgear/props/props.hxx>
+#include <simgear/props/props_io.hxx>
 #include <simgear/structure/event_mgr.hxx>
 #include <simgear/sound/soundmgr_openal.hxx>
 #include <simgear/timing/sg_time.hxx>
+#include <simgear/io/HTTPMemoryRequest.hxx>
 
-#include <Cockpit/panel.hxx>
-#include <Cockpit/panel_io.hxx>
 #include <FDM/flight.hxx>
 #include <GUI/gui.h>
 #include <GUI/new_gui.hxx>
 #include <Scenery/scenery.hxx>
 #include <Scripting/NasalSys.hxx>
 #include <Sound/sample_queue.hxx>
-#include <Time/sunsolver.hxx>
+#include <Airports/xmlloader.hxx>
+#include <Network/HTTPClient.hxx>
+#include <Viewer/viewmgr.hxx>
+#include <Viewer/viewer.hxx>
+#include <Environment/presets.hxx>
 
 #include "fg_init.hxx"
 #include "fg_io.hxx"
 #include "globals.hxx"
 #include "logger.hxx"
 #include "util.hxx"
-#include "viewmgr.hxx"
 #include "main.hxx"
-#include <Main/viewer.hxx>
-#include <Environment/presets.hxx>
+#include "positioninit.hxx"
+
+#include <boost/scoped_array.hpp>
+
+#if FG_HAVE_GPERFTOOLS
+# include <google/profiler.h>
+#endif
 
 using std::string;
 using std::ifstream;
 using std::ofstream;
 
 
-\f
 ////////////////////////////////////////////////////////////////////////
 // Static helper functions.
 ////////////////////////////////////////////////////////////////////////
@@ -151,7 +158,7 @@ compare_values (SGPropertyNode * value1, SGPropertyNode * value2)
 }
 
 
-\f
+
 ////////////////////////////////////////////////////////////////////////
 // Command implementations.
 ////////////////////////////////////////////////////////////////////////
@@ -185,31 +192,7 @@ do_exit (const SGPropertyNode * arg)
 {
     SG_LOG(SG_INPUT, SG_INFO, "Program exit requested.");
     fgSetBool("/sim/signals/exit", true);
-
-    if (fgGetBool("/sim/startup/save-on-exit")) {
-#ifdef _WIN32
-        char* envp = ::getenv( "APPDATA" );
-        if ( envp != NULL ) {
-            SGPath config( envp );
-            config.append( "flightgear.org" );
-#else
-        if ( homedir != NULL ) {
-            SGPath config( homedir );
-            config.append( ".fgfs" );
-#endif
-            config.append( "autosave.xml" );
-            config.create_dir( 0700 );
-            SG_LOG(SG_IO, SG_INFO, "Saving user settings to " << config.str());
-            try {
-                writeProperties(config.str(), globals->get_props(), false, SGPropertyNode::USERARCHIVE);
-            } catch (const sg_exception &e) {
-                guiErrorMessage("Error writing autosave.xml: ", e);
-            }
-
-            SG_LOG(SG_INPUT, SG_DEBUG, "Finished Saving user settings");
-        }
-    }
-    
+    globals->saveUserSettings();
     fgOSExit(arg->getIntValue("status", 0));
     return true;
 }
@@ -225,103 +208,42 @@ do_reset (const SGPropertyNode * arg)
     return true;
 }
 
-
 /**
- * Built-in command: reinitialize one or more subsystems.
- *
- * subsystem[*]: the name(s) of the subsystem(s) to reinitialize; if
- * none is specified, reinitialize all of them.
+ * Built-in command: replay the FDR buffer
  */
 static bool
-do_reinit (const SGPropertyNode * arg)
+do_replay (const SGPropertyNode * arg)
 {
-    bool result = true;
-
-    vector<SGPropertyNode_ptr> subsystems = arg->getChildren("subsystem");
-    if (subsystems.size() == 0) {
-        globals->get_subsystem_mgr()->reinit();
-    } else {
-        for ( unsigned int i = 0; i < subsystems.size(); i++ ) {
-            const char * name = subsystems[i]->getStringValue();
-            SGSubsystem * subsystem = globals->get_subsystem(name);
-            if (subsystem == 0) {
-                result = false;
-                SG_LOG( SG_GENERAL, SG_ALERT,
-                        "Subsystem " << name << " not found" );
-            } else {
-                subsystem->reinit();
-            }
-        }
-    }
-
-    globals->get_event_mgr()->reinit();
-
-    return result;
+    FGReplay *r = (FGReplay *)(globals->get_subsystem( "replay" ));
+    return r->start();
 }
 
-#if 0
-  //
-  // these routines look useful ??? but are never used in the code ???
-  //
-
 /**
- * Built-in command: suspend one or more subsystems.
- *
- * subsystem[*] - the name(s) of the subsystem(s) to suspend.
+ * Built-in command: pause/unpause the sim
  */
 static bool
-do_suspend (const SGPropertyNode * arg)
+do_pause (const SGPropertyNode * arg)
 {
-    bool result = true;
-
-    vector<SGPropertyNode_ptr> subsystems = arg->getChildren("subsystem");
-    for ( unsigned int i = 0; i < subsystems.size(); i++ ) {
-        const char * name = subsystems[i]->getStringValue();
-        SGSubsystem * subsystem = globals->get_subsystem(name);
-        if (subsystem == 0) {
-            result = false;
-            SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found");
-        } else {
-            subsystem->suspend();
-        }
+    bool paused = fgGetBool("/sim/freeze/master",true) || fgGetBool("/sim/freeze/clock",true);
+    if (paused && (fgGetInt("/sim/freeze/replay-state",0)>0))
+    {
+        do_replay(NULL);
     }
-    return result;
-}
-
-/**
- * Built-in command: suspend one or more subsystems.
- *
- * subsystem[*] - the name(s) of the subsystem(s) to suspend.
- */
-static bool
-do_resume (const SGPropertyNode * arg)
-{
-    bool result = true;
-
-    vector<SGPropertyNode_ptr> subsystems = arg->getChildren("subsystem");
-    for ( unsigned int i = 0; i < subsystems.size(); i++ ) {
-        const char * name = subsystems[i]->getStringValue();
-        SGSubsystem * subsystem = globals->get_subsystem(name);
-        if (subsystem == 0) {
-            result = false;
-            SG_LOG(SG_GENERAL, SG_ALERT, "Subsystem " << name << " not found");
-        } else {
-            subsystem->resume();
-        }
+    else
+    {
+        fgSetBool("/sim/freeze/master",!paused);
+        fgSetBool("/sim/freeze/clock",!paused);
     }
-    return result;
-}
-
-#endif
-
-static bool
-do_pause (const SGPropertyNode * arg)
-{
-    bool paused = fgGetBool("/sim/freeze/master",true);
-    fgSetBool("/sim/freeze/master",!paused);
-    fgSetBool("/sim/freeze/clock",!paused);
-    if (fgGetBool("/sim/freeze/replay-state",false))
-        fgSetBool("/sim/replay/disable",true);
+  
+    SGPropertyNode_ptr args(new SGPropertyNode);
+    args->setStringValue("id", "sim-pause");
+    if (!paused && fgGetBool("/sim/view-name-popup")) {
+      args->setStringValue("label", "Simulation is paused");
+      globals->get_commands()->execute("show-message", args);
+    } else {
+      globals->get_commands()->execute("clear-message", args);
+    }
+  
     return true;
 }
 
@@ -388,6 +310,30 @@ do_save (const SGPropertyNode * arg)
     }
 }
 
+/**
+ * Built-in command: save flight recorder tape.
+ *
+ */
+static bool
+do_save_tape (const SGPropertyNode * arg)
+{
+    FGReplay* replay = (FGReplay*) globals->get_subsystem("replay");
+    replay->saveTape(arg);
+
+    return true;
+}
+/**
+ * Built-in command: load flight recorder tape.
+ *
+ */
+static bool
+do_load_tape (const SGPropertyNode * arg)
+{
+    FGReplay* replay = (FGReplay*) globals->get_subsystem("replay");
+    replay->loadTape(arg);
+
+    return true;
+}
 
 /**
  * Built-in command: (re)load the panel.
@@ -399,49 +345,15 @@ do_save (const SGPropertyNode * arg)
 static bool
 do_panel_load (const SGPropertyNode * arg)
 {
-  string panel_path =
-    arg->getStringValue("path", fgGetString("/sim/panel/path"));
-  if (panel_path.empty()) {
-    return false;
+  string panel_path = arg->getStringValue("path");
+  if (!panel_path.empty()) {
+    // write to the standard property, which will force a load
+    fgSetString("/sim/panel/path", panel_path.c_str());
   }
   
-  FGPanel * new_panel = fgReadPanel(panel_path);
-  if (new_panel == 0) {
-    SG_LOG(SG_INPUT, SG_ALERT,
-          "Error reading new panel from " << panel_path);
-    return false;
-  }
-  SG_LOG(SG_INPUT, SG_INFO, "Loaded new panel from " << panel_path);
-  globals->get_current_panel()->unbind();
-  delete globals->get_current_panel();
-  globals->set_current_panel( new_panel );
-  globals->get_current_panel()->bind();
   return true;
 }
 
-
-/**
- * Built-in command: pass a mouse click to the panel.
- *
- * button: the mouse button number, zero-based.
- * is-down: true if the button is down, false if it is up.
- * x-pos: the x position of the mouse click.
- * y-pos: the y position of the mouse click.
- */
-static bool
-do_panel_mouse_click (const SGPropertyNode * arg)
-{
-  if (globals->get_current_panel() != 0)
-    return globals->get_current_panel()
-      ->doMouseAction(arg->getIntValue("button"),
-                     arg->getBoolValue("is-down") ? PU_DOWN : PU_UP,
-                     arg->getIntValue("x-pos"),
-                     arg->getIntValue("y-pos"));
-  else
-    return false;
-}
-
-
 /**
  * Built-in command: (re)load preferences.
  *
@@ -463,17 +375,36 @@ do_preferences_load (const SGPropertyNode * arg)
 }
 
 static void
-do_view_next( bool )
+do_view_next(bool do_it)
 {
+  // Only switch view if really requested to do so (and not for example while
+  // reset/reposition where /command/view/next is set to false)
+  if( do_it )
+  {
     globals->get_current_view()->setHeadingOffset_deg(0.0);
     globals->get_viewmgr()->next_view();
+  }
 }
 
 static void
-do_view_prev( bool )
+do_view_prev(bool do_it)
 {
+  if( do_it )
+  {
     globals->get_current_view()->setHeadingOffset_deg(0.0);
     globals->get_viewmgr()->prev_view();
+  }
+}
+
+/**
+ * An fgcommand to toggle fullscreen mode.
+ * No parameters.
+ */
+static bool
+do_toggle_fullscreen(const SGPropertyNode *arg)
+{
+    fgOSFullScreen();
+    return true;
 }
 
 /**
@@ -551,22 +482,45 @@ do_hires_screen_capture (const SGPropertyNode * arg)
 static bool
 do_tile_cache_reload (const SGPropertyNode * arg)
 {
-    static const SGPropertyNode *master_freeze
-       = fgGetNode("/sim/freeze/master");
+    SGPropertyNode *master_freeze = fgGetNode("/sim/freeze/master");
     bool freeze = master_freeze->getBoolValue();
     SG_LOG(SG_INPUT, SG_INFO, "ReIniting TileCache");
     if ( !freeze ) {
-       fgSetBool("/sim/freeze/master", true);
+        master_freeze->setBoolValue(true);
     }
 
     globals->get_subsystem("tile-manager")->reinit();
 
     if ( !freeze ) {
-       fgSetBool("/sim/freeze/master", false);
+        master_freeze->setBoolValue(false);
     }
     return true;
 }
 
+/**
+ * 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(), 
+                                  mpath.str(), 
+                                  globals->get_props());
+   
+   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 
@@ -698,85 +652,6 @@ do_set_dewpoint_degc (const SGPropertyNode * arg)
     return do_set_dewpoint_sea_level_degc(dummy.get_dewpoint_sea_level_degc());
 }
 #endif
-/**
- * Update the lighting manually.
- */
-static bool
-do_timeofday (const SGPropertyNode * arg)
-{
-    const string &offset_type = arg->getStringValue("timeofday", "noon");
-
-    static const SGPropertyNode *longitude
-        = fgGetNode("/position/longitude-deg");
-    static const SGPropertyNode *latitude
-        = fgGetNode("/position/latitude-deg");
-
-    int orig_warp = globals->get_warp();
-    SGTime *t = globals->get_time_params();
-    time_t cur_time = t->get_cur_time();
-    // cout << "cur_time = " << cur_time << endl;
-    // cout << "orig_warp = " << orig_warp << endl;
-
-    int warp = 0;
-    if ( offset_type == "real" ) {
-        warp = -orig_warp;
-    } else if ( offset_type == "dawn" ) {
-        warp = fgTimeSecondsUntilSunAngle( cur_time,
-                                           longitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           latitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           90.0, true ); 
-    } else if ( offset_type == "morning" ) {
-        warp = fgTimeSecondsUntilSunAngle( cur_time,
-                                           longitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           latitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           75.0, true ); 
-    } else if ( offset_type == "noon" ) {
-        warp = fgTimeSecondsUntilSunAngle( cur_time,
-                                           longitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           latitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           0.0, true ); 
-    } else if ( offset_type == "afternoon" ) {
-        warp = fgTimeSecondsUntilSunAngle( cur_time,
-                                           longitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           latitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           60.0, false ); 
-     } else if ( offset_type == "dusk" ) {
-        warp = fgTimeSecondsUntilSunAngle( cur_time,
-                                           longitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           latitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           90.0, false ); 
-     } else if ( offset_type == "evening" ) {
-        warp = fgTimeSecondsUntilSunAngle( cur_time,
-                                           longitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           latitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           100.0, false ); 
-    } else if ( offset_type == "midnight" ) {
-        warp = fgTimeSecondsUntilSunAngle( cur_time,
-                                           longitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           latitude->getDoubleValue()
-                                             * SGD_DEGREES_TO_RADIANS,
-                                           180.0, false ); 
-    }
-    
-
-    fgSetInt("/sim/time/warp", orig_warp + warp);
-    
-    return true;
-}
-
 
 /**
  * Built-in command: toggle a bool property value.
@@ -802,15 +677,18 @@ static bool
 do_property_assign (const SGPropertyNode * arg)
 {
   SGPropertyNode * prop = get_prop(arg);
-  const SGPropertyNode * prop2 = get_prop2(arg);
   const SGPropertyNode * value = arg->getNode("value");
 
   if (value != 0)
       return prop->setUnspecifiedValue(value->getStringValue());
-  else if (prop2)
-      return prop->setUnspecifiedValue(prop2->getStringValue());
   else
-      return false;
+  {
+      const SGPropertyNode * prop2 = get_prop2(arg);
+      if (prop2)
+          return prop->setUnspecifiedValue(prop2->getStringValue());
+      else
+          return false;
+  }
 }
 
 
@@ -965,7 +843,12 @@ static bool
 do_property_cycle (const SGPropertyNode * arg)
 {
     SGPropertyNode * prop = get_prop(arg);
-    vector<SGPropertyNode_ptr> values = arg->getChildren("value");
+    std::vector<SGPropertyNode_ptr> values = arg->getChildren("value");
+    
+    bool wrap = arg->getBoolValue("wrap", true);
+    // compatible with knob/pick animations
+    int offset = arg->getIntValue("offset", 1);
+    
     int selection = -1;
     int nSelections = values.size();
 
@@ -977,15 +860,22 @@ do_property_cycle (const SGPropertyNode * arg)
                                 // Try to find the current selection
     for (int i = 0; i < nSelections; i++) {
         if (compare_values(prop, values[i])) {
-            selection = i + 1;
+            selection = i;
             break;
         }
     }
 
-                                // Default or wrap to the first selection
-    if (selection < 0 || selection >= nSelections)
+    if (selection < 0) { // default to first selection
         selection = 0;
-
+    } else {
+        selection += offset;
+        if (wrap) {
+            selection = (selection + nSelections) % nSelections;
+        } else {
+            SG_CLAMP_RANGE(selection, 0, nSelections - 1);
+        }
+    }
+    
     prop->setUnspecifiedValue(values[selection]->getStringValue());
     return true;
 }
@@ -1008,6 +898,90 @@ do_property_randomize (const SGPropertyNode * arg)
     return true;
 }
 
+/**
+ * Built-in command: interpolate a property value over time
+ *
+ * property:        the name of the property value to interpolate.
+ * type:            the interpolation type ("numeric", "color", etc.)
+ * easing:          name of easing function (see http://easings.net/)
+ * value[0..n]      any number of constant values to interpolate
+ * time/rate[0..n]  time between each value, number of time elements must
+ *                  match those of value elements. Instead of time also rate can
+ *                  be used which automatically calculates the time to change
+ *                  the property value at the given speed.
+ * -or-
+ * property[1..n+1] any number of target values taken from named properties
+ * time/rate[0..n]  time between each value, number of time elements must
+ *                  match those of value elements. Instead of time also rate can
+ *                  be used which automatically calculates the time to change
+ *                  the property value at the given speed.
+ */
+static bool
+do_property_interpolate (const SGPropertyNode * arg)
+{
+  SGPropertyNode * prop = get_prop(arg);
+  if( !prop )
+    return false;
+
+  simgear::PropertyList time_nodes = arg->getChildren("time");
+  simgear::PropertyList rate_nodes = arg->getChildren("rate");
+
+  if( !time_nodes.empty() && !rate_nodes.empty() )
+    // mustn't specify time and rate
+    return false;
+
+  simgear::PropertyList::size_type num_times = time_nodes.empty()
+                                             ? rate_nodes.size()
+                                             : time_nodes.size();
+
+  simgear::PropertyList value_nodes = arg->getChildren("value");
+  if( value_nodes.empty() )
+  {
+    simgear::PropertyList prop_nodes = arg->getChildren("property");
+
+    // must have one more property node
+    if( prop_nodes.size() != num_times + 1 )
+      return false;
+
+    value_nodes.reserve(num_times);
+    for( size_t i = 1; i < prop_nodes.size(); ++i )
+      value_nodes.push_back( fgGetNode(prop_nodes[i]->getStringValue()) );
+  }
+
+  // must match
+  if( value_nodes.size() != num_times )
+    return false;
+
+  double_list deltas;
+  deltas.reserve(num_times);
+
+  if( !time_nodes.empty() )
+  {
+    for( size_t i = 0; i < num_times; ++i )
+      deltas.push_back( time_nodes[i]->getDoubleValue() );
+  }
+  else
+  {
+    for( size_t i = 0; i < num_times; ++i )
+    {
+      // TODO calculate delta based on property type
+      double delta = value_nodes[i]->getDoubleValue()
+                   - ( i > 0
+                     ? value_nodes[i - 1]->getDoubleValue()
+                     : prop->getDoubleValue()
+                     );
+      deltas.push_back( fabs(delta / rate_nodes[i]->getDoubleValue()) );
+    }
+  }
+
+  return prop->interpolate
+  (
+    arg->getStringValue("type", "numeric"),
+    value_nodes,
+    deltas,
+    arg->getStringValue("easing", "linear")
+  );
+}
 
 /**
  * Built-in command: reinit the data logging system based on the
@@ -1032,7 +1006,10 @@ static bool
 do_dialog_new (const SGPropertyNode * arg)
 {
     NewGUI * gui = (NewGUI *)globals->get_subsystem("gui");
-
+    if (!gui) {
+      return false;
+    }
+  
     // Note the casting away of const: this is *real*.  Doing a
     // "dialog-apply" command later on will mutate this property node.
     // I'm not convinced that this isn't the Right Thing though; it
@@ -1094,6 +1071,20 @@ do_dialog_update (const SGPropertyNode * arg)
     }
 }
 
+static bool
+do_open_browser (const SGPropertyNode * arg)
+{
+    string path;
+    if (arg->hasValue("path"))
+        path = arg->getStringValue("path");
+    else
+    if (arg->hasValue("url"))
+        path = arg->getStringValue("url");
+    else
+        return false;
+
+    return openBrowser(path);
+}
 
 /**
  * Apply a value in the active XML-configured dialog.
@@ -1140,14 +1131,9 @@ static bool
 do_add_model (const SGPropertyNode * arg)
 {
     SGPropertyNode * model = fgGetNode("models", true);
-    for (int i = 0;; i++) {
-        if (i < 0)
-            return false;
-        if (!model->getChild("model", i, false)) {
-            model = model->getChild("model", i, true);
-            break;
-        }
-    }
+    int i;
+    for (i = 0; model->hasChild("model",i); i++);
+    model = model->getChild("model", i, true);
     copyProperties(arg, model);
     if (model->hasValue("elevation-m"))
         model->setDoubleValue("elevation-ft", model->getDoubleValue("elevation-m")
@@ -1158,32 +1144,6 @@ do_add_model (const SGPropertyNode * arg)
     return true;
 }
 
-
-/**
- * Set mouse cursor coordinates and cursor shape.
- */
-static bool
-do_set_cursor (const SGPropertyNode * arg)
-{
-    if (arg->hasValue("x") || arg->hasValue("y")) {
-        SGPropertyNode *mx = fgGetNode("/devices/status/mice/mouse/x", true);
-        SGPropertyNode *my = fgGetNode("/devices/status/mice/mouse/y", true);
-        int x = arg->getIntValue("x", mx->getIntValue());
-        int y = arg->getIntValue("y", my->getIntValue());
-        fgWarpMouse(x, y);
-        mx->setIntValue(x);
-        my->setIntValue(y);
-    }
-
-    SGPropertyNode *cursor = const_cast<SGPropertyNode *>(arg)->getNode("cursor", true);
-    if (cursor->getType() != simgear::props::NONE)
-        fgSetMouseCursor(cursor->getIntValue());
-
-    cursor->setIntValue(fgGetMouseCursor());
-    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
@@ -1193,16 +1153,22 @@ do_set_cursor (const SGPropertyNode * arg)
 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;
+        FGSampleQueue *queue = globals->get_chatter_queue();
         if ( !queue ) {
-           SGSoundMgr *smgr = globals->get_soundmgr();
-           queue = new FGSampleQueue(smgr, "chatter");
-           queue->tie_to_listener();
+            queue = new FGSampleQueue(smgr, "chatter");
+            queue->tie_to_listener();
+            globals->set_chatter_queue(queue);
         }
 
         SGSoundSample *msg = new SGSoundSample(file.c_str(), path);
@@ -1230,7 +1196,7 @@ do_presets_commit (const SGPropertyNode * arg)
       // Nasal can trigger this during initial init, which confuses
       // the logic in ReInitSubsystems, since initial state has not been
       // saved at that time. Short-circuit everything here.
-      fgInitPosition();
+      flightgear::initPosition();
     }
     
     return true;
@@ -1247,24 +1213,6 @@ do_log_level (const SGPropertyNode * arg)
    return true;
 }
 
-/**
- * Built-in command: replay the FDR buffer
- */
-static bool
-do_replay (const SGPropertyNode * arg)
-{
-    // freeze the fdm, resume from sim pause 
-    fgSetInt( "/sim/freeze/replay-state", 1 );
-    fgSetBool("/sim/freeze/master", 0 );
-    fgSetBool("/sim/freeze/clock", 0 );
-    fgSetDouble( "/sim/replay/time", -1 );
-
-    // cout << "start = " << r->get_start_time()
-    //      << "  end = " << r->get_end_time() << endl;
-
-    return true;
-}
-
 /*
 static bool
 do_decrease_visibility (const SGPropertyNode * arg)
@@ -1301,11 +1249,28 @@ do_load_xml_to_proptree(const SGPropertyNode * arg)
 
     if (file.extension() != "xml")
         file.concat(".xml");
-
-    if (file.isRelative()) {
-      file = globals->resolve_maybe_aircraft_path(file.str());
+    
+    std::string icao = arg->getStringValue("icao");
+    if (icao.empty()) {
+        if (file.isRelative()) {
+          SGPath absPath = globals->resolve_maybe_aircraft_path(file.str());
+          if (!absPath.isNull())
+              file = absPath;
+          else
+          {
+              SG_LOG(SG_IO, SG_ALERT, "loadxml: Cannot find XML property file '"  
+                          << file.str() << "'.");
+              return false;
+          }
+        }
+    } else {
+        if (!XMLLoader::findAirportData(icao, file.str(), file)) {
+          SG_LOG(SG_IO, SG_INFO, "loadxml: failed to find airport data for "
+            << file.str() << " at ICAO:" << icao);
+          return false;
+        }
     }
-
+    
     if (!fgValidatePath(file.c_str(), false)) {
         SG_LOG(SG_IO, SG_ALERT, "loadxml: reading '" << file.str() << "' denied "
                 "(unauthorized access)");
@@ -1328,6 +1293,106 @@ do_load_xml_to_proptree(const SGPropertyNode * arg)
     return true;
 }
 
+class RemoteXMLRequest:
+  public simgear::HTTP::MemoryRequest
+{
+public:
+    SGPropertyNode_ptr _complete;
+    SGPropertyNode_ptr _status;
+    SGPropertyNode_ptr _failed;
+    SGPropertyNode_ptr _target;
+
+    RemoteXMLRequest(const std::string& url, SGPropertyNode* targetNode) :
+      simgear::HTTP::MemoryRequest(url),
+      _target(targetNode)
+    {
+    }
+    
+    void setCompletionProp(SGPropertyNode_ptr p)
+    {
+        _complete = p;
+    }
+    
+    void setStatusProp(SGPropertyNode_ptr p)
+    {
+        _status = p;
+    }
+    
+    void setFailedProp(SGPropertyNode_ptr p)
+    {
+        _failed = p;
+    }
+    
+protected:
+    
+    virtual void onFail()
+    {
+        SG_LOG(SG_IO, SG_INFO, "network level failure in RemoteXMLRequest");
+        if (_failed) {
+            _failed->setBoolValue(true);
+        }
+    }
+    
+    virtual void onDone()
+    {
+        int response = responseCode();
+        bool failed = false;
+        if (response == 200) {
+            try {
+                const char* buffer = responseBody().c_str();
+                readProperties(buffer, responseBody().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)
+{
+    FGHTTPClient* http = static_cast<FGHTTPClient*>(globals->get_subsystem("http"));
+    if (!http) {
+        SG_LOG(SG_IO, SG_ALERT, "xmlhttprequest: HTTP client not running");
+        return false;
+    }
+  
+    std::string url(arg->getStringValue("url"));
+    if (url.empty())
+        return false;
+        
+    SGPropertyNode *targetnode;
+    if (arg->hasValue("targetnode"))
+        targetnode = fgGetNode(arg->getStringValue("targetnode"), true);
+    else
+        targetnode = const_cast<SGPropertyNode *>(arg)->getNode("data", true);
+    
+    RemoteXMLRequest* req = new RemoteXMLRequest(url, targetnode);
+    
+    if (arg->hasChild("body"))
+        req->setBodyData(arg->getChild("body"));
+    
+// connect up optional reporting properties
+    if (arg->hasValue("complete")) 
+        req->setCompletionProp(fgGetNode(arg->getStringValue("complete"), true));
+    if (arg->hasValue("failure")) 
+        req->setFailedProp(fgGetNode(arg->getStringValue("failure"), true));
+    if (arg->hasValue("status")) 
+        req->setStatusProp(fgGetNode(arg->getStringValue("status"), true));
+        
+    http->makeRequest(req);
+    return true;
+}
+
 
 /**
  * An fgcommand to allow saving of xml files via nasal,
@@ -1419,6 +1484,47 @@ do_release_cockpit_button (const SGPropertyNode *arg)
   return true;
 }
 
+// Optional profiling commands using gperftools:
+// http://code.google.com/p/gperftools/
+
+#if !FG_HAVE_GPERFTOOLS
+static void
+no_profiling_support()
+{
+  SG_LOG
+  (
+    SG_GENERAL,
+    SG_WARN,
+    "No profiling support! Install gperftools and reconfigure/rebuild fgfs."
+  );
+}
+#endif
+
+static bool
+do_profiler_start(const SGPropertyNode *arg)
+{
+#if FG_HAVE_GPERFTOOLS
+  const char *filename = arg->getStringValue("filename", "fgfs.profile");
+  ProfilerStart(filename);
+  return true;
+#else
+  no_profiling_support();
+  return false;
+#endif
+}
+
+static bool
+do_profiler_stop(const SGPropertyNode *arg)
+{
+#if FG_HAVE_GPERFTOOLS
+  ProfilerStop();
+  return true;
+#else
+  no_profiling_support();
+  return false;
+#endif
+}
+
 
 ////////////////////////////////////////////////////////////////////////
 // Command setup.
@@ -1439,15 +1545,14 @@ static struct {
     { "nasal", do_nasal },
     { "exit", do_exit },
     { "reset", do_reset },
-    { "reinit", do_reinit },
-    { "suspend", do_reinit },
-    { "resume", do_reinit },
     { "pause", do_pause },
     { "load", do_load },
     { "save", do_save },
+    { "save-tape", do_save_tape },
+    { "load-tape", do_load_tape },
     { "panel-load", do_panel_load },
-    { "panel-mouse-click", do_panel_mouse_click },
     { "preferences-load", do_preferences_load },
+    { "toggle-fullscreen", do_toggle_fullscreen },
     { "view-cycle", do_view_cycle },
     { "screen-capture", do_screen_capture },
     { "hires-screen-capture", do_hires_screen_capture },
@@ -1458,7 +1563,6 @@ static struct {
     { "set-dewpoint-sea-level-air-temp-degc", do_set_dewpoint_sea_level_degc },
     { "set-dewpoint-temp-degc", do_set_dewpoint_degc },
     */
-    { "timeofday", do_timeofday },
     { "property-toggle", do_property_toggle },
     { "property-assign", do_property_assign },
     { "property-adjust", do_property_adjust },
@@ -1467,15 +1571,16 @@ static struct {
     { "property-scale", do_property_scale },
     { "property-cycle", do_property_cycle },
     { "property-randomize", do_property_randomize },
+    { "property-interpolate", do_property_interpolate },
     { "data-logging-commit", do_data_logging_commit },
     { "dialog-new", do_dialog_new },
     { "dialog-show", do_dialog_show },
     { "dialog-close", do_dialog_close },
     { "dialog-update", do_dialog_update },
     { "dialog-apply", do_dialog_apply },
+    { "open-browser", do_open_browser },
     { "gui-redraw", do_gui_redraw },
     { "add-model", do_add_model },
-    { "set-cursor", do_set_cursor },
     { "play-audio-sample", do_play_audio_sample },
     { "presets-commit", do_presets_commit },
     { "log-level", do_log_level },
@@ -1486,12 +1591,18 @@ static struct {
     */
     { "loadxml", do_load_xml_to_proptree},
     { "savexml", do_save_xml_from_proptree },
+    { "xmlhttprequest", do_load_xml_from_url },
     { "press-cockpit-button", do_press_cockpit_button },
     { "release-cockpit-button", do_release_cockpit_button },
     { "dump-scenegraph", do_dump_scene_graph },
     { "dump-terrainbranch", do_dump_terrain_branch },
     { "print-visible-scene", do_print_visible_scene_info },
     { "reload-shaders", do_reload_shaders },
+    { "reload-materials", do_materials_reload },
+
+    { "profiler-start", do_profiler_start },
+    { "profiler-stop",  do_profiler_stop },
+
     { 0, 0 }                   // zero-terminated
 };
 
@@ -1514,6 +1625,9 @@ fgInitCommands ()
   typedef bool (*dummy)();
   fgTie( "/command/view/next", dummy(0), do_view_next );
   fgTie( "/command/view/prev", dummy(0), do_view_prev );
+
+  globals->get_props()->setValueReadOnly( "/sim/debug/profiler-available",
+                                          bool(FG_HAVE_GPERFTOOLS) );
 }
 
 // end of fg_commands.cxx