#include <simgear/compiler.h>
-#include STL_STRING
-#include STL_FSTREAM
+#include <string>
+#include <fstream>
#include <simgear/sg_inlines.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/math/sg_random.h>
+#include <simgear/scene/material/mat.hxx>
+#include <simgear/scene/material/matlib.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/structure/commands.hxx>
#include <simgear/props/props.hxx>
+#include <simgear/structure/event_mgr.hxx>
+#include <simgear/sound/soundmgr_openal.hxx>
#include <Cockpit/panel.hxx>
#include <Cockpit/panel_io.hxx>
#include <GUI/dialog.hxx>
#include <Aircraft/replay.hxx>
#include <Scenery/tilemgr.hxx>
-#if defined(HAVE_PLIB_PSL)
-# include <Scripting/scriptmgr.hxx>
-#endif
+#include <Scenery/scenery.hxx>
#include <Scripting/NasalSys.hxx>
-#include <Sound/fg_fx.hxx>
+#include <Sound/sample_queue.hxx>
#include <Time/sunsolver.hxx>
#include <Time/tmp.hxx>
#include "fg_init.hxx"
#include "fg_io.hxx"
+#include "fg_os.hxx"
#include "fg_commands.hxx"
#include "fg_props.hxx"
#include "globals.hxx"
#include "util.hxx"
#include "viewmgr.hxx"
#include "main.hxx"
+#include <Main/viewer.hxx>
-SG_USING_STD(string);
-SG_USING_STD(ifstream);
-SG_USING_STD(ofstream);
+using std::string;
+using std::ifstream;
+using std::ofstream;
\f
compare_values (SGPropertyNode * value1, SGPropertyNode * value2)
{
switch (value1->getType()) {
- case SGPropertyNode::BOOL:
+ case simgear::props::BOOL:
return (value1->getBoolValue() == value2->getBoolValue());
- case SGPropertyNode::INT:
+ case simgear::props::INT:
return (value1->getIntValue() == value2->getIntValue());
- case SGPropertyNode::LONG:
+ case simgear::props::LONG:
return (value1->getLongValue() == value2->getLongValue());
- case SGPropertyNode::FLOAT:
+ case simgear::props::FLOAT:
return (value1->getFloatValue() == value2->getFloatValue());
- case SGPropertyNode::DOUBLE:
+ case simgear::props::DOUBLE:
return (value1->getDoubleValue() == value2->getDoubleValue());
default:
return !strcmp(value1->getStringValue(), value2->getStringValue());
return true;
}
-#if defined(HAVE_PLIB_PSL)
-/**
- * Built-in command: run a PSL script.
- *
- * script: the PSL script to execute
- */
-static bool
-do_script (const SGPropertyNode * arg)
-{
- FGScriptMgr * mgr = (FGScriptMgr *)globals->get_subsystem("scripting");
- return mgr->run(arg->getStringValue("script"));
-}
-#endif // HAVE_PLIB_PSL
-
/**
* Built-in command: run a Nasal script.
*/
fgSetBool("/sim/signals/exit", true);
if (fgGetBool("/sim/startup/save-on-exit")) {
-#ifdef _MSC_VER
+#ifdef _WIN32
char* envp = ::getenv( "APPDATA" );
if ( envp != NULL ) {
SGPath config( envp );
#endif
config.append( "autosave.xml" );
config.create_dir( 0700 );
- SG_LOG(SG_IO, SG_INFO, "Saving user settings to autosave.xml");
+ 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_BULK, "Finished Saving user settings");
+ SG_LOG(SG_INPUT, SG_DEBUG, "Finished Saving user settings");
}
}
fgExit(arg->getIntValue("status", 0));
}
+/**
+ * Reset FlightGear (Shift-Escape or Menu->File->Reset)
+ */
+static bool
+do_reset (const SGPropertyNode * arg)
+{
+ reInit();
+ return true;
+}
+
+
/**
* Built-in command: reinitialize one or more subsystems.
*
static bool
do_load (const SGPropertyNode * arg)
{
- const string &file = arg->getStringValue("file", "fgfs.sav");
- ifstream input(file.c_str());
- if (input.good() && fgLoadFlight(input)) {
- input.close();
- SG_LOG(SG_INPUT, SG_INFO, "Restored flight from " << file);
- return true;
- } else {
- SG_LOG(SG_INPUT, SG_ALERT, "Cannot load flight from " << file);
- return false;
- }
+ string file = arg->getStringValue("file", "fgfs.sav");
+ if (file.size() < 4 || file.substr(file.size() - 4) != ".sav")
+ file += ".sav";
+
+ if (!fgValidatePath(file.c_str(), false)) {
+ SG_LOG(SG_IO, SG_ALERT, "load: reading '" << file << "' denied "
+ "(unauthorized access)");
+ return false;
+ }
+
+ ifstream input(file.c_str());
+ if (input.good() && fgLoadFlight(input)) {
+ input.close();
+ SG_LOG(SG_INPUT, SG_INFO, "Restored flight from " << file);
+ return true;
+ } else {
+ SG_LOG(SG_INPUT, SG_WARN, "Cannot load flight from " << file);
+ return false;
+ }
}
static bool
do_save (const SGPropertyNode * arg)
{
- const string &file = arg->getStringValue("file", "fgfs.sav");
- bool write_all = arg->getBoolValue("write-all", false);
- SG_LOG(SG_INPUT, SG_INFO, "Saving flight");
- ofstream output(file.c_str());
- if (output.good() && fgSaveFlight(output, write_all)) {
- output.close();
- SG_LOG(SG_INPUT, SG_INFO, "Saved flight to " << file);
- return true;
- } else {
- SG_LOG(SG_INPUT, SG_ALERT, "Cannot save flight to " << file);
- return false;
- }
+ string file = arg->getStringValue("file", "fgfs.sav");
+ if (file.size() < 4 || file.substr(file.size() - 4) != ".sav")
+ file += ".sav";
+
+ if (!fgValidatePath(file.c_str(), false)) {
+ 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());
+ if (output.good() && fgSaveFlight(output, write_all)) {
+ output.close();
+ SG_LOG(SG_INPUT, SG_INFO, "Saved flight to " << file);
+ return true;
+ } else {
+ SG_LOG(SG_INPUT, SG_ALERT, "Cannot save flight to " << file);
+ return false;
+ }
}
globals->get_current_view()->setHeadingOffset_deg(0.0);
globals->get_viewmgr()->next_view();
fix_hud_visibility();
- globals->get_tile_mgr()->refresh_view_timestamps();
}
static void
globals->get_current_view()->setHeadingOffset_deg(0.0);
globals->get_viewmgr()->prev_view();
fix_hud_visibility();
- globals->get_tile_mgr()->refresh_view_timestamps();
}
/**
globals->get_current_view()->setHeadingOffset_deg(0.0);
globals->get_viewmgr()->next_view();
fix_hud_visibility();
- globals->get_tile_mgr()->refresh_view_timestamps();
-// fgReshape(fgGetInt("/sim/startup/xsize"), fgGetInt("/sim/startup/ysize"));
return true;
}
static bool
do_screen_capture (const SGPropertyNode * arg)
{
- fgDumpSnapShot();
- return true;
+ return fgDumpSnapShot();
+}
+
+static bool
+do_reload_shaders (const SGPropertyNode*)
+{
+ simgear::reload_shaders();
+ return true;
}
+static bool
+do_dump_scene_graph (const SGPropertyNode*)
+{
+ fgDumpSceneGraph();
+ return true;
+}
+
+static bool
+do_dump_terrain_branch (const SGPropertyNode*)
+{
+ fgDumpTerrainBranch();
+
+ double lon_deg = fgGetDouble("/position/longitude-deg");
+ double lat_deg = fgGetDouble("/position/latitude-deg");
+ SGGeod geodPos = SGGeod::fromDegFt(lon_deg, lat_deg, 0.0);
+ SGVec3d zero = SGVec3d::fromGeod(geodPos);
+
+ SG_LOG(SG_INPUT, SG_INFO, "Model parameters:");
+ SG_LOG(SG_INPUT, SG_INFO, "Center: " << zero.x() << ", " << zero.y() << ", " << zero.z() );
+ SG_LOG(SG_INPUT, SG_INFO, "Rotation: " << lat_deg << ", " << lon_deg );
+
+ return true;
+}
/**
* Built-in command: hires capture screen.
if ( !freeze ) {
fgSetBool("/sim/freeze/master", true);
}
- // BusyCursor(0);
if ( globals->get_tile_mgr()->init() ) {
// Load the local scenery data
double visibility_meters = fgGetDouble("/environment/visibility-m");
"Error in Tile Manager initialization!" );
exit(-1);
}
- // BusyCursor(1);
if ( !freeze ) {
fgSetBool("/sim/freeze/master", false);
}
do_dialog_update (const SGPropertyNode * arg)
{
NewGUI * gui = (NewGUI *)globals->get_subsystem("gui");
- FGDialog * dialog = gui->getActiveDialog();
+ FGDialog * dialog;
+ if (arg->hasValue("dialog-name"))
+ dialog = gui->getDialog(arg->getStringValue("dialog-name"));
+ else
+ dialog = gui->getActiveDialog();
+
if (dialog != 0) {
- if (arg->hasValue("object-name")) {
- dialog->updateValue(arg->getStringValue("object-name"));
- } else {
- dialog->updateValues();
- }
+ dialog->updateValues(arg->getStringValue("object-name"));
return true;
} else {
return false;
do_dialog_apply (const SGPropertyNode * arg)
{
NewGUI * gui = (NewGUI *)globals->get_subsystem("gui");
- FGDialog * dialog = gui->getActiveDialog();
+ FGDialog * dialog;
+ if (arg->hasValue("dialog-name"))
+ dialog = gui->getDialog(arg->getStringValue("dialog-name"));
+ else
+ dialog = gui->getActiveDialog();
+
if (dialog != 0) {
- if (arg->hasValue("object-name")) {
- const char * name = arg->getStringValue("object-name");
- dialog->applyValue(name);
- dialog->updateValue(name);
- } else {
- dialog->applyValues();
- dialog->updateValues();
- }
+ dialog->applyValues(arg->getStringValue("object-name"));
return true;
} else {
return false;
return true;
}
+
+/**
+ * Adds model to the scenery. The path to the added branch (/models/model[*])
+ * is returned in property "property".
+ */
+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;
+ }
+ }
+ copyProperties(arg, model);
+ if (model->hasValue("elevation-m"))
+ model->setDoubleValue("elevation-ft", model->getDoubleValue("elevation-m")
+ * SG_METER_TO_FEET);
+ model->getNode("load", true);
+ model->removeChildren("load");
+ const_cast<SGPropertyNode *>(arg)->setStringValue("property", model->getPath());
+ 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
* overlap.
*/
static bool
-do_play_audio_message (const SGPropertyNode * arg)
+do_play_audio_sample (const SGPropertyNode * arg)
{
- FGFX *fx = (FGFX *)globals->get_subsystem("fx");
string path = arg->getStringValue("path");
string file = arg->getStringValue("file");
+ float volume = arg->getFloatValue("volume");
// cout << "playing " << path << " / " << file << endl;
- fx->play_message( path, file );
+ try {
+ static FGSampleQueue *queue = 0;
+ if ( !queue ) {
+ SGSoundMgr *smgr = globals->get_soundmgr();
+ queue = new FGSampleQueue(smgr, "chatter");
+ queue->tie_to_listener();
+ }
- return true;
+ SGSoundSample *msg = new SGSoundSample(path.c_str(), file.c_str());
+ 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;
+ }
}
/**
// don't get lost when we subsequently delete this fdm
// and create a new one.
cur_fdm_state->unbind();
-
+
// set position from presets
fgInitPosition();
- // BusyCursor(0);
fgReInitSubsystems();
globals->get_tile_mgr()->update( fgGetDouble("/environment/visibility-m") );
}
-
static bool
do_decrease_visibility (const SGPropertyNode * arg)
{
return true;
}
-static bool
-do_hud_brightkey(const SGPropertyNode *)
-{
- HUD_brightkey( true );
- return true;
-}
-
-static bool
-do_hud_masterswitch(const SGPropertyNode *)
-{
- HUD_masterswitch( true );
- return true;
-}
-
static bool
do_hud_init(const SGPropertyNode *)
{
return true;
}
+
/**
* An fgcommand to allow loading of xml files via nasal,
* the xml file's structure will be made available within
- * a (definable) property tree node
+ * a property tree node defined under argument "targetnode",
+ * or in the given argument tree under "data" otherwise.
*
- * @param filename a string to hold the complete path & filename of a XML file
+ * @param filename a string to hold the complete path & filename of an XML file
* @param targetnode a string pointing to a location within the property tree
- * where to store the parsed XML file
+ * where to store the parsed XML file. If <targetnode> is undefined, then the
+ * file contents are stored under a node <data> in the argument tree.
*/
-static bool
-do_load_xml_to_proptree(const SGPropertyNode * node)
+static bool
+do_load_xml_to_proptree(const SGPropertyNode * arg)
{
- // SG_LOG(SG_GENERAL, SG_ALERT, "fgcommand loadxml executed");
+ SGPath file(arg->getStringValue("filename"));
+ if (file.str().empty())
+ return false;
+
+ if (file.extension() != "xml")
+ file.concat(".xml");
+
+ if (!fgValidatePath(file.c_str(), false)) {
+ SG_LOG(SG_IO, SG_ALERT, "loadxml: reading '" << file.str() << "' denied "
+ "(unauthorized access)");
+ return false;
+ }
+
+ SGPropertyNode *targetnode;
+ if (arg->hasValue("targetnode"))
+ targetnode = fgGetNode(arg->getStringValue("targetnode"), true);
+ else
+ targetnode = const_cast<SGPropertyNode *>(arg)->getNode("data", true);
- SGPropertyNode * targetnode;
- targetnode = fgGetNode(node->getNode("targetnode")->getStringValue(),true);
-
- const char *filename = node->getNode("filename")->getStringValue();
try {
- fgLoadProps(filename, targetnode);
+ readProperties(file.c_str(), targetnode, true);
} catch (const sg_exception &e) {
- string errmsg = "Error reading file " + string(filename) + ":\n";
- guiErrorMessage(errmsg.c_str(), e);
+ SG_LOG(SG_IO, SG_WARN, "loadxml: " << e.getFormattedMessage());
return false;
}
- return true;
+ return true;
}
/**
- * an fgcommand to allow saving of xml files via nasal,
+ * An fgcommand to allow saving of xml files via nasal,
* the file's structure will be determined based on what's
* encountered in the passed (source) property tree node
*
* XML file
* @param sourcenode a string pointing to a location within the property tree
* where to find the nodes that should be written recursively into an XML file
- *
- * TODO:
- * deal with already existing filenames, optionally return error/success
- * values in a separate node to provide status information
- *
- * note: it's directly using writeProperties, which is not necessarily
- * preferable, but for now it should work ...
+ * @param data if no sourcenode is given, then the file contents are taken from
+ * the argument tree's "data" node.
*/
-static bool
-do_save_xml_from_proptree(const SGPropertyNode * node)
+static bool
+do_save_xml_from_proptree(const SGPropertyNode * arg)
{
- //TODO: do Parameter validation !
- SGPropertyNode * sourcenode;
- sourcenode = fgGetNode(node->getNode("sourcenode")->getStringValue(),true);
+ SGPath file(arg->getStringValue("filename"));
+ if (file.str().empty())
+ return false;
+
+ if (file.extension() != "xml")
+ file.concat(".xml");
+
+ if (!fgValidatePath(file.c_str(), true)) {
+ SG_LOG(SG_IO, SG_ALERT, "savexml: writing to '" << file.str() << "' denied "
+ "(unauthorized access)");
+ return false;
+ }
+
+ SGPropertyNode *sourcenode;
+ if (arg->hasValue("sourcenode"))
+ sourcenode = fgGetNode(arg->getStringValue("sourcenode"), true);
+ else if (arg->getNode("data", false))
+ sourcenode = const_cast<SGPropertyNode *>(arg)->getNode("data");
+ else
+ return false;
- const char *filename = node->getNode("filename")->getStringValue();
try {
- writeProperties (filename, sourcenode, true);
+ writeProperties (file.c_str(), sourcenode, true);
} catch (const sg_exception &e) {
- string errmsg = "Error writing file " + string(filename) + ":\n";
- guiErrorMessage(errmsg.c_str(), e);
+ SG_LOG(SG_IO, SG_WARN, "savexml: " << e.getFormattedMessage());
return false;
}
return true;
}
+static bool
+do_press_cockpit_button (const SGPropertyNode *arg)
+{
+ const char *prefix = arg->getStringValue("prefix");
+
+ if (arg->getBoolValue("guarded") && fgGetDouble((string(prefix) + "-guard").c_str()) < 1)
+ return true;
+
+ string prop = string(prefix) + "-button";
+ double value;
+
+ if (arg->getBoolValue("latching"))
+ value = fgGetDouble(prop.c_str()) > 0 ? 0 : 1;
+ else
+ value = 1;
+
+ fgSetDouble(prop.c_str(), value);
+ fgSetBool(arg->getStringValue("discrete"), value > 0);
+
+ return true;
+}
+
+static bool
+do_release_cockpit_button (const SGPropertyNode *arg)
+{
+ const char *prefix = arg->getStringValue("prefix");
+
+ if (arg->getBoolValue("guarded")) {
+ string prop = string(prefix) + "-guard";
+ if (fgGetDouble(prop.c_str()) < 1) {
+ fgSetDouble(prop.c_str(), 1);
+ return true;
+ }
+ }
+
+ if (! arg->getBoolValue("latching")) {
+ fgSetDouble((string(prefix) + "-button").c_str(), 0);
+ fgSetBool(arg->getStringValue("discrete"), false);
+ }
+
+ return true;
+}
+
////////////////////////////////////////////////////////////////////////
// Command setup.
SGCommandMgr::command_t command;
} built_ins [] = {
{ "null", do_null },
-#if defined(HAVE_PLIB_PSL)
- { "script", do_script },
-#endif // HAVE_PLIB_PSL
{ "nasal", do_nasal },
{ "exit", do_exit },
+ { "reset", do_reset },
{ "reinit", do_reinit },
{ "suspend", do_reinit },
{ "resume", do_reinit },
{ "dialog-update", do_dialog_update },
{ "dialog-apply", do_dialog_apply },
{ "gui-redraw", do_gui_redraw },
- { "play-audio-message", do_play_audio_message },
+ { "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 },
{ "replay", do_replay },
{ "decrease-visibility", do_decrease_visibility },
{ "increase-visibility", do_increase_visibility },
- { "hud-brightkey", do_hud_brightkey },
- { "hud-masterswitch", do_hud_masterswitch },
{ "hud-init", do_hud_init },
{ "hud-init2", do_hud_init2 },
{ "loadxml", do_load_xml_to_proptree},
- { "savexml", do_save_xml_from_proptree },
+ { "savexml", do_save_xml_from_proptree },
+ { "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 },
+ { "reload-shaders", do_reload_shaders },
{ 0, 0 } // zero-terminated
};
void
fgInitCommands ()
{
- SG_LOG(SG_GENERAL, SG_INFO, "Initializing basic built-in commands:");
+ SG_LOG(SG_GENERAL, SG_BULK, "Initializing basic built-in commands:");
for (int i = 0; built_ins[i].name != 0; i++) {
- SG_LOG(SG_GENERAL, SG_INFO, " " << built_ins[i].name);
+ SG_LOG(SG_GENERAL, SG_BULK, " " << built_ins[i].name);
globals->get_commands()->addCommand(built_ins[i].name,
built_ins[i].command);
}