Files
o3de/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Debugger/Debugger.cpp
T
2021-03-25 13:57:57 -07:00

822 lines
32 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/Entity/GameEntityContextBus.h>
#include "Debugger.h"
#include "Messages/Notify.h"
#include "Messages/Request.h"
#include <ScriptCanvas/Core/GraphBus.h>
#include <ScriptCanvas/Execution/RuntimeComponent.h>
namespace ScriptCanvas
{
namespace Debugger
{
void ServiceComponent::Connect(Target& target)
{
// \todo disconnect previous or reject or something
m_client = target;
if (m_state == SCDebugState_Detached)
{
m_state = SCDebugState_Attached;
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("Debugger attached to new connection");
}
else if (m_state == SCDebugState_Interactive)
{
Lock guard(m_msgMutex);
m_msgQueue.push_back(AzFramework::TmMsgPtr(aznew Message::ContinueRequest()));
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("Debugger attached to new connection, continuing");
}
else
{
AZ_Warning("ScriptCanvas Debugger", false, "Something has gone terribly wrong with the debugger");
return;
}
m_self.CopyScript(m_client);
m_activeEntityStatusDirty = true;
m_activeGraphStatusDirty = true;
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_client.m_info, Message::Connected(m_self));
}
Message::Request* ServiceComponent::FilterMessage(AzFramework::TmMsgPtr& msg)
{
AzFramework::TargetInfo client;
AzFramework::TargetManager::Bus::BroadcastResult(client, &AzFramework::TargetManager::GetTargetInfo, msg->GetSenderTargetId());
// cull messages without a target match
if (m_client.m_info.GetNetworkId() != client.GetNetworkId())
{
if (auto connection = azrtti_cast<Message::ConnectRequest*>(msg.get()))
{
// connection messages are handled separately
Target connectionTarget;
connectionTarget.m_info = client;
connectionTarget.m_script = connection->m_target;
Connect(connectionTarget);
return nullptr;
}
// \todo send a connection denied message
// AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, sender, Message::Denied());
return nullptr;
}
else if (auto disconnection = azrtti_cast<Message::DisconnectRequest*>(msg.get()))
{
DisconnectFromClient();
}
return azrtti_cast<Message::Request*>(msg.get());
}
void ServiceComponent::Interact()
{
if (m_state == SCDebugState_Interactive)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("The debugger is going into interactive mode");
while (true)
{
// the events aren't getting dispatched from another thread, so force them out here
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::DispatchMessages, k_clientRequestsMsgSlotId);
// process any new ones
ProcessMessages();
// check if we're still in interactive mode
if (m_state != SCDebugState_Interactive)
{
return;
}
// give other threads a chance
AZStd::this_thread::yield();
}
}
}
bool ServiceComponent::IsAttached() const
{
return m_state != SCDebugState_Detached && m_state != SCDebugState_Detaching;
}
void ServiceComponent::ProcessMessages()
{
AzFramework::TmMsgQueue messages;
while (true)
{
{
Lock lock(m_msgMutex);
if (m_msgQueue.empty())
{
return;
}
AZStd::swap(messages, m_msgQueue);
}
while (!messages.empty())
{
AzFramework::TmMsgPtr msg = *messages.begin();
messages.pop_front();
if (Message::Request* request = FilterMessage(msg))
{
request->Visit(*this);
}
}
}
}
void ServiceComponent::OnReceivedMsg(AzFramework::TmMsgPtr msg)
{
if (!msg)
{
AZ_Error("ScriptCanvas Debugger", false, "We received a NULL message in the service message queue");
return;
}
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("service component received a message of type: %s", msg->RTTI_GetTypeName());
if (m_state != SCDebugState_Detaching && azrtti_cast<Message::Request*>(msg.get()))
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("service is putting the request in the queue");
{
Lock lock(m_msgMutex);
m_msgQueue.push_back(msg);
}
if (m_state != SCDebugState_Interactive)
{
ProcessMessages();
}
}
else
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("service is rejecting the message");
// \todo send a connection denied message
// AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, sender, Message::Acknowledge(0, AZ_CRC("AccessDenied", 0xde72ce21)));
}
}
void ServiceComponent::TargetLeftNetwork(AzFramework::TargetInfo info)
{
if (m_client.m_info.IsIdentityEqualTo(info))
{
DisconnectFromClient();
}
}
void ServiceComponent::Init()
{}
void ServiceComponent::Activate()
{
m_state = SCDebugState_Detached;
AzFramework::TmMsgBus::Handler::BusConnect(k_clientRequestsMsgSlotId);
AzFramework::TargetManagerClient::Bus::Handler::BusConnect();
ExecutionNotificationsBus::Handler::BusConnect();
AzFramework::TargetContainer targets;
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::EnumTargetInfos, targets);
for (auto& idAndInfo : targets)
{
if (idAndInfo.second.GetStatusFlags() & AzFramework::TF_SELF)
{
m_self.m_info = idAndInfo.second;
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("Self found!");
}
}
if (!m_self.m_info.GetDisplayName())
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("Self NOT found!");
}
}
void ServiceComponent::Deactivate()
{
if (m_state != SCDebugState_Detached)
{
//\todo DetachAll();
}
AzFramework::TmMsgBus::Handler::BusDisconnect(k_clientRequestsMsgSlotId);
AzFramework::TargetManagerClient::Bus::Handler::BusDisconnect();
ExecutionNotificationsBus::Handler::BusDisconnect();
{
Lock lock(m_msgMutex);
m_msgQueue.clear();
}
}
void ServiceComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("ScriptCanvasDebugService", 0x7ece424b));
}
void ServiceComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("ScriptCanvasDebugService", 0x7ece424b));
}
void ServiceComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
dependent.push_back(AZ_CRC("ScriptCanvasService", 0x41fd58f3));
}
void ServiceComponent::Reflect(AZ::ReflectContext* context)
{
ReflectExecutionBusArguments(context);
ReflectArguments(context);
ReflectNotifications(context);
ReflectRequests(context);
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ServiceComponent, AZ::Component>()
->Version(1)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<ServiceComponent>("Script Canvas Runtime Debugger", "Provides remote debugging services for Script Canvas")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::Category, "Scripting")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
;
}
}
}
void ServiceComponent::GraphActivated(const GraphActivation& graphInfo)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("GraphActivation: %s", graphInfo.ToString().data());
Lock lock(m_mutex);
ActiveGraphStatus* activeGraphStatus = nullptr;
auto graphIter = m_activeGraphs.find(graphInfo.m_graphIdentifier.m_assetId);
if (graphIter == m_activeGraphs.end())
{
activeGraphStatus = &(m_activeGraphs[graphInfo.m_graphIdentifier.m_assetId]);
if (IsAssetObserved(graphInfo.m_graphIdentifier.m_assetId))
{
activeGraphStatus->m_isObserved = true;
}
}
else
{
activeGraphStatus = &(graphIter->second);
}
if (activeGraphStatus)
{
activeGraphStatus->m_instanceCounter++;
}
const AZ::NamedEntityId& namedEntityId = graphInfo.m_runtimeEntity;
auto entityIter = m_activeEntities.find(namedEntityId);
ActiveEntityStatus* entityStatus = nullptr;
if (entityIter == m_activeEntities.end())
{
entityStatus = &(m_activeEntities[namedEntityId]);
entityStatus->m_namedEntityId = namedEntityId;
}
else
{
entityStatus = &(entityIter->second);
}
if (entityStatus)
{
auto graphCountIter = entityStatus->m_activeGraphs.find(graphInfo.m_graphIdentifier);
if (graphCountIter == entityStatus->m_activeGraphs.end())
{
ActiveGraphStatus graphStatus;
graphStatus.m_instanceCounter = 1;
graphStatus.m_isObserved = IsGraphObserved(graphInfo.m_runtimeEntity, graphInfo.m_graphIdentifier);
entityStatus->m_activeGraphs.insert(AZStd::make_pair(graphInfo.m_graphIdentifier, graphStatus));
}
else
{
// We received a double activation signal for the same graph without a deactivate?
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("Accounting error. An activated graph was already found for the entity the active list");
}
}
if (!m_client.m_script.m_staticEntities.empty())
{
auto clientStaticEntityIter = m_client.m_script.m_staticEntities.begin();
while (clientStaticEntityIter != m_client.m_script.m_staticEntities.end())
{
AZ::EntityId runtimeEntityId;
AZ::SliceComponent::EntityIdToEntityIdMap loadedEntityIdMap;
AzFramework::SliceEntityOwnershipServiceRequestBus::EventResult(runtimeEntityId, m_contextId, &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::FindLoadedEntityIdMapping, clientStaticEntityIter->first);
if (runtimeEntityId == graphInfo.m_runtimeEntity)
{
AZ::EntityId staticEntity = clientStaticEntityIter->first;
// Remap the static entity identifiers and move them into the 'self' script targets
{
auto insertResult = m_self.m_script.m_entities.insert(runtimeEntityId);
auto selfStaticEntityIter = m_self.m_script.m_staticEntities.find(staticEntity);
AZ_Assert(selfStaticEntityIter != m_self.m_script.m_staticEntities.end(), "self scripts miss match with client scripts");
// Once debugger supports multiple same graphs per entity, we can directly copy over without comparing,
// because the component id should be hooked between editor and runtime component
for (auto graphIdentifier : selfStaticEntityIter->second)
{
if (graphIdentifier.m_assetId == graphInfo.m_graphIdentifier.m_assetId)
{
insertResult.first->second.insert(graphInfo.m_graphIdentifier);
selfStaticEntityIter->second.erase(graphIdentifier);
break;
}
}
if (selfStaticEntityIter->second.empty())
{
m_self.m_script.m_staticEntities.erase(staticEntity);
}
}
// Remap the static entity identifiers and move them into the 'client' script targets
{
auto insertResult = m_client.m_script.m_entities.insert(runtimeEntityId);
// Once debugger supports multiple same graphs per entity, we can directly copy over without comparing,
// because the component id should be hooked between editor and runtime component
for (auto graphIdentifier : clientStaticEntityIter->second)
{
if (graphIdentifier.m_assetId == graphInfo.m_graphIdentifier.m_assetId)
{
insertResult.first->second.insert(graphInfo.m_graphIdentifier);
clientStaticEntityIter->second.erase(graphIdentifier);
break;
}
}
if (clientStaticEntityIter->second.empty())
{
clientStaticEntityIter = m_client.m_script.m_staticEntities.erase(clientStaticEntityIter);
}
}
break;
}
else
{
++clientStaticEntityIter;
}
}
}
GraphActivation payload = graphInfo;
payload.m_entityIsObserved = IsGraphObserved(graphInfo.m_runtimeEntity, graphInfo.m_graphIdentifier);
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_client.m_info, Message::GraphActivated(payload));
}
void ServiceComponent::GraphDeactivated(const GraphActivation& graphInfo)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("GraphDeactivated: %s", graphInfo.ToString().data());
Lock lock(m_mutex);
auto graphIter = m_activeGraphs.find(graphInfo.m_graphIdentifier.m_assetId);
if (graphIter == m_activeGraphs.end())
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("Accounting error. A deactivated graph was not found in the active list");
}
else
{
--graphIter->second.m_instanceCounter;
if (graphIter->second.m_instanceCounter == 0)
{
m_activeGraphs.erase(graphIter);
}
}
auto namedEntity = graphInfo.m_runtimeEntity;
auto entityIter = m_activeEntities.find(namedEntity);
if (entityIter == m_activeEntities.end())
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("Accounting error. A deactivated entity was not found in the active list");
}
else
{
ActiveEntityStatus& entityStatus = entityIter->second;
auto graphIterator = entityStatus.m_activeGraphs.find(graphInfo.m_graphIdentifier);
if (graphIterator == entityStatus.m_activeGraphs.end())
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("Accounting error. A deactivated graph was not found for the entity the active list");
}
else
{
entityStatus.m_activeGraphs.erase(graphIterator);
}
if (entityStatus.m_activeGraphs.empty())
{
// At this point entityStatus is bad. So no touchy
m_activeEntities.erase(entityIter);
}
}
GraphActivation payload = graphInfo;
payload.m_entityIsObserved = IsGraphObserved(graphInfo.m_runtimeEntity, graphInfo.m_graphIdentifier);
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_client.m_info, Message::GraphDeactivated(payload));
}
bool ServiceComponent::IsAssetObserved(const AZ::Data::AssetId& assetId) const
{
if (!m_client.m_script.m_logExecution)
{
return false;
}
#if defined(SCRIPT_CANVAS_DEBUGGER_IS_ALWAYS_OBSERVING)
return true;
#else
if (m_state == SCDebugState_Detached || m_state == SCDebugState_Detaching)
{
return false;
}
return m_client.m_script.IsObservingAsset(assetId);
#endif //defined(SCRIPT_CANVAS_DEBUGGER_IS_ALWAYS_OBSERVING)
}
bool ServiceComponent::IsGraphObserved(const AZ::EntityId& entityId, const GraphIdentifier& identifier)
{
if (!m_client.m_script.m_logExecution)
{
return false;
}
#if defined(SCRIPT_CANVAS_DEBUGGER_IS_ALWAYS_OBSERVING)
return true;
#else
if (m_state == SCDebugState_Detached || m_state == SCDebugState_Detaching)
{
return false;
}
return m_client.m_script.IsObserving(entityId, identifier);
#endif //defined(SCRIPT_CANVAS_DEBUGGER_IS_ALWAYS_OBSERVING)
}
bool ServiceComponent::IsVariableObserved(const VariableId& /*variableId*/)
{
#if defined(SCRIPT_CANVAS_DEBUGGER_IS_ALWAYS_OBSERVING)
return true;
#else
// \todo finish me!
return true;
#endif//defined(SCRIPT_CANVAS_DEBUGGER_IS_ALWAYS_OBSERVING)
}
void ServiceComponent::NodeSignaledOutput(const OutputSignal& nodeSignal)
{
NodeSignalled<OutputSignal, Message::SignaledOutput>(nodeSignal);
}
void ServiceComponent::NodeSignaledInput(const InputSignal& nodeSignal)
{
NodeSignalled<InputSignal, Message::SignaledInput>(nodeSignal);
}
void ServiceComponent::NodeStateUpdated(const NodeStateChange&)
{
// \todo decide whether or not this should break
// if (m_state == SCDebugState_Interactive)
// {
// Interact();
// }
}
void ServiceComponent::VariableChanged(const VariableChange& variableChange)
{
/*
if (variableChange breakpoint hit)
{}
else
*/
if (m_client.m_script.m_logExecution || m_state == SCDebugState_Interactive || m_state == SCDebugState_InteractOnNext)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("Interactive: %s", variableChange.ToString().data());
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_client.m_info, Message::VariableChanged(variableChange));
if (m_state == SCDebugState_Interactive || m_state == SCDebugState_InteractOnNext)
{
Interact();
}
}
}
void ServiceComponent::AnnotateNode(const AnnotateNodeSignal& annotateNode)
{
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_client.m_info, Message::AnnotateNode(annotateNode));
}
void ServiceComponent::Visit(Message::AddBreakpointRequest&)
{
Lock lock(m_mutex);
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("The debugger has received an add breakpoint request!");
// translate to runtime component values
// !add the graph to the list of graphs being debugged!
/*
if (m_breakpoints.find(request.m_breakpoint) == m_breakpoints.end())
{
m_breakpoints.insert(request.m_breakpoint);
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_client.m_info, Message::BreakpointAdded(request.m_breakpoint));
}
*/
}
void ServiceComponent::Visit(Message::AddTargetsRequest& request)
{
Lock lock(m_mutex);
if (m_state == SCDebugState_Attached)
{
m_activeEntityStatusDirty = true;
m_activeGraphStatusDirty = true;
m_self.m_script.Merge(request.m_addTargets);
m_client.m_script.Merge(request.m_addTargets);
SetTargetsObserved(request.m_addTargets.m_entities, true);
SetTargetsObserved(request.m_addTargets.m_staticEntities, true);
}
}
void ServiceComponent::Visit(Message::RemoveTargetsRequest& request)
{
Lock lock(m_mutex);
if (m_state == SCDebugState_Attached)
{
m_activeEntityStatusDirty = true;
m_activeGraphStatusDirty = true;
m_self.m_script.Remove(request.m_removeTargets);
m_client.m_script.Remove(request.m_removeTargets);
SetTargetsObserved(request.m_removeTargets.m_entities, false);
SetTargetsObserved(request.m_removeTargets.m_staticEntities, false);
}
}
void ServiceComponent::Visit(Message::StartLoggingRequest& request)
{
Lock lock(m_mutex);
if (IsAttached())
{
m_self.m_script = request.m_initialTargets;
m_self.m_script.m_logExecution = true;
m_client.m_script = request.m_initialTargets;
m_client.m_script.m_logExecution = true;
SetTargetsObserved(request.m_initialTargets.m_entities, true);
SetTargetsObserved(request.m_initialTargets.m_staticEntities, true);
m_contextId = AzFramework::EntityContextId::CreateNull();
if (!request.m_initialTargets.m_staticEntities.empty())
{
AzFramework::GameEntityContextRequestBus::BroadcastResult(m_contextId, &AzFramework::GameEntityContextRequests::GetGameEntityContextId);
}
}
}
void ServiceComponent::Visit(Message::StopLoggingRequest& /*request*/)
{
Lock lock(m_mutex);
if (IsAttached())
{
m_self.m_script.m_logExecution = false;
m_client.m_script.m_logExecution = false;
}
}
void ServiceComponent::Visit(Message::BreakRequest&)
{
if (m_state == SCDebugState_Attached)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("The debugger is GOING TO BREAK!");
m_state = SCDebugState_Interactive;
}
else
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("The debugger is rejecting break request as it is not attached");
}
}
void ServiceComponent::Visit(Message::ContinueRequest&)
{
if (m_state == SCDebugState_Interactive)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("The debugger is CONTINUING TO RUN!");
m_state = SCDebugState_Attached;
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_client.m_info, Message::Continued());
}
else
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("The debugger is rejecting continue request as it is not interactive");
}
}
void ServiceComponent::Visit(Message::GetAvailableScriptTargets&)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("received Message::GetAvailableScriptTargets");
if (IsAttached())
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("sending Message::GetAvailableScriptTargets");
RefreshActiveEntityStatus();
RefreshActiveGraphStatus();
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_client.m_info, Message::AvailableScriptTargetsResult(AZStd::make_pair(m_activeEntities, m_activeGraphs)));
}
}
void ServiceComponent::Visit(Message::GetActiveEntitiesRequest&)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("received Message::GetActiveEntitiesRequest");
if (IsAttached())
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("sending Message::GetActiveEntitiesResult: %d", m_activeEntities.size());
RefreshActiveEntityStatus();
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_client.m_info, Message::ActiveEntitiesResult(m_activeEntities));
}
}
void ServiceComponent::Visit(Message::GetActiveGraphsRequest&)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("received Message::GetActiveGraphsRequest");
if (IsAttached())
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("sending Message::GetActiveGraphsResult: %d", m_activeGraphs.size());
RefreshActiveGraphStatus();
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_client.m_info, Message::ActiveGraphsResult(m_activeGraphs));
}
}
void ServiceComponent::Visit(Message::RemoveBreakpointRequest&)
{
Lock lock(m_mutex);
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("The debugger has received a remoe breakpoint request!");
// translate to runtime component values
// !remove the graph from the list of graphs being debugged!
/*
if (m_breakpoints.find(request.m_breakpoint) == m_breakpoints.end())
{
m_breakpoints.insert(request.m_breakpoint);
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_client.m_info, Message::BreakpointAdded(request.m_breakpoint));
}
*/
}
void ServiceComponent::Visit(Message::StepOverRequest&)
{
if (m_state == SCDebugState_Interactive)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("The debugger is going to step over the current instruction!");
m_state = SCDebugState_InteractOnNext;
}
else
{
SCRIPT_CANVAS_DEBUGGER_TRACE_SERVER("The debugger is rejecting step over request as it is not interactive");
}
}
void ServiceComponent::RuntimeError([[maybe_unused]] const AZ::EntityId& entityId, [[maybe_unused]] const GraphIdentifier& identifier, [[maybe_unused]] const AZStd::string_view& description)
{
}
void ServiceComponent::SetTargetsObserved(const TargetEntities& targetEntities, bool /*observedState*/)
{
for (auto target : targetEntities)
{
AZ::Entity* entity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, target.first);
if (entity)
{
auto runtimeComponents = AZ::EntityUtils::FindDerivedComponents<RuntimeComponent>(entity);
if (runtimeComponents.empty())
{
continue;
}
for (auto graphIdentifier : target.second)
{
for (auto graphIter = runtimeComponents.begin(); graphIter != runtimeComponents.end(); ++graphIter)
{
auto runtimeComponent = (*graphIter);
if (graphIdentifier.m_assetId.m_guid == runtimeComponent->GetAsset().GetId().m_guid)
{
// TODO: Gate on ComponentId
// \todo chcurran restore this functionality
// runtimeComponent->SetIsGraphObserved(observedState);
runtimeComponents.erase(graphIter);
break;
}
}
}
}
}
}
void ServiceComponent::DisconnectFromClient()
{
m_state = SCDebugState_Detaching;
AzFramework::TargetInfo targetInfo = m_client.m_info;
m_client = Target();
m_self.m_script = ScriptTarget();
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, targetInfo, Message::Disconnected());
m_state = SCDebugState_Detached;
}
void ServiceComponent::RefreshActiveEntityStatus()
{
if (m_activeEntityStatusDirty)
{
m_activeEntityStatusDirty = false;
for (auto& entityPair : m_activeEntities)
{
for (auto& graphPair : entityPair.second.m_activeGraphs)
{
graphPair.second.m_isObserved = IsGraphObserved(entityPair.first, graphPair.first);
}
}
}
}
void ServiceComponent::RefreshActiveGraphStatus()
{
if (m_activeGraphStatusDirty)
{
m_activeGraphStatusDirty = false;
for (auto& graphPair : m_activeGraphs)
{
graphPair.second.m_isObserved = IsAssetObserved(graphPair.first);
}
}
}
}
}