-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tag entity exclusion #59
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* Copyright 2024, Robotec.ai sp. z o.o. | ||
* | ||
* 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. | ||
*/ | ||
#include <Entity/EntityTagListener.h> | ||
#include <RGL/RGLBus.h> | ||
|
||
namespace RGL | ||
{ | ||
EntityTagListener::EntityTagListener(AZ::EntityId entityId) | ||
: m_entityId(entityId) | ||
{ | ||
AZ::EntityBus::Handler::BusConnect(m_entityId); | ||
} | ||
|
||
EntityTagListener::~EntityTagListener() | ||
{ | ||
AZ::EntityBus::Handler::BusDisconnect(m_entityId); | ||
} | ||
|
||
void EntityTagListener::OnEntityActivated([[maybe_unused]] const AZ::EntityId& entityId) | ||
{ | ||
LmbrCentral::Tags entityTags; | ||
LmbrCentral::TagComponentRequestBus::EventResult(entityTags, m_entityId, &LmbrCentral::TagComponentRequests::GetTags); | ||
|
||
if (!entityTags.empty()) | ||
{ | ||
RGLInterface::Get()->ReviseEntityPresence(m_entityId); | ||
} | ||
|
||
LmbrCentral::TagComponentNotificationsBus::Handler::BusConnect(m_entityId); | ||
} | ||
|
||
void EntityTagListener::OnEntityDeactivated(const AZ::EntityId& entity_id) | ||
{ | ||
LmbrCentral::TagComponentNotificationsBus::Handler::BusDisconnect(m_entityId); | ||
} | ||
|
||
void EntityTagListener::OnTagAdded(const LmbrCentral::Tag& crc32) | ||
{ | ||
RGLInterface::Get()->ReviseEntityPresence(m_entityId); | ||
} | ||
|
||
void EntityTagListener::OnTagRemoved(const LmbrCentral::Tag& crc32) | ||
{ | ||
RGLInterface::Get()->ReviseEntityPresence(m_entityId); | ||
} | ||
} // namespace RGL |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* Copyright 2024, Robotec.ai sp. z o.o. | ||
* | ||
* 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. | ||
*/ | ||
#pragma once | ||
|
||
#include <AzCore/Component/EntityBus.h> | ||
#include <LmbrCentral/Scripting/TagComponentBus.h> | ||
|
||
namespace RGL | ||
{ | ||
class EntityTagListener | ||
: AZ::EntityBus::Handler | ||
, LmbrCentral::TagComponentNotificationsBus::Handler | ||
{ | ||
public: | ||
EntityTagListener(AZ::EntityId entityId); | ||
~EntityTagListener(); | ||
|
||
void OnEntityActivated(const AZ::EntityId&) override; | ||
void OnEntityDeactivated(const AZ::EntityId&) override; | ||
|
||
// TagComponentNotificationsBus overrides | ||
void OnTagAdded(const LmbrCentral::Tag&) override; | ||
void OnTagRemoved(const LmbrCentral::Tag&) override; | ||
|
||
private: | ||
AZ::EntityId m_entityId; | ||
}; | ||
} // namespace RGL |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -87,13 +87,15 @@ namespace RGL | |
|
||
AzFramework::EntityContextEventBus::Handler::BusConnect(gameEntityContextId); | ||
LidarSystemNotificationBus::Handler::BusConnect(); | ||
AZ::TickBus::Handler::BusConnect(); | ||
|
||
m_rglLidarSystem.Activate(); | ||
} | ||
|
||
void RGLSystemComponent::Deactivate() | ||
{ | ||
m_rglLidarSystem.Deactivate(); | ||
AZ::TickBus::Handler::BusDisconnect(); | ||
LidarSystemNotificationBus::Handler::BusDisconnect(); | ||
AzFramework::EntityContextEventBus::Handler::BusDisconnect(); | ||
|
||
|
@@ -113,6 +115,18 @@ namespace RGL | |
void RGLSystemComponent::SetSceneConfiguration(const SceneConfiguration& config) | ||
{ | ||
m_sceneConfig = config; | ||
|
||
m_excludedTags.resize(config.m_excludedTagNames.size()); | ||
AZStd::transform( | ||
config.m_excludedTagNames.begin(), | ||
config.m_excludedTagNames.end(), | ||
m_excludedTags.begin(), | ||
[](const AZStd::string& tagName) -> LmbrCentral::Tag | ||
{ | ||
return LmbrCentral::Tag(tagName); | ||
}); | ||
UpdateTagExcludedEntities(); | ||
|
||
RGLNotificationBus::Broadcast(&RGLNotifications::OnSceneConfigurationSet, config); | ||
} | ||
|
||
|
@@ -121,14 +135,37 @@ namespace RGL | |
return m_sceneConfig; | ||
} | ||
|
||
static bool HasExcludedTag(AZ::EntityId entityId, const AZStd::vector<LmbrCentral::Tag>& excludedTags) | ||
{ | ||
LmbrCentral::Tags entityTags; | ||
LmbrCentral::TagComponentRequestBus::EventResult(entityTags, entityId, &LmbrCentral::TagComponentRequests::GetTags); | ||
|
||
if (entityTags.empty()) | ||
{ | ||
return false; | ||
} | ||
|
||
for (const auto tag : excludedTags) | ||
{ | ||
if (entityTags.contains(tag)) | ||
{ | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
alek-kam-robotec-ai marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
void RGLSystemComponent::OnEntityContextCreateEntity(AZ::Entity& entity) | ||
{ | ||
if (m_excludedEntities.contains(entity.GetId())) | ||
if (!HasVisuals(entity)) | ||
{ | ||
return; | ||
} | ||
|
||
if (m_activeLidarCount < 1U) | ||
m_entityTagListeners.emplace_back(entity.GetId()); | ||
alek-kam-robotec-ai marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (m_activeLidarCount < 1U || ShouldEntityBeExcluded(entity.GetId())) | ||
{ | ||
m_unprocessedEntities.emplace(entity.GetId()); | ||
return; | ||
|
@@ -163,6 +200,12 @@ namespace RGL | |
RGLNotificationBus::Broadcast(&RGLNotifications::OnAnyLidarExists); | ||
for (auto entityIdIt = m_unprocessedEntities.begin(); entityIdIt != m_unprocessedEntities.end();) | ||
{ | ||
if (ShouldEntityBeExcluded(*entityIdIt)) | ||
{ | ||
++entityIdIt; | ||
continue; | ||
} | ||
|
||
AZ::Entity* entity = nullptr; | ||
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, *entityIdIt); | ||
AZ_Assert(entity, "Failed to find entity with provided id!"); | ||
|
@@ -189,6 +232,26 @@ namespace RGL | |
m_modelLibrary.Clear(); | ||
} | ||
|
||
void RGLSystemComponent::OnTick(float deltaTime, AZ::ScriptTimePoint time) | ||
{ | ||
for (auto entityId : m_managersToBeRemoved) | ||
{ | ||
m_entityManagers.erase(entityId); | ||
m_unprocessedEntities.insert(entityId); | ||
} | ||
m_managersToBeRemoved.clear(); | ||
} | ||
Comment on lines
+234
to
+242
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why couldn't we erase entity manager in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is so that the caller can signal revision inside a bus notification and can then safely disconnect from said bus after the call has ended (on destruction). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At the moment, the only caller is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exactly. I believe that this could lead to bugs that would be hard to track down as in previous iterations of the solution the entity manager handlet the tag notification bus and the |
||
|
||
bool RGLSystemComponent::HasVisuals(const AZ::Entity& entity) | ||
{ | ||
return entity.FindComponent<EMotionFX::Integration::ActorComponent>() || entity.FindComponent(AZ::Render::MeshComponentTypeId); | ||
} | ||
|
||
bool RGLSystemComponent::ShouldEntityBeExcluded(AZ::EntityId entityId) const | ||
{ | ||
return m_excludedEntities.contains(entityId) || HasExcludedTag(entityId, m_excludedTags); | ||
} | ||
|
||
void RGLSystemComponent::ProcessEntity(const AZ::Entity& entity) | ||
{ | ||
AZStd::unique_ptr<EntityManager> entityManager; | ||
|
@@ -209,6 +272,27 @@ namespace RGL | |
AZ_Error(__func__, inserted, "Object with provided entityId already exists."); | ||
} | ||
|
||
void RGLSystemComponent::UpdateTagExcludedEntities() | ||
{ | ||
if (m_excludedTags.empty()) | ||
{ | ||
return; | ||
} | ||
|
||
for (auto entityManagerIt = m_entityManagers.begin(); entityManagerIt != m_entityManagers.end();) | ||
{ | ||
if (HasExcludedTag(entityManagerIt->first, m_excludedTags)) | ||
{ | ||
m_unprocessedEntities.insert(entityManagerIt->first); | ||
entityManagerIt = m_entityManagers.erase(entityManagerIt); | ||
} | ||
else | ||
{ | ||
++entityManagerIt; | ||
} | ||
} | ||
} | ||
|
||
void RGLSystemComponent::UpdateScene() | ||
{ | ||
AZ::ScriptTimePoint currentTime; | ||
|
@@ -225,4 +309,33 @@ namespace RGL | |
entityManager->Update(); | ||
} | ||
} | ||
|
||
void RGLSystemComponent::ReviseEntityPresence(AZ::EntityId entityId) | ||
{ | ||
if (m_activeLidarCount < 1U) | ||
{ | ||
return; // No lidars exist. Every entity should stay as unprocessed until they do. | ||
} | ||
|
||
if (m_excludedEntities.contains(entityId)) | ||
{ | ||
return; // Already not included. | ||
} | ||
|
||
if (HasExcludedTag(entityId, m_excludedTags)) | ||
{ | ||
if (m_entityManagers.contains(entityId)) | ||
{ | ||
m_managersToBeRemoved.push_back(entityId); | ||
} | ||
} | ||
else if (const auto it = m_unprocessedEntities.find(entityId); it != m_unprocessedEntities.end()) | ||
{ | ||
m_unprocessedEntities.erase(it); | ||
AZ::Entity* entity = nullptr; | ||
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId); | ||
AZ_Assert(entity, "Failed to find entity with provided id!"); | ||
ProcessEntity(*entity); | ||
} | ||
} | ||
} // namespace RGL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of creating the new class and having separate container for it in
RGLSystemComponent
I'd extendEntityManager
withLmbrCentral::TagComponentNotificationsBus::Handler
. I see no advantages in having this separation.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is to allow for a scenario where an entity is excluded from the raycasting due it being tagged with an excluded tag after which the tag is removed and the entity must be processed. With the bus handled by the entity manager we would not be able to achieve this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if dynamic handling of tag creation/destruction is necessary (if there are any real use cases). If not, this solution could be significantly simplified to checking
ShouldEntityBeExcluded
inOnEntityContextCreateEntity
and discarding entities that should be excluded (skipping processing them and putting them tom_unprocessedEntities
). Did you get the detailed requirements for this feature?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Tag Component allows for tag addition and removal at runtime. I believe we should cover these cases as some proved useful before (as seen in this pr).