PythonProxyObject.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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. #pragma once
  9. #include <AzCore/Memory/Memory.h>
  10. #include <AzCore/RTTI/BehaviorContext.h>
  11. #include <AzCore/RTTI/RTTI.h>
  12. #include <AzCore/std/optional.h>
  13. #include <EditorPythonBindings/PythonCommon.h>
  14. #include <pybind11/pybind11.h>
  15. namespace EditorPythonBindings
  16. {
  17. //! Wraps an instance of a Behavior Class that is flagged for 'Editor'
  18. class PythonProxyObject final
  19. {
  20. public:
  21. AZ_TYPE_INFO(PythonProxyObject, "{448A4480-CCA8-4F14-9F17-41B0491F9FD1}");
  22. AZ_CLASS_ALLOCATOR(PythonProxyObject, AZ::SystemAllocator);
  23. PythonProxyObject() = default;
  24. explicit PythonProxyObject(const AZ::TypeId& typeId);
  25. explicit PythonProxyObject(const char* typeName);
  26. explicit PythonProxyObject(const AZ::BehaviorObject& object);
  27. ~PythonProxyObject();
  28. //! Gets the AZ RTTI type of the BehaviorObject
  29. AZStd::optional<AZ::TypeId> GetWrappedType() const;
  30. //! Returns the wrapped behavior object pointer if it is valid
  31. AZStd::optional<AZ::BehaviorObject*> GetBehaviorObject();
  32. //! Gets the name of the type of the wrapped BehaviorObject
  33. const char* GetWrappedTypeName() const;
  34. //! Assigns a value to a property (by name) a value; the types must match
  35. void SetPropertyValue(const char* propertyName, pybind11::object value);
  36. //! Gets the value or callable held by a property of a wrapped BehaviorObject
  37. pybind11::object GetPropertyValue(const char* attributeName);
  38. //! Creates a default constructed instance a 'typeName'
  39. bool SetByTypeName(const char* typeName);
  40. //! Invokes a method by name on a wrapped BehaviorObject
  41. pybind11::object Invoke(const char* methodName, pybind11::args pythonArgs);
  42. //! Constructs a BehaviorClass using Python arguments
  43. pybind11::object Construct(const AZ::BehaviorClass& behaviorClass, pybind11::args args);
  44. //! Performs an equality operation to compare this object with another object
  45. bool DoEqualityEvaluation(pybind11::object pythonOther);
  46. pybind11::object ToJson();
  47. //! Perform a comparison of a Python operator
  48. enum class Comparison
  49. {
  50. LessThan,
  51. LessThanOrEquals,
  52. GreaterThan,
  53. GreaterThanOrEquals
  54. };
  55. bool DoComparisonEvaluation(pybind11::object pythonOther, Comparison comparison);
  56. //! Gets the wrapped object's __repr__
  57. pybind11::object GetWrappedObjectRepr();
  58. //! Gets the wrapped object's __str__
  59. pybind11::object GetWrappedObjectStr();
  60. //! Gets the wrapped object's __hash__
  61. pybind11::ssize_t GetWrappedObjectHash();
  62. protected:
  63. void PrepareWrappedObject(const AZ::BehaviorClass& behaviorClass);
  64. void ReleaseWrappedObject();
  65. bool CreateDefault(const AZ::BehaviorClass* behaviorClass);
  66. void PopulateMethodsAndProperties(const AZ::BehaviorClass& behaviorClass);
  67. void PopulateComparisonOperators(const AZ::BehaviorClass& behaviorClass);
  68. bool CanConvertPythonToBehaviorValue(const AZ::BehaviorParameter& behaviorArg, pybind11::object pythonArg) const;
  69. private:
  70. enum class Ownership
  71. {
  72. None,
  73. Owned,
  74. Released
  75. };
  76. AZ::BehaviorObject m_wrappedObject;
  77. AZStd::string m_wrappedObjectTypeName;
  78. AZStd::string m_wrappedObjectCachedRepr;
  79. Ownership m_ownership = Ownership::None;
  80. AZStd::unordered_map<AZ::Crc32, AZ::BehaviorMethod*> m_methods;
  81. AZStd::unordered_map<AZ::Crc32, AZ::BehaviorProperty*> m_properties;
  82. };
  83. namespace PythonProxyObjectManagement
  84. {
  85. //! Creates the 'azlmbr.object' module so that Python script developers can manage proxy objects
  86. void CreateSubmodule(pybind11::module parentModule, pybind11::module defaultModule);
  87. //! Creates a Python object storing a BehaviorObject backed by a BehaviorClass
  88. pybind11::object CreatePythonProxyObject(const AZ::TypeId& typeId, void* data);
  89. //! Checks if function can be reflected as a class member method
  90. bool IsMemberLike(const AZ::BehaviorMethod& method, const AZ::TypeId& typeId);
  91. }
  92. }
  93. namespace pybind11
  94. {
  95. namespace detail
  96. {
  97. //! Type caster specialization PythonProxyObject to convert between Python <-> AZ Reflection
  98. template <>
  99. struct type_caster<EditorPythonBindings::PythonProxyObject>
  100. : public type_caster_base<EditorPythonBindings::PythonProxyObject>
  101. {
  102. public:
  103. // Conversion (Python -> C++)
  104. bool load(handle src, bool convert)
  105. {
  106. return type_caster_base<EditorPythonBindings::PythonProxyObject>::load(src, convert);
  107. }
  108. // Conversion (C++ -> Python)
  109. static handle cast(const EditorPythonBindings::PythonProxyObject* src, return_value_policy policy, handle parent)
  110. {
  111. return type_caster_base<EditorPythonBindings::PythonProxyObject>::cast(src, policy, parent);
  112. }
  113. };
  114. }
  115. }