diff --git a/include/gz/sim/Server.hh b/include/gz/sim/Server.hh index 8d1e6ebc800..36b66e15232 100644 --- a/include/gz/sim/Server.hh +++ b/include/gz/sim/Server.hh @@ -26,6 +26,8 @@ #include #include #include +#include +#include namespace gz { @@ -225,14 +227,57 @@ namespace gz const SystemPluginPtr &_system, const unsigned int _worldIndex = 0); + /// \brief Add a System to the server. The server must not be running when + /// calling this. + /// \param[in] _system system to be added + /// \param[in] _entity Entity of system to be added. + /// \param[in] _sdf Pointer to the SDF element of a tag with + /// configuration options for the system being added. + /// \param[in] _worldIndex Index of the world to query. + /// \return Whether the system was added successfully, or std::nullopt + /// if _worldIndex is invalid. + public: std::optional AddSystem( + const SystemPluginPtr &_system, + std::optional _entity, + std::optional> _sdf, + const unsigned int _worldIndex = 0); + + /// \brief Add a System to the server. The server must not be running when + /// calling this. + /// \param[in] _plugin system plugin to be added with any additional XML + /// contents. + /// \param[in] _entity Entity of system to be added. + /// \param[in] _worldIndex Index of the world to query. + /// \return Whether the system was added successfully, or std::nullopt + /// if _worldIndex is invalid. + public: std::optional AddSystem( + const sdf::Plugin &_plugin, + std::optional _entity, + const unsigned int _worldIndex = 0); + + /// \brief Add a System to the server. The server must not be running when + /// calling this. + /// \param[in] _system System to be added + /// \param[in] _worldIndex Index of the world to add to. + /// \return Whether the system was added successfully, or std::nullopt + /// if _worldIndex is invalid. + public: std::optional AddSystem( + const std::shared_ptr &_system, + const unsigned int _worldIndex = 0); + /// \brief Add a System to the server. The server must not be running when /// calling this. /// \param[in] _system System to be added + /// \param[in] _entity Entity of system to be added. + /// \param[in] _sdf Pointer to the SDF element of a tag with + /// configuration options for the system being added /// \param[in] _worldIndex Index of the world to add to. /// \return Whether the system was added successfully, or std::nullopt /// if _worldIndex is invalid. public: std::optional AddSystem( const std::shared_ptr &_system, + std::optional _entity, + std::optional> _sdf, const unsigned int _worldIndex = 0); /// \brief Get an Entity based on a name. diff --git a/src/Server.cc b/src/Server.cc index ba4b681f1ee..357d7884bc0 100644 --- a/src/Server.cc +++ b/src/Server.cc @@ -352,6 +352,29 @@ std::optional Server::SystemCount(const unsigned int _worldIndex) const ////////////////////////////////////////////////// std::optional Server::AddSystem(const SystemPluginPtr &_system, const unsigned int _worldIndex) +{ + return this->AddSystem(_system, std::nullopt, std::nullopt, _worldIndex); +} + +////////////////////////////////////////////////// +std::optional Server::AddSystem(const sdf::Plugin &_plugin, + std::optional _entity, + const unsigned int _worldIndex) +{ + auto system = this->dataPtr->systemLoader->LoadPlugin(_plugin); + if (system) + { + return this->AddSystem(system.value(), _entity, _plugin.ToElement(), _worldIndex); + } + return false; +} + +////////////////////////////////////////////////// +std::optional Server::AddSystem( + const SystemPluginPtr &_system, + std::optional _entity, + std::optional> _sdf, + const unsigned int _worldIndex) { // Check the current state, and return early if preconditions are not met. std::lock_guard lock(this->dataPtr->runMutex); @@ -364,7 +387,7 @@ std::optional Server::AddSystem(const SystemPluginPtr &_system, if (_worldIndex < this->dataPtr->simRunners.size()) { - this->dataPtr->simRunners[_worldIndex]->AddSystem(_system); + this->dataPtr->simRunners[_worldIndex]->AddSystem(_system, _entity, _sdf); return true; } @@ -374,6 +397,16 @@ std::optional Server::AddSystem(const SystemPluginPtr &_system, ////////////////////////////////////////////////// std::optional Server::AddSystem(const std::shared_ptr &_system, const unsigned int _worldIndex) +{ + return this->AddSystem(_system, std::nullopt, std::nullopt, _worldIndex); +} + +////////////////////////////////////////////////// +std::optional Server::AddSystem( + const std::shared_ptr &_system, + std::optional _entity, + std::optional> _sdf, + const unsigned int _worldIndex) { std::lock_guard lock(this->dataPtr->runMutex); if (this->dataPtr->running) @@ -384,7 +417,7 @@ std::optional Server::AddSystem(const std::shared_ptr &_system, if (_worldIndex < this->dataPtr->simRunners.size()) { - this->dataPtr->simRunners[_worldIndex]->AddSystem(_system); + this->dataPtr->simRunners[_worldIndex]->AddSystem(_system, _entity, _sdf); return true; } diff --git a/src/Server_TEST.cc b/src/Server_TEST.cc index c3efe001238..e2fba5e054d 100644 --- a/src/Server_TEST.cc +++ b/src/Server_TEST.cc @@ -625,17 +625,48 @@ TEST_P(ServerFixture, GZ_UTILS_TEST_DISABLED_ON_WIN32(RunOnceUnpaused)) auto mockSystemPlugin = systemLoader.LoadPlugin(sdfPlugin); ASSERT_TRUE(mockSystemPlugin.has_value()); - // Check that it was loaded - const size_t systemCount = *server.SystemCount(); - EXPECT_TRUE(*server.AddSystem(mockSystemPlugin.value())); - EXPECT_EQ(systemCount + 1, *server.SystemCount()); - // Query the interface from the plugin auto system = mockSystemPlugin.value()->QueryInterface(); EXPECT_NE(system, nullptr); auto mockSystem = dynamic_cast(system); EXPECT_NE(mockSystem, nullptr); + Entity entity = server.EntityByName("default").value(); + size_t configureCallCount = 0; + auto configureCallback = [&sdfPlugin, &entity, &configureCallCount]( + const Entity &_entity, + const std::shared_ptr &_sdf, + EntityComponentManager &, + EventManager &) + { + configureCallCount++; + EXPECT_EQ(entity, _entity); + EXPECT_EQ(sdfPlugin.ToElement()->ToString(""), _sdf->ToString("")); + }; + + mockSystem->configureCallback = configureCallback; + const size_t systemCount = *server.SystemCount(); + EXPECT_TRUE( + *server.AddSystem( + mockSystemPlugin.value(), entity, sdfPlugin.ToElement() + )); + + // Add pointer + auto mockSystemPtr = std::make_shared(); + mockSystemPtr->configureCallback = configureCallback; + EXPECT_TRUE(*server.AddSystem(mockSystemPtr, entity, sdfPlugin.ToElement())); + + // Add an sdf::Plugin + EXPECT_TRUE(*server.AddSystem(sdfPlugin, entity)); + + // Fail if plugin is invalid + sdf::Plugin invalidPlugin("foo_plugin", "foo::systems::FooPlugin"); + EXPECT_FALSE(*server.AddSystem(invalidPlugin, entity)); + + // Check that it was loaded + EXPECT_EQ(systemCount + 3, *server.SystemCount()); + EXPECT_EQ(2u, configureCallCount); + // No steps should have been executed EXPECT_EQ(0u, mockSystem->preUpdateCallCount); EXPECT_EQ(0u, mockSystem->updateCallCount);