diff --git a/examples/worlds/camera_sensor.sdf b/examples/worlds/camera_sensor.sdf
index 3d967d701e..0cee711b47 100644
--- a/examples/worlds/camera_sensor.sdf
+++ b/examples/worlds/camera_sensor.sdf
@@ -8,23 +8,11 @@
0.001
1.0
-
-
ogre2
-
-
-
-
1.0 1.0 1.0
@@ -32,103 +20,22 @@
true
+
+ true
+
-
3D View
false
docked
-
ogre2
scene
0.4 0.4 0.4
0.8 0.8 0.8
- -6 0 6 0 0.5 0
-
-
-
-
-
- floating
- 5
- 5
- false
-
-
-
-
- false
- 5
- 5
- floating
- false
-
-
-
-
- false
- 5
- 5
- floating
- false
-
-
-
-
- false
- 5
- 5
- floating
- false
-
-
-
-
-
- World control
- false
- false
- 72
- 1
-
- floating
-
-
-
-
-
-
- true
- true
- true
- true
-
-
-
-
-
-
- World stats
- false
- false
- 110
- 290
- 1
-
- floating
-
-
-
-
-
-
- true
- true
- true
- true
+ -3 0 3 0 0.5 0
@@ -137,20 +44,6 @@
camera
-
-
-
-
- docked
-
-
-
-
-
-
- docked
-
-
diff --git a/examples/worlds/contact_sensor.sdf b/examples/worlds/contact_sensor.sdf
index c37f7f259b..0714c34bf7 100644
--- a/examples/worlds/contact_sensor.sdf
+++ b/examples/worlds/contact_sensor.sdf
@@ -9,22 +9,7 @@ Run the following to print out contacts,
-->
-
-
-
-
-
-
-
-
+
false
diff --git a/examples/worlds/mimic_fast_slow_pendulums_world.sdf b/examples/worlds/mimic_fast_slow_pendulums_world.sdf
index b42c8bc73a..7386bd3dac 100644
--- a/examples/worlds/mimic_fast_slow_pendulums_world.sdf
+++ b/examples/worlds/mimic_fast_slow_pendulums_world.sdf
@@ -16,6 +16,10 @@
1
+
+ gz-physics-bullet-featherstone-plugin
+
+
true
0 0 10 0 0 0
diff --git a/examples/worlds/quadcopter.sdf b/examples/worlds/quadcopter.sdf
index 4b00c86c15..1ec3eaa18e 100644
--- a/examples/worlds/quadcopter.sdf
+++ b/examples/worlds/quadcopter.sdf
@@ -17,18 +17,6 @@
0.001
1.0
-
-
-
-
-
-
diff --git a/include/gz/sim/Constants.hh b/include/gz/sim/Constants.hh
new file mode 100644
index 0000000000..96d281ccc7
--- /dev/null
+++ b/include/gz/sim/Constants.hh
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 Open Source Robotics Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GZ_SIM_CONSTANTS_HH_
+#define GZ_SIM_CONSTANTS_HH_
+
+#include "gz/sim/config.hh"
+#include
+
+namespace gz::sim
+{
+// Inline bracket to help doxygen filtering.
+inline namespace GZ_SIM_VERSION_NAMESPACE
+{
+ constexpr std::string_view kPoliciesTag{"gz:policies"};
+}
+} // namespace gz::sim
+
+#endif
diff --git a/src/ServerConfig.cc b/src/ServerConfig.cc
index b800c541aa..4e75a68ea0 100644
--- a/src/ServerConfig.cc
+++ b/src/ServerConfig.cc
@@ -938,7 +938,7 @@ sim::loadPluginInfo(bool _isPlayback)
gzwarn << kServerConfigPathEnv
<< " set but no plugins found\n";
}
- gzdbg << "Loaded (" << ret.size() << ") plugins from file " <<
+ gzdbg << "Loading (" << ret.size() << ") plugins from file " <<
"[" << envConfig << "]\n";
return ret;
@@ -1018,7 +1018,7 @@ sim::loadPluginInfo(bool _isPlayback)
<< "], but no plugins found\n";
}
- gzdbg << "Loaded (" << ret.size() << ") plugins from file " <<
+ gzdbg << "Loading (" << ret.size() << ") plugins from file " <<
"[" << defaultConfig << "]\n";
return ret;
diff --git a/src/Server_TEST.cc b/src/Server_TEST.cc
index f2248cb121..5f7697eeab 100644
--- a/src/Server_TEST.cc
+++ b/src/Server_TEST.cc
@@ -442,8 +442,7 @@ TEST_P(ServerFixture, GZ_UTILS_TEST_DISABLED_ON_WIN32(ServerConfigLogRecord))
EXPECT_EQ(0u, *server.IterationCount());
EXPECT_EQ(3u, *server.EntityCount());
- // Only the log record system is needed and therefore loaded.
- EXPECT_EQ(1u, *server.SystemCount());
+ EXPECT_EQ(4u, *server.SystemCount());
EXPECT_TRUE(serverConfig.LogRecordTopics().empty());
serverConfig.AddLogRecordTopic("test_topic1");
@@ -483,8 +482,7 @@ TEST_P(ServerFixture,
EXPECT_EQ(0u, *server.IterationCount());
EXPECT_EQ(3u, *server.EntityCount());
- // Only the log record system is needed and therefore loaded.
- EXPECT_EQ(1u, *server.SystemCount());
+ EXPECT_EQ(4u, *server.SystemCount());
}
EXPECT_FALSE(common::exists(logFile));
diff --git a/src/SimulationRunner.cc b/src/SimulationRunner.cc
index ceea22ad49..268e956cda 100644
--- a/src/SimulationRunner.cc
+++ b/src/SimulationRunner.cc
@@ -18,6 +18,7 @@
#include "SimulationRunner.hh"
#include
+#include
#ifdef HAVE_PYBIND11
#include
#endif
@@ -36,6 +37,7 @@
#include
#include "gz/common/Profiler.hh"
+#include "gz/sim/Constants.hh"
#include "gz/sim/components/Model.hh"
#include "gz/sim/components/Name.hh"
#include "gz/sim/components/Sensor.hh"
@@ -50,6 +52,7 @@
#include "gz/sim/components/RenderEngineServerHeadless.hh"
#include "gz/sim/components/RenderEngineServerPlugin.hh"
#include "gz/sim/Events.hh"
+#include "gz/sim/ServerConfig.hh"
#include "gz/sim/SdfEntityCreator.hh"
#include "gz/sim/Util.hh"
#include "gz/transport/TopicUtils.hh"
@@ -263,6 +266,18 @@ SimulationRunner::SimulationRunner(const sdf::World &_world,
if (_world.Gui())
{
this->guiMsg = convert(*_world.Gui());
+
+ auto worldElem = this->sdfWorld.Element();
+ if (worldElem)
+ {
+ auto policies = worldElem->FindElement("gz:policies");
+ if (policies)
+ {
+ auto headerData = this->guiMsg.mutable_header()->add_data();
+ headerData->set_key("gz:policies");
+ headerData->add_value(policies->ToString(""));
+ }
+ }
}
std::string infoService{"gui/info"};
@@ -1586,21 +1601,60 @@ void SimulationRunner::CreateEntities(const sdf::World &_world)
// Load any additional plugins from the Server Configuration
this->LoadServerPlugins(this->serverConfig.Plugins());
+ auto loadedWorldPlugins = this->systemMgr->TotalByEntity(worldEntity);
// If we have reached this point and no world systems have been loaded, then
// load a default set of systems.
- if (this->systemMgr->TotalByEntity(worldEntity).empty())
+
+ auto worldElem = this->sdfWorld.Element();
+ bool includeServerConfigPlugins = true;
+ if (worldElem)
{
- gzmsg << "No systems loaded from SDF, loading defaults" << std::endl;
- bool isPlayback = !this->serverConfig.LogPlaybackPath().empty();
- auto plugins = gz::sim::loadPluginInfo(isPlayback);
- this->LoadServerPlugins(plugins);
+ auto policies = worldElem->FindElement(std::string(kPoliciesTag));
+ if (policies)
+ {
+ includeServerConfigPlugins =
+ policies
+ ->Get("include_server_config_plugins", includeServerConfigPlugins)
+ .first;
+ }
}
+ if (includeServerConfigPlugins || loadedWorldPlugins.empty())
+ {
+ bool isPlayback = !this->serverConfig.LogPlaybackPath().empty();
+ auto defaultPlugins = gz::sim::loadPluginInfo(isPlayback);
+ if (loadedWorldPlugins.empty())
+ {
+ gzmsg << "No systems loaded from SDF, loading defaults" << std::endl;
+ }
+ else
+ {
+ std::unordered_set loadedWorldPluginFileNames;
+ for (const auto &pl : loadedWorldPlugins)
+ {
+ loadedWorldPluginFileNames.insert(pl.fname);
+ }
+ auto isPluginLoaded =
+ [&loadedWorldPluginFileNames](const ServerConfig::PluginInfo &_pl)
+ {
+ return loadedWorldPluginFileNames.count(_pl.Plugin().Filename()) != 0;
+ };
+
+ // Remove plugin if it's already loaded so as to not duplicate world
+ // plugins.
+ defaultPlugins.remove_if(isPluginLoaded);
+
+ gzdbg << "Additional plugins to load:\n";
+ for (const auto &plugin : defaultPlugins)
+ {
+ gzdbg << plugin.Plugin().Name() << " " << plugin.Plugin().Filename()
+ << "\n";
+ }
+ }
+
+ this->LoadServerPlugins(defaultPlugins);
+ };
+
// Store the initial state of the ECM;
this->initialEntityCompMgr.CopyFrom(this->entityCompMgr);
-
- // Publish empty GUI messages for worlds that have no GUI in the beginning.
- // In the future, support modifying GUI from the server at runtime.
- if (_world.Gui())
- this->guiMsg = convert(*_world.Gui());
}
diff --git a/src/gui/Gui.cc b/src/gui/Gui.cc
index 035d082299..2d6f4549f1 100644
--- a/src/gui/Gui.cc
+++ b/src/gui/Gui.cc
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
#include
@@ -29,7 +30,10 @@
#include
#include
#include
+#include
+#include
+#include "gz/sim/Constants.hh"
#include "gz/sim/InstallationDirectories.hh"
#include "gz/sim/Util.hh"
#include "gz/sim/config.hh"
@@ -47,6 +51,119 @@ namespace sim
{
// Inline bracket to help doxygen filtering.
inline namespace GZ_SIM_VERSION_NAMESPACE {
+namespace {
+
+std::unique_ptr parseDefaultPlugins(
+ const std::string &_defaultConfig)
+{
+ const auto resolvedDefaultConfigPath =
+ gz::gui::App()->ResolveConfigFile(_defaultConfig);
+ auto pluginsDoc = std::make_unique();
+ if (pluginsDoc->LoadFile(resolvedDefaultConfigPath.c_str()) ==
+ tinyxml2::XML_SUCCESS)
+ {
+ // Remove everything that's not a plugin
+ for (auto elem = pluginsDoc->FirstChildElement(); elem != nullptr;)
+ {
+ if (std::strcmp("plugin", elem->Value()) != 0)
+ {
+ auto tmp = elem;
+ elem = elem->NextSiblingElement();
+ pluginsDoc->DeleteChild(tmp);
+ }
+ else
+ {
+ elem = elem->NextSiblingElement();
+ }
+ }
+ }
+
+ return pluginsDoc;
+}
+
+auto combineUserAndDefaultPlugins(
+ std::unique_ptr _userPlugins,
+ const tinyxml2::XMLDocument &_defaultPlugins, bool _includeDefaultPlugins)
+{
+ if (_includeDefaultPlugins)
+ {
+ auto combinedPlugins = std::make_unique();
+ _defaultPlugins.DeepCopy(combinedPlugins.get());
+
+ std::set processedUserPlugins;
+ for (auto pluginElem = _userPlugins->FirstChildElement("plugin");
+ pluginElem != nullptr;
+ pluginElem = pluginElem->NextSiblingElement("plugin"))
+ {
+ const char *pluginFilename = pluginElem->Attribute("filename");
+
+ bool replacedPlugin{false};
+ for (auto elem = combinedPlugins->FirstChildElement("plugin");
+ elem != nullptr && processedUserPlugins.count(elem) == 0;
+ elem = elem->NextSiblingElement("plugin"))
+ {
+ if (elem->Attribute("filename", pluginFilename))
+ {
+ auto tmp = elem;
+ // Insert the replacement
+ auto clonedPlugin = pluginElem->DeepClone(combinedPlugins.get());
+ elem = combinedPlugins->InsertAfterChild(elem, clonedPlugin)
+ ->ToElement();
+ // Remove the original
+ combinedPlugins->DeleteNode(tmp);
+ replacedPlugin = true;
+ }
+ }
+ if (!replacedPlugin)
+ {
+ auto clonedPlugin = pluginElem->DeepClone(combinedPlugins.get());
+ auto insertedElem = combinedPlugins->InsertEndChild(clonedPlugin);
+ processedUserPlugins.insert(insertedElem );
+ }
+ }
+
+ return combinedPlugins;
+ }
+ return _userPlugins;
+}
+
+/// \brief Various policies that affect the behavior of the GUI
+struct GuiPolicies
+{
+ /// \brief Whether to include default plugins
+ bool includeGuiDefaultPlugins{true};
+
+ /// \brief Parse policies from a GUI message
+ /// \param[in] _msg Input message
+ /// \return A GuiPolicies object populated from parsing the message.
+ static GuiPolicies ParsePolicies(const msgs::GUI &_msg)
+ {
+ GuiPolicies policies;
+ for (const auto &data : _msg.header().data())
+ {
+ if (data.key() == "gz:policies")
+ {
+ tinyxml2::XMLDocument doc;
+ if (data.value_size() > 0)
+ {
+ if (doc.Parse(data.value(0).c_str()) == tinyxml2::XML_SUCCESS)
+ {
+ tinyxml2::XMLHandle handle(doc);
+ auto elem = handle.FirstChildElement(kPoliciesTag.data())
+ .FirstChildElement("include_gui_default_plugins")
+ .ToElement();
+ if (elem)
+ {
+ elem->QueryBoolText(&policies.includeGuiDefaultPlugins);
+ }
+ }
+ }
+ }
+ }
+ return policies;
+ }
+};
+}
namespace gui
{
/// \brief Get the path to the default config file. If the file doesn't exist
@@ -434,6 +551,9 @@ std::unique_ptr createGui(
// Load plugins after creating GuiRunner, so they can access worldName
if (_loadPluginsFromSdf)
{
+ const auto guiPolicies = GuiPolicies::ParsePolicies(res);
+ auto userPlugins = std::make_unique();
+ std::string pluginsXml = "";
for (int p = 0; p < res.plugin_size(); ++p)
{
const auto &plugin = res.plugin(p);
@@ -444,13 +564,13 @@ std::unique_ptr createGui(
if (fileName == "GzScene3D")
{
std::vector extras{"GzSceneManager",
- "InteractiveViewControl",
- "CameraTracking",
- "MarkerManager",
- "SelectEntities",
- "EntityContextMenuPlugin",
- "Spawn",
- "VisualizationCapabilities"};
+ "InteractiveViewControl",
+ "CameraTracking",
+ "MarkerManager",
+ "SelectEntities",
+ "EntityContextMenuPlugin",
+ "Spawn",
+ "VisualizationCapabilities"};
std::string msg{
"The [GzScene3D] GUI plugin has been removed since Garden.\n"
@@ -460,7 +580,7 @@ std::unique_ptr createGui(
for (auto extra : extras)
{
- msg += "* " + extra + "\n";
+ msg += "* " + extra + "\n";
auto newPlugin = res.add_plugin();
newPlugin->set_filename(extra);
@@ -478,15 +598,23 @@ std::unique_ptr createGui(
fileName = "MinimalScene";
}
+ pluginsXml += "" +
+ plugin.innerxml() + "\n";
+ }
+ userPlugins->Parse(pluginsXml.c_str());
- std::string pluginStr = "" +
- plugin.innerxml() + "";
-
- tinyxml2::XMLDocument pluginDoc;
- pluginDoc.Parse(pluginStr.c_str());
+ const auto defaultPlugins = parseDefaultPlugins(defaultConfig);
+ auto pluginsToLoad = combineUserAndDefaultPlugins(
+ std::move(userPlugins), *defaultPlugins,
+ guiPolicies.includeGuiDefaultPlugins);
- app->LoadPlugin(fileName,
- pluginDoc.FirstChildElement("plugin"));
+ gzdbg << "Loading plugins:\n";
+ for (auto pluginElem = pluginsToLoad->FirstChildElement("plugin");
+ pluginElem != nullptr;
+ pluginElem = pluginElem->NextSiblingElement("plugin"))
+ {
+ app->LoadPlugin(pluginElem->Attribute("filename"), pluginElem);
+ gzdbg << pluginElem->Attribute("filename") << "\n";
}
}
}
diff --git a/test/integration/reset_sensors.cc b/test/integration/reset_sensors.cc
index 7b9c43d492..be9c3b6a38 100644
--- a/test/integration/reset_sensors.cc
+++ b/test/integration/reset_sensors.cc
@@ -23,6 +23,7 @@
#include
#include
+#include
#include
#include
@@ -336,6 +337,7 @@ TEST_F(ResetFixture, GZ_UTILS_TEST_DISABLED_ON_MAC(HandleReset))
imageReceiver.msgReceived = false;
server.Run(true, 2000 - server.IterationCount().value(), false);
+ std::this_thread::sleep_for(20ms);
// Check iterator state
EXPECT_EQ(2000u, server.IterationCount().value());
diff --git a/test/test_config.hh.in b/test/test_config.hh.in
index b367ed89de..89118966c9 100644
--- a/test/test_config.hh.in
+++ b/test/test_config.hh.in
@@ -48,6 +48,9 @@ struct TestWorldSansPhysics
static std::string world = std::string(""
""
""
+ ""
+ " false"
+ ""
""
diff --git a/test/worlds/air_pressure.sdf b/test/worlds/air_pressure.sdf
index 0679f9e280..d66cb0fccd 100644
--- a/test/worlds/air_pressure.sdf
+++ b/test/worlds/air_pressure.sdf
@@ -5,6 +5,9 @@
0
+
+ false
+
diff --git a/test/worlds/air_speed.sdf b/test/worlds/air_speed.sdf
index feb3347655..b23d7ee6d5 100644
--- a/test/worlds/air_speed.sdf
+++ b/test/worlds/air_speed.sdf
@@ -5,6 +5,9 @@
0
+
+ false
+
diff --git a/test/worlds/reset_sensors.sdf b/test/worlds/reset_sensors.sdf
index 733658fefc..7f8db14a7e 100644
--- a/test/worlds/reset_sensors.sdf
+++ b/test/worlds/reset_sensors.sdf
@@ -1,6 +1,9 @@
+
+ false
+
diff --git a/tutorials/gui_config.md b/tutorials/gui_config.md
index 9cc42fa1e0..0304f1131a 100644
--- a/tutorials/gui_config.md
+++ b/tutorials/gui_config.md
@@ -16,10 +16,33 @@ There are a few places where the GUI configuration can come from:
3. The default configuration file at `$HOME/.gz/sim/<#>/gui.config` \*,
where `<#>` is Gazebo Sim's major version.
-Each of the items above takes precedence over the ones below it. For example,
-if a user chooses a `--gui-config`, the SDF's `` element is ignored. And
-the default configuration file is only loaded if no configuration is passed
-through the command line or the SDF file.
+If a configuration file is specified using `--gui-config`, Gazebo will
+ignore both the `` element inside the SDF file and the default
+configuration file. Otherwise, Gazebo will load plugins by combining
+plugins in the `` element and the default configuration file.
+How Gazebo combines these plugins is determined by the
+`` policy set in ``:
+
+- `true`: Plugins
+ from the default configuration file merged with plugins from the SDF file.
+ Plugins from SDF files take precedence over plugins from
+ the default configuration file. This means, if a plugin is specified in
+ both places, by default, only the one specified in the SDF file will be
+ loaded. If replacement occurs, the replacement
+ plugin will take the position of the replaced plugin in the order of plugins.
+ If replacement does not occur, the plugin is appended to the end of the list.
+
+ The main use case for this policy is for users to rely on
+ the default list of plugins and only add extra plugins they need for the
+ application. This policy is also useful for overriding the parameters of a small
+ subset of the default plugins. This is the default setting in
+ Gazebo Ionic and later.
+
+- `false`: If
+ there are any plugins specified in the SDF file, plugins from the default
+ configuration file are ignored. This allows the user to have complete
+ control over which plugins are loaded. This is the default setting in
+ Gazebo Harmonic and earlier.
> \* For log-playback, the default file is
> `$HOME/.gz/sim/<#>/playback_gui.config`
@@ -28,10 +51,9 @@ through the command line or the SDF file.
### Default configuration
-Let's try this in practice. First, let's open Gazebo without passing
-any arguments:
+Let's try this in practice. First, let's open the default Gazebo world:
-`gz sim`
+`gz sim default.sdf`
You should see an empty world with several plugins loaded by default, such as the
3D Scene, the play/pause button, etc.
@@ -57,7 +79,7 @@ Let's try customizing it:
3. Reload Gazebo:
- `gz sim`
+ `gz sim default.sdf`
Note how the UI is now in dark mode!
@@ -75,7 +97,7 @@ will be created with default values:
Let's try overriding the default configuration from an SDF file. Open your
favorite editor and save this file as `fuel_preview.sdf`:
-```
+```xml
@@ -84,6 +106,10 @@ favorite editor and save this file as `fuel_preview.sdf`:
name="gz::sim::systems::SceneBroadcaster">
+
+ false
+
+
@@ -137,7 +163,7 @@ Now let's load this world:
`gz sim /fuel_preview.sdf`
-Notice how the application has only one GUI plugin loaded, the 3D scene, as defined
+Notice how the application has only 3 GUI plugins loaded, as defined
on the SDF file above.
@image html files/gui_config/fuel_preview.png
@@ -147,6 +173,75 @@ the same model loaded into the default GUI layout.
@image html files/gui_config/fuel_preview_no_gui.png
+Now, let's change the policy so that default plugins are included
+
+```xml
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+ 3D View
+ false
+ docked
+
+
+ ogre2
+ scene
+ 1.0 1.0 1.0
+ 0.4 0.6 1.0
+ 8.3 7 7.8 0 0.5 -2.4
+
+
+
+ false
+ 5
+ 5
+ floating
+ false
+
+
+
+
+ false
+ 5
+ 5
+ floating
+ false
+
+
+
+
+
+
+ https://fuel.gazebosim.org/1.0/OpenRobotics/models/Sun
+
+
+
+ https://fuel.gazebosim.org/1.0/OpenRobotics/models/Gazebo
+
+
+
+
+```
+
+You will now see the same model loaded in the default GUI layout
+similar to when you deleted the `` element altogether. Note that this will also
+be the behavior if we removed `` tag.
+
+@image html files/gui_config/fuel_preview_no_gui.png
+
### Command line
It's often inconvenient to embed your GUI layout directly into every SDF file.
diff --git a/tutorials/server_config.md b/tutorials/server_config.md
index bbab5f5110..650eafe0c4 100644
--- a/tutorials/server_config.md
+++ b/tutorials/server_config.md
@@ -17,11 +17,26 @@ There are a few places where the plugins can be defined:
3. The default configuration file at `$HOME/.gz/sim/<#>/server.config` \*,
where `<#>` is Gazebo Sim's major version.
-Each of the items above takes precedence over the ones below it. For example,
-if a the SDF file has any `` elements, then the
-`GZ_SIM_SERVER_CONFIG_PATH` variable is ignored. And the default configuration
-file is only loaded if no plugins are passed through the SDF file or the
-environment variable.
+The behavior of Gazebo when loading these plugins depends on the
+`` policy set in ``:
+
+- `true`: Plugins
+ in the SDF file are first loaded, followed by plugins from config files
+ (either `GZ_SIM_SERVER_CONFIG_PATH` or the default configuration file).
+ Plugins from SDF files take precedence over plugins from config files, this
+ means, if a plugin is specified in both places, only the one specified in the
+ SDF file will be loaded. The main use case for this is for users to rely on
+ the default list of plugins and only add extra plugins they need for the
+ application. This is the default setting in Gazebo Ionic and later.
+
+- `false`: If
+ there are any plugins specified in the SDF file, plugins from the config files
+ (either `GZ_SIM_SERVER_CONFIG_PATH` or the default configuration file) are
+ ignored. This allows the user to have complete control over which plugins are
+ loaded. This is the default setting in Gazebo Harmonic and earlier.
+
+In both policy settings, the default configuration file is only loaded if no
+plugins are passed through the `GZ_SIM_SERVER_CONFIG_PATH` environment variable.
> \* For log-playback, the default file is
> `$HOME/.gz/sim/<#>/playback_server.config`
@@ -85,7 +100,7 @@ will be created with default values:
Let's try overriding the default configuration from an SDF file. Open your
favorite editor and save this file as `fuel_preview.sdf`:
-```
+```xml
@@ -147,8 +162,84 @@ Now let's load this world:
`gz sim -r /fuel_preview.sdf`
-Notice how the application has only one system plugin loaded, the scene
-broadcaster, as defined on the SDF file above. Physics is not loaded, so even
+Notice how the application has loaded the scene
+broadcaster, as defined on the SDF file above as well as the default plugins
+`Physics` and `UserCommands`. Since `SceneBroadcaster` is loaded from the SDF file,
+it's not loaded again. We see that the cone falls due to gravity since all the
+necessary plugins are loaded.
+
+@image html files/server_config/from_sdf_no_plugins.gif
+
+Now, let's modify the SDF file to change the policy `false`
+
+```xml
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+ 3D View
+ false
+ docked
+
+
+ ogre2
+ scene
+ 1.0 1.0 1.0
+ 0.4 0.6 1.0
+ 8.3 7 7.8 0 0.5 -2.4
+
+
+
+ false
+ 5
+ 5
+ floating
+ false
+
+
+
+
+ false
+ 5
+ 5
+ floating
+ false
+
+
+
+
+
+
+ https://fuel.gazebosim.org/1.0/OpenRobotics/models/Sun
+
+
+
+ https://fuel.gazebosim.org/1.0/OpenRobotics/models/Construction Cone
+
+
+
+
+```
+Let's load this world again:
+
+`gz sim -r /fuel_preview.sdf`
+
+Notice how the application has only one system plugin loaded, the `SceneBroadcaster`,
+as defined on the SDF file above. `Physics` is not loaded, so even
though the simulation is running (started with `-r`), the cone doesn't fall
with gravity.
@@ -299,3 +390,8 @@ the background color is the default grey, instead of the blue color set on the
GUI `GzScene` plugin.
@image html files/server_config/camera_env.gif
+
+
+### Order of Execution of Plugins
+The order of execution of plugins can be controlled by setting
+the `` tag inside ``. See example in examples/plugin/priority_printer_plugin and the associated README.md file to learn more.