Files
o3de/Gems/ScriptEvents/Code/Include/ScriptEvents/Internal/BehaviorContextBinding/DefaultEventHandler.cpp
T
Steve Pham b4a2edec6a Final update copyright headers to reference license files at the repo root (#1693)
* Final update copyright headers to reference license files at the repo root

Signed-off-by: spham <spham@amazon.com>

* Fix copyright validator unit tests to support the stale O3DE header scenario

Signed-off-by: spham <spham@amazon.com>
2021-06-30 19:51:55 -07:00

151 lines
6.4 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 "precompiled.h"
#include "DefaultEventHandler.h"
#include <ScriptEvents/ScriptEventsBus.h>
#include <ScriptEvents/ScriptEventDefinition.h>
#include <ScriptEvents/Internal/VersionedProperty.h>
#include "ScriptEventsBindingBus.h"
namespace ScriptEvents
{
DefaultBehaviorHandler::~DefaultBehaviorHandler()
{
Disconnect();
}
DefaultBehaviorHandler::DefaultBehaviorHandler(AZ::BehaviorEBus* ebus, const ScriptEvents::ScriptEvent* scriptEventDefinition)
: m_ebus(ebus)
{
m_busNameId = AZ::Uuid::CreateName(m_ebus->m_name.c_str());
for (const auto& eventPair : m_ebus->m_events)
{
auto* event = (eventPair.second.m_event != nullptr) ? eventPair.second.m_event : eventPair.second.m_broadcast;
if (event)
{
AZ::BehaviorEBusHandler::BusForwarderEvent eventForwarder;
eventForwarder.m_name = event->m_name.c_str();
eventForwarder.m_parameters.push_back(*event->GetResult());
// If a definition is provided, for each method check all the versions until we find the one that matches.
// This is necessary because we need to use the versioned property's ID as the m_eventId of the forwarder
// for Script Canvas.
if (scriptEventDefinition)
{
for (auto& method : scriptEventDefinition->GetMethods())
{
AZStd::string name = method.GetName();
if (name.compare(event->m_name) == 0)
{
// We need the of this property as they will all have the same ID.
eventForwarder.m_eventId = AZ::Crc32(method.GetNameProperty().GetId().ToString<AZStd::string>().c_str());
}
else
{
// If the event name doesn't match the current version, check all other versions.
for (const auto& version : method.GetNameProperty().GetVersions())
{
AZStd::string versionName;
if (version.Get<AZStd::string>(versionName))
{
if (versionName.compare(event->m_name) == 0)
{
// We need the ID of any version of this property as they will all have the same ID.
eventForwarder.m_eventId = AZ::Crc32(version.GetId().ToString<AZStd::string>().c_str());
}
}
}
}
}
}
// As a fallback, we'll use the Crc32 of the event name
if (eventForwarder.m_eventId == AZ::Crc32())
{
eventForwarder.m_eventId = AZ::Crc32(event->m_name.c_str());
}
// this extra parameter is only needed for broadcast only buses
bool isAddressable = Types::IsAddressableType(m_ebus->m_idParam.m_typeId);
if (!isAddressable)
{
eventForwarder.m_parameters.push_back(m_ebus->m_idParam);
}
size_t argumentCount = event->GetNumArguments();
for (size_t i = 0; i < argumentCount; ++i)
{
eventForwarder.m_parameters.push_back(*event->GetArgument(i));
}
eventForwarder.m_isFunctionGeneric = true;
m_events.push_back(eventForwarder);
}
}
}
int DefaultBehaviorHandler::GetFunctionIndex(const char* name) const
{
if (m_ebus->m_events.find(name) == m_ebus->m_events.end())
{
AZ_Error("Script Events", false, "No function with the name %s found.", name);
return -1;
}
return static_cast<int>(AZStd::distance(m_ebus->m_events.begin(), m_ebus->m_events.find(name)));
}
bool DefaultBehaviorHandler::Connect(AZ::BehaviorValueParameter* address)
{
if (address)
{
AZ_Assert(address->m_typeId == m_ebus->m_idParam.m_typeId, "Error EBus %s requires an address of type %s (%s), received %s (%s)",
m_ebus->m_name.c_str(), m_ebus->m_idParam.m_name, m_ebus->m_idParam.m_typeId.ToString<AZStd::string>().c_str(), address->m_name, address->m_typeId.ToString<AZStd::string>().c_str());
if (!m_address.m_value && address->m_typeId != azrtti_typeid<void>())
{
// get the behavior class for our address
const AZ::BehaviorClass* behaviorClass = AZ::BehaviorContextHelper::GetClass(address->m_typeId);
AZ_Warning("DefaultBehaviorHandler", behaviorClass, "%s is not a valid reflected class", address->m_name);
if (behaviorClass)
{
// cache a copy of the bus address for invoking events
static_cast<AZ::BehaviorParameter&>(m_address) = m_ebus->m_idParam;
m_address.m_value = behaviorClass->Allocate();
behaviorClass->m_cloner(m_address.m_value, address->m_value, nullptr);
}
}
}
Internal::BindingRequestBus::Event(m_busNameId, &Internal::BindingRequest::Connect, &m_address, this);
return true;
}
void DefaultBehaviorHandler::Disconnect()
{
Internal::BindingRequestBus::Event(m_busNameId, &Internal::BindingRequest::Disconnect, &m_address, this);
if (m_address.m_value)
{
const AZ::BehaviorClass* behaviorClass = AZ::BehaviorContextHelper::GetClass(m_address.m_typeId);
AZ_Assert(behaviorClass, "Did not find class %s when disconnecting DefaultBehaviorHandler", m_ebus->m_name.c_str());
behaviorClass->m_destructor(m_address.m_value, behaviorClass->m_userData);
behaviorClass->Deallocate(m_address.m_value);
m_address.m_value = nullptr;
}
}
}