ScriptEventsMethod.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "ScriptEvents/ScriptEventsMethod.h"
  9. #include <AzCore/RTTI/BehaviorContext.h>
  10. #include <AzCore/Serialization/SerializeContext.h>
  11. #include <AzCore/std/string/regex.h>
  12. namespace ScriptEvents
  13. {
  14. void Method::FromScript(AZ::ScriptDataContext& dc)
  15. {
  16. if (dc.GetNumArguments() > 0)
  17. {
  18. AZStd::string name;
  19. if (dc.IsString(0) && dc.ReadArg(0, name))
  20. {
  21. m_name.Set(name.c_str());
  22. }
  23. if (dc.GetNumArguments() > 1)
  24. {
  25. AZ::Uuid returnType;
  26. if (dc.ReadArg(1, returnType))
  27. {
  28. m_returnType.Set(returnType);
  29. }
  30. }
  31. }
  32. // AZ_TracePrintf("Script Events", "Added Script Method: %s (return type: %s)\n", GetName().c_str(), m_returnType.IsEmpty() ? "none"
  33. // : GetReturnType().ToString<AZStd::string>().c_str());
  34. }
  35. void Method::Reflect(AZ::ReflectContext* context)
  36. {
  37. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  38. {
  39. serializeContext->Class<Method>()
  40. ->Field("m_name", &Method::m_name)
  41. ->Field("m_tooltip", &Method::m_tooltip)
  42. ->Field("m_returnType", &Method::m_returnType)
  43. ->Field("m_parameters", &Method::m_parameters);
  44. if (AZ::EditContext* editContext = serializeContext->GetEditContext())
  45. {
  46. editContext->Class<Method>("Script Event", "A script event's definition")
  47. ->DataElement(
  48. AZ::Edit::UIHandlers::Default, &Method::m_name, "Name",
  49. "The specified name for this event, represents a callable function (i.e. MyScriptEvent())")
  50. ->DataElement(AZ::Edit::UIHandlers::Default, &Method::m_tooltip, "Tooltip", "A description of this event")
  51. ->DataElement(
  52. AZ::Edit::UIHandlers::ComboBox, &Method::m_returnType, "Return value type",
  53. "the typeid of the return value, ex. AZ::type_info<int>::Uuid foo()")
  54. ->Attribute(AZ::Edit::Attributes::GenericValueList, &Types::GetValidReturnTypes)
  55. ->DataElement(
  56. AZ::Edit::UIHandlers::Default, &Method::m_parameters, "Parameters",
  57. "A list of parameters for the EBus event, ex. void foo(Parameter1, Parameter2)");
  58. }
  59. }
  60. if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  61. {
  62. behaviorContext->Class<Method>("Method")
  63. ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
  64. ->Method("AddParameter", &Method::AddParameter)
  65. ->Property("Name", BehaviorValueProperty(&Method::m_name))
  66. ->Property("ReturnType", BehaviorValueProperty(&Method::m_returnType))
  67. ->Property("Parameters", BehaviorValueProperty(&Method::m_parameters));
  68. }
  69. }
  70. AZ::Outcome<bool, AZStd::string> Method::Validate() const
  71. {
  72. const AZStd::string name = GetName();
  73. const AZ::Uuid returnType = GetReturnType();
  74. // Validate address type
  75. if (!Types::IsValidReturnType(returnType))
  76. {
  77. return AZ::Failure(AZStd::string::format(
  78. "The specified type %s is not valid as return type for Script Event: %s", returnType.ToString<AZStd::string>().c_str(),
  79. name.c_str()));
  80. }
  81. // Definition name cannot be empty
  82. if (name.empty())
  83. {
  84. return AZ::Failure(AZStd::string("Definition name cannot be empty"));
  85. }
  86. // Name cannot start with a number
  87. if (isdigit(name.at(0)))
  88. {
  89. return AZ::Failure(AZStd::string::format("%s, names cannot start with a number", name.c_str()));
  90. }
  91. // Conform to valid function names
  92. AZStd::smatch match;
  93. // Ascii-only
  94. AZStd::regex asciionly_regex("[^\x0A\x0D\x20-\x7E]");
  95. AZStd::regex_match(name, match, asciionly_regex);
  96. if (!match.empty())
  97. {
  98. return AZ::Failure(AZStd::string::format("%s, invalid name, names may only contain ASCII characters", name.c_str()));
  99. }
  100. AZStd::regex validate_regex("[_[:alpha:]][_[:alnum:]]*");
  101. AZStd::regex_match(name, match, validate_regex);
  102. if (match.empty())
  103. {
  104. return AZ::Failure(AZStd::string::format("%s, invalid name specified", name.c_str()));
  105. }
  106. AZStd::string parameterName;
  107. int parameterIndex = 0;
  108. for (const Parameter& parameter : m_parameters)
  109. {
  110. auto outcome = parameter.Validate();
  111. if (!outcome.IsSuccess())
  112. {
  113. return outcome;
  114. }
  115. int duplicateCount = 0;
  116. for (auto item = m_parameters.begin(); item != m_parameters.end(); item++)
  117. {
  118. if (item->GetName().compare(parameterName) == 0)
  119. {
  120. duplicateCount++;
  121. }
  122. if (duplicateCount > 1)
  123. {
  124. return AZ::Failure(AZStd::string::format(
  125. "Cannot have duplicate parameter names (%d: %s) make sure each parameter name is unique",
  126. parameterIndex,
  127. parameterName.c_str()));
  128. }
  129. }
  130. parameterName = parameter.GetName();
  131. ++parameterIndex;
  132. }
  133. return AZ::Success(true);
  134. }
  135. void Method::PreSave()
  136. {
  137. m_name.PreSave();
  138. m_tooltip.PreSave();
  139. m_returnType.PreSave();
  140. for (Parameter parameter : m_parameters)
  141. {
  142. parameter.PreSave();
  143. }
  144. }
  145. void Method::Flatten()
  146. {
  147. m_name.Flatten();
  148. m_tooltip.Flatten();
  149. m_returnType.Flatten();
  150. for (Parameter& parameter : m_parameters)
  151. {
  152. parameter.Flatten();
  153. }
  154. }
  155. } // namespace ScriptEvents