Files
o3de/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Debugger/ClientTransceiver.cpp
T
Steve Pham 38261d0800 Shorten copyright headers by splitting into 2 lines (#2213)
* Updated all copyright headers to split the longer original copyright line into 2 shorter lines

Signed-off-by: Steve Pham <spham@amazon.com>
2021-07-16 15:25:48 -07:00

550 lines
21 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "ClientTransceiver.h"
#include "Messages/Request.h"
#include "Messages/Notify.h"
using namespace AzFramework;
namespace ScriptCanvas
{
namespace Debugger
{
ClientTransceiver::ClientTransceiver()
{
AzFramework::TargetManagerClient::Bus::Handler::BusConnect();
TmMsgBus::Handler::BusConnect(k_serviceNotificationsMsgSlotId);
ClientRequestsBus::Handler::BusConnect();
ClientUIRequestBus::Handler::BusConnect();
DiscoverNetworkTargets();
for (auto& idAndInfo : m_networkTargets)
{
if (idAndInfo.second.GetStatusFlags() & AzFramework::TF_SELF)
{
m_selfTarget = idAndInfo.second;
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("Self found!");
}
}
if (!m_selfTarget.GetDisplayName())
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("Self NOT found!");
}
m_addCache.m_logExecution = true;
m_removeCache.m_logExecution = false;
}
ClientTransceiver::~ClientTransceiver()
{
ClientUIRequestBus::Handler::BusDisconnect();
ClientRequestsBus::Handler::BusDisconnect();
TmMsgBus::Handler::BusDisconnect(k_serviceNotificationsMsgSlotId);
AzFramework::TargetManagerClient::Bus::Handler::BusDisconnect();
}
void ClientTransceiver::AddBreakpoint(const Breakpoint& breakpoint)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("TRX sending AddBreakpoint Request %s", breakpoint.ToString().data());
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_currentTarget, Message::AddBreakpointRequest(breakpoint));
}
void ClientTransceiver::AddVariableChangeBreakpoint(const VariableChangeBreakpoint&)
{
}
void ClientTransceiver::Break()
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("TRX Sending Break Request %s", m_currentTarget.GetDisplayName());
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_currentTarget, Message::BreakRequest());
}
void ClientTransceiver::BreakpointAdded(const Breakpoint& breakpoint)
{
Lock lock(m_mutex);
auto inactiveIter = m_breakpointsInactive.find(breakpoint);
if (inactiveIter != m_breakpointsInactive.end())
{
m_breakpointsInactive.erase(inactiveIter);
}
if (m_breakpointsActive.find(breakpoint) == m_breakpointsActive.end())
{
m_breakpointsActive.insert(breakpoint);
ServiceNotificationsBus::Broadcast(&ServiceNotifications::BreakPointAdded, breakpoint);
}
}
void ClientTransceiver::ClearMessages()
{
Lock guard(m_msgMutex);
m_msgQueue.clear();
}
void ClientTransceiver::Continue()
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("TRX Sending Continue Request %s", m_currentTarget.GetDisplayName());
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_currentTarget, Message::ContinueRequest());
}
void ClientTransceiver::DesiredTargetConnected(bool connected)
{
if (connected)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("DesiredTarget connected!, sending connect request to %s", m_currentTarget.GetDisplayName());
AzFramework::TargetManager::Bus::BroadcastResult(m_currentTarget, &AzFramework::TargetManager::GetDesiredTarget);
}
else
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("DesiredTarget NOT connected!");
m_currentTarget = AzFramework::TargetInfo();
}
ClientUINotificationBus::Broadcast(&ClientUINotifications::OnCurrentTargetChanged);
// If we are connected to our self, we want to use a different mechanism for now.
// Will unify this in a second pass so this handles all the indirection.
if (m_currentTarget.IsValid())
{
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_currentTarget, Message::ConnectRequest(m_connectionState));
}
}
void ClientTransceiver::DesiredTargetChanged([[maybe_unused]] AZ::u32 newId, [[maybe_unused]] AZ::u32 oldId)
{
if (HasValidConnection())
{
DisconnectFromTarget();
}
}
AzFramework::TargetContainer ClientTransceiver::EnumerateAvailableNetworkTargets()
{
return m_networkTargets;
}
void ClientTransceiver::DiscoverNetworkTargets()
{
AzFramework::TargetContainer targets;
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::EnumTargetInfos, targets);
AzFramework::TargetContainer connectableTargets;
for (auto& idAndInfo : targets)
{
const auto& targetInfo = idAndInfo.second;
auto isConnectable = IsTargetConnectable(targetInfo);
if (isConnectable.IsSuccess())
{
connectableTargets[idAndInfo.first] = idAndInfo.second;
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("Debugger TRX can connect to %s", targetInfo.GetDisplayName());
}
else
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("Debugger TRX can't connect to %s because: %s", targetInfo.GetDisplayName(), isConnectable.GetError().c_str());
}
}
{
Lock lock(m_mutex);
m_networkTargets = connectableTargets;
}
}
AzFramework::TargetInfo ClientTransceiver::GetNetworkTarget()
{
AzFramework::TargetInfo targetInfo;
AzFramework::TargetManager::Bus::BroadcastResult(targetInfo, &AzFramework::TargetManager::GetDesiredTarget);
if (!targetInfo.GetPersistentId())
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("Debugger TRX The user has not chosen a target to connect to.\n");
return AzFramework::TargetInfo();
}
auto isConnectable = IsTargetConnectable(targetInfo);
if (!isConnectable.IsSuccess())
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("Debugger TRX has no target because: %s", isConnectable.GetError().c_str());
return AzFramework::TargetInfo();
}
return targetInfo;
}
void ClientTransceiver::GetAvailableScriptTargets()
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("TRX sending GetAvailableScriptTargets Request %s", m_currentTarget.GetDisplayName());
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_currentTarget, Message::GetAvailableScriptTargets());
}
void ClientTransceiver::GetActiveEntities()
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("TRX sending GetActiveEntities Request %s", m_currentTarget.GetDisplayName());
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_currentTarget, Message::GetActiveEntitiesRequest());
}
void ClientTransceiver::GetActiveGraphs()
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("TRX sending GetActiveGraphs Request %s", m_currentTarget.GetDisplayName());
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_currentTarget, Message::GetActiveGraphsRequest());
}
void ClientTransceiver::GetVariableValue()
{
}
bool ClientTransceiver::HasValidConnection() const
{
return m_currentTarget.IsValid();
}
bool ClientTransceiver::IsConnected(const AzFramework::TargetInfo& targetInfo) const
{
return m_currentTarget.IsIdentityEqualTo(targetInfo);
}
bool ClientTransceiver::IsConnectedToSelf() const
{
return IsConnected(m_selfTarget) || !m_currentTarget.IsValid();
}
void ClientTransceiver::OnReceivedMsg(AzFramework::TmMsgPtr msg)
{
{
Lock lock(m_msgMutex);
if (msg)
{
m_msgQueue.push_back(msg);
}
else
{
AZ_Error("ScriptCanvas Debugger", msg, "We received a NULL message in the trx message queue!");
}
}
ProcessMessages();
}
void ClientTransceiver::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 (auto request = azrtti_cast<Message::Notification*>(msg.get()))
{
request->Visit(*this);
}
}
}
}
void ClientTransceiver::DisconnectFromTarget()
{
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_currentTarget, Message::DisconnectRequest());
}
void ClientTransceiver::CleanupConnection()
{
ClearMessages();
}
void ClientTransceiver::RemoveBreakpoint(const Breakpoint&)
{
}
void ClientTransceiver::RemoveVariableChangeBreakpoint(const VariableChangeBreakpoint&)
{
}
void ClientTransceiver::SetVariableValue()
{
}
void ClientTransceiver::StepOver()
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("TRX Sending StepOver Request %s", m_currentTarget.GetDisplayName());
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_currentTarget, Message::StepOverRequest());
}
void ClientTransceiver::TargetJoinedNetwork(AzFramework::TargetInfo info)
{
auto isConnectable = IsTargetConnectable(info);
if (isConnectable.IsSuccess())
{
m_networkTargets.emplace(info.GetNetworkId(), info);
ServiceNotificationsBus::Broadcast(&ServiceNotifications::BecameUnavailable, Target(info));
}
}
void ClientTransceiver::TargetLeftNetwork(AzFramework::TargetInfo info)
{
bool eventNeeded = false;
if (info.GetNetworkId() == m_currentTarget.GetNetworkId())
{
CleanupConnection();
eventNeeded = true;
}
else
{
auto iter = m_networkTargets.find(info.GetNetworkId());
if (iter != m_networkTargets.end())
{
m_networkTargets.erase(iter);
eventNeeded = true;
}
}
if (eventNeeded)
{
ServiceNotificationsBus::Broadcast(&ServiceNotifications::BecameUnavailable, Target(info));
}
}
void ClientTransceiver::Visit(Message::AvailableScriptTargetsResult& notification)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("received AvailableScriptTargetsResult!");
ServiceNotificationsBus::Broadcast(&ServiceNotifications::GetAvailableScriptTargetResult, notification.m_payload);
}
void ClientTransceiver::Visit(Message::ActiveEntitiesResult& notification)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("received ActiveEntitiesResult!");
ServiceNotificationsBus::Broadcast(&ServiceNotifications::GetActiveEntitiesResult, notification.m_payload);
}
void ClientTransceiver::Visit(Message::ActiveGraphsResult& notification)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("received ActiveGraphsResult!");
ServiceNotificationsBus::Broadcast(&ServiceNotifications::GetActiveGraphsResult, notification.m_payload);
}
void ClientTransceiver::Visit(Message::AnnotateNode& notification)
{
ServiceNotificationsBus::Broadcast(&ServiceNotifications::AnnotateNode, notification.m_payload);
}
void ClientTransceiver::Visit(Message::BreakpointAdded& notification)
{
BreakpointAdded(notification.m_breakpoint);
}
void ClientTransceiver::Visit(Message::BreakpointHit& notification)
{
BreakpointAdded(notification.m_breakpoint);
ServiceNotificationsBus::Broadcast(&ServiceNotifications::BreakPointHit, notification.m_breakpoint);
}
void ClientTransceiver::Visit(Message::Connected& notification)
{
if (notification.m_target.m_info.IsIdentityEqualTo(m_currentTarget))
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("Neat. we're connected");
ServiceNotificationsBus::Broadcast(&ServiceNotifications::Connected, notification.m_target);
}
else
{
AZ_Warning("ScriptCanvas Debugger", false, "Received connection notification, but targets did not match");
}
}
void ClientTransceiver::Visit([[maybe_unused]] Message::Disconnected& notification)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("Disconnect Notification Received");
ServiceNotificationsBus::Broadcast(&ServiceNotifications::Disconnected);
CleanupConnection();
if (m_resetDesiredTarget)
{
m_resetDesiredTarget = false;
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SetDesiredTargetInfo, m_previousDesiredInfo);
m_currentTarget = AzFramework::TargetInfo();
}
}
void ClientTransceiver::Visit([[maybe_unused]] Message::Continued& notification)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("received continue notification!");
Target connectedTarget;
connectedTarget.m_info = m_currentTarget;
ServiceNotificationsBus::Broadcast(&ServiceNotifications::Continued, connectedTarget);
}
void ClientTransceiver::Visit(Message::GraphActivated& notification)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("received GraphActivated! %s", notification.m_payload.ToString().data());
ServiceNotificationsBus::Broadcast(&ServiceNotifications::GraphActivated, notification.m_payload);
}
void ClientTransceiver::Visit(Message::GraphDeactivated& notification)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("received GraphDeactivated! %s", notification.m_payload.ToString().data());
ServiceNotificationsBus::Broadcast(&ServiceNotifications::GraphDeactivated, notification.m_payload);
}
void ClientTransceiver::Visit(Message::SignaledInput& notification)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("received input signal notification! %s", notification.m_signal.ToString().data());
ServiceNotificationsBus::Broadcast(&ServiceNotifications::SignaledInput, notification.m_signal);
}
void ClientTransceiver::Visit(Message::SignaledOutput& notification)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("received output signal notification! %s", notification.m_signal.ToString().data());
ServiceNotificationsBus::Broadcast(&ServiceNotifications::SignaledOutput, notification.m_signal);
}
void ClientTransceiver::Visit(Message::VariableChanged& notification)
{
SCRIPT_CANVAS_DEBUGGER_TRACE_CLIENT("received variable change notification! %s", notification.m_variableChange.ToString().data());
ServiceNotificationsBus::Broadcast(&ServiceNotifications::VariableChanged, notification.m_variableChange);
}
void ClientTransceiver::OnSystemTick()
{
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_currentTarget, Message::AddTargetsRequest(m_addCache));
m_connectionState.Merge(m_addCache);
m_addCache.Clear();
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_currentTarget, Message::RemoveTargetsRequest(m_removeCache));
m_connectionState.Remove(m_removeCache);
m_removeCache.Clear();
AZ::SystemTickBus::Handler::BusDisconnect();
}
void ClientTransceiver::StartEditorSession()
{
if (!m_currentTarget.IsValid())
{
m_resetDesiredTarget = true;
AzFramework::TargetManager::Bus::BroadcastResult(m_previousDesiredInfo, &AzFramework::TargetManager::GetDesiredTarget);
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SetDesiredTargetInfo, m_selfTarget);
}
}
void ClientTransceiver::StopEditorSession()
{
if (m_resetDesiredTarget)
{
DisconnectFromTarget();
}
}
void ClientTransceiver::StartLogging(ScriptTarget& initialTargets)
{
m_connectionState.m_logExecution = true;
m_connectionState.Clear();
m_connectionState.Merge(initialTargets);
if (m_currentTarget.IsValid())
{
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_currentTarget, Message::StartLoggingRequest(initialTargets));
}
}
void ClientTransceiver::StopLogging()
{
AzFramework::TargetManager::Bus::Broadcast(&AzFramework::TargetManager::SendTmMessage, m_currentTarget, Message::StopLoggingRequest());
m_connectionState.m_logExecution = false;
m_connectionState.Clear();
}
void ClientTransceiver::AddEntityLoggingTarget(const AZ::EntityId& entityId, const ScriptCanvas::GraphIdentifier& graphIdentifier)
{
auto insertResult = m_addCache.m_entities.insert(entityId);
auto addCacheIter = insertResult.first;
addCacheIter->second.insert(graphIdentifier);
auto removeCacheIter = m_removeCache.m_entities.find(entityId);
if (removeCacheIter != m_removeCache.m_entities.end())
{
removeCacheIter->second.erase(graphIdentifier);
}
if (!AZ::SystemTickBus::Handler::BusIsConnected())
{
AZ::SystemTickBus::Handler::BusConnect();
}
}
void ClientTransceiver::RemoveEntityLoggingTarget(const AZ::EntityId& entityId, const ScriptCanvas::GraphIdentifier& graphIdentifier)
{
auto insertResult = m_removeCache.m_entities.insert(entityId);
auto removeCacheIter = insertResult.first;
removeCacheIter->second.insert(graphIdentifier);
auto addCacheIter = m_addCache.m_entities.find(entityId);
if (addCacheIter != m_addCache.m_entities.end())
{
addCacheIter->second.erase(graphIdentifier);
}
if (!AZ::SystemTickBus::Handler::BusIsConnected())
{
AZ::SystemTickBus::Handler::BusConnect();
}
}
void ClientTransceiver::AddGraphLoggingTarget(const AZ::Data::AssetId& assetId)
{
m_addCache.m_graphs.insert(assetId);
m_removeCache.m_graphs.erase(assetId);
if (!AZ::SystemTickBus::Handler::BusIsConnected())
{
AZ::SystemTickBus::Handler::BusConnect();
}
}
void ClientTransceiver::RemoveGraphLoggingTarget(const AZ::Data::AssetId& assetId)
{
m_addCache.m_graphs.erase(assetId);
m_removeCache.m_graphs.insert(assetId);
if (!AZ::SystemTickBus::Handler::BusIsConnected())
{
AZ::SystemTickBus::Handler::BusConnect();
}
}
}
}