/* * 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 "LmbrCentral_precompiled.h" #include "Events/ReflectScriptableEvents.h" #include #include #include #include #include #include #include #include #include #include #include namespace LmbrCentral { /// BahaviorContext forwarder for FloatGameplayNotificationBus class BehaviorInputEventNotificationBusHandler : public AZ::InputEventNotificationBus::Handler, public AZ::BehaviorEBusHandler { public: AZ_EBUS_BEHAVIOR_BINDER(BehaviorInputEventNotificationBusHandler, "{8AAEEB1A-21E2-4D2E-A719-73552D41F506}", AZ::SystemAllocator, OnPressed, OnHeld, OnReleased); void OnPressed(float value) override { Call(FN_OnPressed, value); } void OnHeld(float value) override { Call(FN_OnHeld, value); } void OnReleased(float value) override { Call(FN_OnReleased, value); } }; /// BahaviorContext forwarder for FloatGameplayNotificationBus class BehaviorGameplayNotificationBusHandler : public AZ::GameplayNotificationBus::Handler, public AZ::BehaviorEBusHandler { public: AZ_EBUS_BEHAVIOR_BINDER(BehaviorGameplayNotificationBusHandler, "{227DCFE6-B527-4FED-8A4D-5D723B07EAA5}", AZ::SystemAllocator, OnEventBegin, OnEventUpdating, OnEventEnd); void OnEventBegin(const AZStd::any& value) override { Call(FN_OnEventBegin, value); } void OnEventUpdating(const AZStd::any& value) override { Call(FN_OnEventUpdating, value); } void OnEventEnd(const AZStd::any& value) override { Call(FN_OnEventEnd, value); } }; class MathUtils { public: AZ_TYPE_INFO(MathUtils, "{BB7F7465-B355-4435-BB9D-44D8F586EE8B}"); AZ_CLASS_ALLOCATOR(MathUtils, AZ::SystemAllocator, 0); MathUtils() = default; ~MathUtils() = default; }; class AxisWrapper { public: AZ_TYPE_INFO(AxisWrapper, "{86817913-7D0C-4883-8EDC-2B0DE643392B}"); AZ_CLASS_ALLOCATOR(AxisWrapper, AZ::SystemAllocator, 0); AxisWrapper() = default; ~AxisWrapper() = default; }; void InputEventNonIntrusiveConstructor(AZ::InputEventNotificationId* thisOutPtr, AZ::ScriptDataContext& dc) { if (dc.GetNumArguments() == 0) { // Use defaults. } else if (dc.GetNumArguments() == 1 && dc.IsString(0)) { thisOutPtr->m_localUserId = AzFramework::LocalUserIdAny; const char* actionName = nullptr; dc.ReadArg(0, actionName); thisOutPtr->m_actionNameCrc = Input::ProcessedEventName(actionName); } else if (dc.GetNumArguments() == 2 && dc.IsClass(0) && dc.IsString(1)) { AzFramework::LocalUserId localUserId = 0; dc.ReadArg(0, localUserId); thisOutPtr->m_localUserId = localUserId; const char* actionName = nullptr; dc.ReadArg(1, actionName); thisOutPtr->m_actionNameCrc = Input::ProcessedEventName(actionName); } else { AZ_Error("InputEventNotificationId", false, "The InputEventNotificationId takes one or two args. 1 argument: a string representing the input events name (determined by the event group). 2 arguments: a Crc of the profile channel, and a string representing the input event's name"); } } void GameplayEventIdNonIntrusiveConstructor(AZ::GameplayNotificationId* outData, AZ::ScriptDataContext& dc) { static const int s_channelIndex = 0; static const int s_actionNameIndex = 1; static const int s_payloadTypeIndex = 2; static const int s_defaultConstructorArgCount = 0; static const int s_deprecatedConstructorArgCount = 2; static const int s_verboseConstructorArgCount = 3; static const bool s_showCallStack = true; if (dc.GetNumArguments() == s_defaultConstructorArgCount) { // Use defaults. outData->m_channel.SetInvalid(); outData->m_actionNameCrc = 0; outData->m_payloadTypeId = AZ::Uuid::CreateNull(); } else if (dc.GetNumArguments() == s_deprecatedConstructorArgCount && dc.IsClass(s_channelIndex) && dc.IsString(s_actionNameIndex)) { AZ::EntityId channel(0); dc.ReadArg(s_channelIndex, channel); outData->m_channel = channel; const char* actionName = nullptr; dc.ReadArg(s_actionNameIndex, actionName); outData->m_actionNameCrc = AZ_CRC(actionName); outData->m_payloadTypeId = AZ::Uuid::CreateNull(); AZ::ScriptContext::FromNativeContext(dc.GetNativeContext())->Error( AZ::ScriptContext::ErrorType::Warning, s_showCallStack, "This constructor has been deprecated. Please add the name of the type you wish to send/receive, example \"float\"" ); } else if (dc.GetNumArguments() == s_verboseConstructorArgCount && dc.IsClass(s_channelIndex) && (dc.IsString(s_actionNameIndex) || dc.IsClass(s_actionNameIndex)) && (dc.IsString(s_payloadTypeIndex) || dc.IsClass(s_payloadTypeIndex) || dc.IsClass(s_payloadTypeIndex))) { dc.ReadArg(s_channelIndex, outData->m_channel); if (dc.IsString(s_actionNameIndex)) { const char* actionName = nullptr; dc.ReadArg(s_actionNameIndex, actionName); outData->m_actionNameCrc = AZ_CRC(actionName); } else { dc.ReadArg(s_actionNameIndex, outData->m_actionNameCrc); } if (dc.IsClass(s_payloadTypeIndex)) { dc.ReadArg(s_payloadTypeIndex, outData->m_payloadTypeId); } else { AZ::BehaviorContext* behaviorContext = nullptr; AZ::ComponentApplicationBus::BroadcastResult(behaviorContext, &AZ::ComponentApplicationBus::Events::GetBehaviorContext); const char* payloadClassName = nullptr; if (dc.IsString(s_payloadTypeIndex)) { dc.ReadArg(s_payloadTypeIndex, payloadClassName); // Specifically handling float for gameplay event bus support. // LuaNumber is a double, so typeid(1) will return double, and fundamental numerics are not exposed to BehaviorContext. // This is case sensitive since it is possible to have float and Float and FlOaT, etc. if (strcmp(payloadClassName, "float") == 0) { outData->m_payloadTypeId = AZ::AzTypeInfo::Uuid(); } else { auto&& behaviorClassIterator = behaviorContext->m_classes.find(payloadClassName); if (behaviorClassIterator != behaviorContext->m_classes.end()) { outData->m_payloadTypeId = behaviorClassIterator->second->m_typeId; } else { AZ::ScriptContext::FromNativeContext(dc.GetNativeContext())->Error( AZ::ScriptContext::ErrorType::Warning, s_showCallStack, "Class \"%s\" not found in behavior context. Ensure your type is reflected to behavior context or consider using typeid(type).", payloadClassName ); } } } else { AZ::Crc32 requestedCrc; dc.ReadArg(s_payloadTypeIndex, requestedCrc); AZ::ScriptContext::FromNativeContext(dc.GetNativeContext())->Error( AZ::ScriptContext::ErrorType::Warning, s_showCallStack, "Constructing a GameplayNotificationId with a Crc32 for payload type is expensive. Consider using string name or typeid instead." ); for (auto&& behaviorClassPair : behaviorContext->m_classes) { AZ::Crc32 currentBehaviorClassCrc = AZ::Crc32(behaviorClassPair.first.c_str()); if (currentBehaviorClassCrc == requestedCrc) { outData->m_payloadTypeId = behaviorClassPair.second->m_typeId; } } } } } else { AZ::ScriptContext::FromNativeContext(dc.GetNativeContext())->Error( AZ::ScriptContext::ErrorType::Error, s_showCallStack, "The GameplayNotificationId takes 3 arguments: an entityId representing the channel, a string or crc representing the action's name, and a string or uuid for the type" ); } } void ReflectScriptableEvents::Reflect(AZ::ReflectContext* context) { if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() ->Version(1) ->Field("Channel", &AZ::GameplayNotificationId::m_channel) ->Field("ActionName", &AZ::GameplayNotificationId::m_actionNameCrc) ->Field("PayloadType", &AZ::GameplayNotificationId::m_payloadTypeId) ; serializeContext->Class() ->Version(1) ->Field("LocalUserId", &AZ::InputEventNotificationId::m_localUserId) ->Field("ActionName", &AZ::InputEventNotificationId::m_actionNameCrc) ; } ShapeComponentConfig::Reflect(context); if (auto behaviorContext = azrtti_cast(context)) { behaviorContext->Class("GameplayNotificationId") ->Attribute(AZ::Script::Attributes::Deprecated, true) ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview) ->Constructor() ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) ->Attribute(AZ::Script::Attributes::ConstructorOverride, &GameplayEventIdNonIntrusiveConstructor) ->Property("actionNameCrc", BehaviorValueProperty(&AZ::GameplayNotificationId::m_actionNameCrc)) ->Property("channel", BehaviorValueProperty(&AZ::GameplayNotificationId::m_channel)) ->Property("payloadTypeId", BehaviorValueProperty(&AZ::GameplayNotificationId::m_payloadTypeId)) ->Method("ToString", &AZ::GameplayNotificationId::ToString) ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString) ->Method("Equal", &AZ::GameplayNotificationId::operator==) ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Equal) ->Method("Clone", &AZ::GameplayNotificationId::Clone); behaviorContext->Class("InputEventNotificationId") ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview) ->Constructor() ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) ->Attribute(AZ::Script::Attributes::ConstructorOverride, &InputEventNonIntrusiveConstructor) ->Property("actionNameCrc", BehaviorValueProperty(&AZ::InputEventNotificationId::m_actionNameCrc)) ->Property("localUserId", BehaviorValueProperty(&AZ::InputEventNotificationId::m_localUserId)) ->Method("ToString", &AZ::InputEventNotificationId::ToString) ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString) ->Method("Equal", &AZ::InputEventNotificationId::operator==) ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Equal) ->Method("Clone", &AZ::InputEventNotificationId::Clone) ->Property("actionName", nullptr, [](AZ::InputEventNotificationId* thisPtr, AZStd::string_view value) { *thisPtr = AZ::InputEventNotificationId(value.data()); }) ->Method("CreateInputEventNotificationId", [](AzFramework::LocalUserId localUserId, AZStd::string_view value) -> AZ::InputEventNotificationId { return AZ::InputEventNotificationId(localUserId, value.data()); }, { { { "localUserId", "Local User ID" }, { "actionName", "The name of the Input event action used to create an InputEventNotificationId" } } }); behaviorContext->EBus("GameplayNotificationBus") ->Attribute(AZ::Script::Attributes::Deprecated, true) ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::List) ->Handler() ->Event("OnEventBegin", &AZ::GameplayNotificationBus::Events::OnEventBegin) ->Event("OnEventUpdating", &AZ::GameplayNotificationBus::Events::OnEventUpdating) ->Event("OnEventEnd", &AZ::GameplayNotificationBus::Events::OnEventEnd); behaviorContext->Class("AxisType") ->Constant("XPositive", BehaviorConstant(AZ::Transform::Axis::XPositive)) ->Constant("XNegative", BehaviorConstant(AZ::Transform::Axis::XNegative)) ->Constant("YPositive", BehaviorConstant(AZ::Transform::Axis::YPositive)) ->Constant("YNegative", BehaviorConstant(AZ::Transform::Axis::YNegative)) ->Constant("ZPositive", BehaviorConstant(AZ::Transform::Axis::ZPositive)) ->Constant("ZNegative", BehaviorConstant(AZ::Transform::Axis::ZNegative)); behaviorContext->Class("MathUtils") ->Method("ConvertTransformToEulerDegrees", &AZ::ConvertTransformToEulerDegrees) ->Method("ConvertTransformToEulerRadians", &AZ::ConvertTransformToEulerRadians) ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) ->Method("ConvertEulerDegreesToTransform", &AZ::ConvertEulerDegreesToTransform) ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) ->Method("ConvertEulerDegreesToTransformPrecise", &AZ::ConvertEulerDegreesToTransformPrecise) ->Method("ConvertQuaternionToEulerDegrees", &AZ::ConvertQuaternionToEulerDegrees) ->Method("ConvertQuaternionToEulerRadians", &AZ::ConvertQuaternionToEulerRadians) ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) ->Method("ConvertEulerRadiansToQuaternion", &AZ::ConvertEulerRadiansToQuaternion) ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) ->Method("ConvertEulerDegreesToQuaternion", &AZ::ConvertEulerDegreesToQuaternion) ->Method("CreateLookAt", &AZ::Transform::CreateLookAt); ShapeComponentGeneric::Reflect(behaviorContext); behaviorContext->EBus("InputEventNotificationBus") ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview) ->Handler() ->Event("OnPressed", &AZ::InputEventNotificationBus::Events::OnPressed) ->Event("OnHeld", &AZ::InputEventNotificationBus::Events::OnHeld) ->Event("OnReleased", &AZ::InputEventNotificationBus::Events::OnReleased); behaviorContext->EBus("InputRequestBus") ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview) ->Event("PushContext", &AZ::InputRequestBus::Events::PushContext) ->Event("PopContext", &AZ::InputRequestBus::Events::PopContext) ->Event("PopAllContexts", &AZ::InputRequestBus::Events::PopAllContexts) ->Event("GetCurrentContext", &AZ::InputRequestBus::Events::GetCurrentContext); } } }