C12712453_ScriptCanvas_MultipleRaycastNode.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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. SPDX-License-Identifier: Apache-2.0 OR MIT
  5. """
  6. # Test case ID : C12712453
  7. # Test Case Title : Verify Raycast Multiple Node
  8. # fmt:off
  9. class Tests:
  10. enter_game_mode = ("Entered game mode", "Failed to enter game mode")
  11. exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
  12. test_completed = ("The test successfully completed", "The test timed out")
  13. # entities found
  14. caster_found = ("Caster entity found", "Caster entity NOT found")
  15. multi_target_close_found = ("Multicast close target entity found", "Multicast close target NOT found")
  16. multi_target_far_found = ("Multicast far target entity found", "Multicast far target NOT found")
  17. single_target_found = ("Single close target entity found", "Single close target NOT found")
  18. fail_entities_found = ("Found all fail entities", "Failed to find at least one fail entities")
  19. # entity results
  20. caster_result = ("Caster was activated", "Caster was NOT activated")
  21. multi_target_close_result = ("Multicast close target was hit with a ray", "Multicast close target WAS NOT hit with a ray")
  22. multi_target_far_result = ("Multicast far target was hit with a ray", "Multicast far target WAS NOT hit with a ray")
  23. single_target_result = ("Single target was hit with a ray", "Single target WAS NOT hit with a ray")
  24. # fmt:on
  25. # Lines to search for by the log monitor
  26. class Lines:
  27. # FAILURE (in all caps) is used as the failure flag for both this python script and ScriptCanvas.
  28. # If this is present in the log, something has gone fatally wrong and the test will fail.
  29. # Additional details as to why the test fails will be printed in the log accompanying this entry.
  30. unexpected = ["FAILURE"]
  31. def C12712453_ScriptCanvas_MultipleRaycastNode():
  32. """
  33. Summary:
  34. Uses script canvas to cast two types of rays in game mode (multiple raycast and single raycast). Script canvas
  35. validates the results from the raycasts, then deactivates any entities hit. This python script ensures only
  36. the expected entities were deactivated.
  37. Level Description:
  38. Caster - A sphere with gravity disabled and a scriptcanvas component for emitting raycasts. Caster starts inactive.
  39. Targets - Three spheres with gravity disabled. They are the expected targets of the raycasts.
  40. Fail Boxes - These boxes are positioned in various places where no ray should collide with them. They are set
  41. up print a fail message if any ray should hit them.
  42. ScriptCanvas - The ScriptCanvas script is attached to the Caster entity, and is set to start on entity Activation.
  43. The script will activate two different raycast nodes, a single raycast and a multiple raycast. For every raycast
  44. hit, the script validates all properties of a raycast (while printing to log) and then deactivates any entity
  45. that is [raycast] hit. This ScriptCanvas file can be found in this test's level folder named
  46. "Raycast.scrpitcanvas".
  47. Expected Behavior:
  48. The level should load and appear to instantly close. After setup the Caster sphere should emit the raycasts which
  49. should deactivate all expected Targets (via script canvas). The python script waits for the Targets to be
  50. deactivated then prints the results.
  51. Steps:
  52. 1) Load level / enter game mode
  53. 2) Retrieve entities
  54. 3) Start the test (activate the caster entity)
  55. 4) Wait for Target entities to deactivate
  56. 5) Exit game mode and close the editor
  57. :return: None
  58. """
  59. # Disabled until Script Canvas merges the new backend
  60. return
  61. import os
  62. import sys
  63. import ImportPathHelper as imports
  64. imports.init()
  65. from editor_python_test_tools.utils import Report
  66. from editor_python_test_tools.utils import TestHelper as helper
  67. import azlmbr.legacy.general as general
  68. import azlmbr.bus
  69. import azlmbr
  70. # Constants
  71. TIME_OUT = 1.0
  72. FAIL_ENTITIES = 5
  73. # Entity base class handles very general entity initialization
  74. class EntityBase:
  75. def __init__(self, name):
  76. # type: (str) -> None
  77. self.name = name
  78. self.id = general.find_game_entity(name)
  79. # Stores entity "is active" state. Most entities start as "Active"
  80. self.activated = True
  81. # Caster starts deactivated. When the caster is activated the script canvas test will begin.
  82. class Caster(EntityBase):
  83. def __init__(self, name):
  84. # type: (str) -> None
  85. EntityBase.__init__(self, name)
  86. found_tuple = Tests.__dict__[name.lower() + "_found"]
  87. Report.critical_result(found_tuple, self.id.isValid())
  88. # Caster starts as "Inactive" because the script canvas starts when Caster is Activated
  89. self.activated = False
  90. # Activates the Caster which starts it's ScriptCanvas script (and the test)
  91. def activate(self):
  92. # type: () -> None
  93. azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "ActivateGameEntity", self.id)
  94. self.activated = True
  95. Report.success(Tests.__dict__[self.name + "_result"])
  96. # Targets start activated and only get deactivated by the ScriptCanvas script.
  97. # Successful execution means every Target gets deactivated via ScriptCanvas
  98. class Target(EntityBase):
  99. def __init__(self, name):
  100. # type: (str) -> None
  101. EntityBase.__init__(self, name)
  102. found_tuple = Tests.__dict__[name.lower() + "_found"]
  103. Report.critical_result(found_tuple, self.id.isValid())
  104. self.handler = azlmbr.entity.EntityBusHandler()
  105. self.handler.connect(self.id)
  106. self.handler.add_callback("OnEntityDeactivated", self.on_deactivation)
  107. # Callback: gets called when entity is deactivated. This is expected for Target entities.
  108. def on_deactivation(self, args):
  109. # type: ([EntityId, ...]) -> None
  110. if args[0].Equal(self.id):
  111. Report.success(Tests.__dict__[self.name + "_result"])
  112. self.activated = False
  113. # Disconnects event handler.
  114. # (Needed so the deactivation callback doesn't not get called on level clean up)
  115. def disconnect(self):
  116. # type: () -> None
  117. self.handler.disconnect()
  118. self.handler = None
  119. # Failure entities start activated and get deactivated via the ScriptCanvas. Ideally none will be deactivated
  120. # during the test. If one is deactivated, and Failure message is logged that will be caught by the log monitor.
  121. class Failure(EntityBase):
  122. def __init__(self, num):
  123. # type: (int) -> None
  124. EntityBase.__init__(self, "fail_" + str(num))
  125. if not self.id.IsValid():
  126. Report.info("FAILURE: {} could not be found".format(self.name))
  127. self.handler = azlmbr.entity.EntityBusHandler()
  128. self.handler.connect(self.id)
  129. self.handler.add_callback("OnEntityDeactivated", self.on_deactivation)
  130. # Callback: gets called when entity is deactivated. This is expected for Target entities.
  131. def on_deactivation(self, args):
  132. # type: ([EntityId, ...]) -> None
  133. if args[0].Equal(self.id):
  134. Report.info("{}: FAILURE".format(self.name))
  135. self.activated = False
  136. # Disconnects event handler.
  137. # (Needed so the deactivation callback doesn't not get called on level clean up)
  138. def disconnect(self):
  139. # type: () -> None
  140. self.handler.disconnect()
  141. self.handler = None
  142. # 1) Open level
  143. helper.init_idle()
  144. helper.open_level("Physics", "C12712453_ScriptCanvas_MultipleRaycastNode")
  145. helper.enter_game_mode(Tests.enter_game_mode)
  146. # 2) Retrieve entities
  147. caster = Caster("caster")
  148. targets = [Target("multi_target_close"), Target("multi_target_far"), Target("single_target")]
  149. fails = [Failure(i) for i in range(FAIL_ENTITIES)]
  150. Report.critical_result(Tests.fail_entities_found, all(entity.id.isValid() for entity in fails))
  151. # 3) Start the test
  152. caster.activate()
  153. # 4) Wait for Target entities to deactivate
  154. test_completed = helper.wait_for_condition(lambda: all(not target.activated for target in targets), TIME_OUT)
  155. Report.result(Tests.test_completed, test_completed)
  156. # Disconnect all "on deactivated" event handlers so they don't get called implicitly on level cleanup
  157. for entity in targets + fails:
  158. entity.disconnect()
  159. # 5) Close test
  160. helper.exit_game_mode(Tests.exit_game_mode)
  161. if __name__ == "__main__":
  162. import ImportPathHelper as imports
  163. imports.init()
  164. from editor_python_test_tools.utils import Report
  165. Report.start_test(C12712453_ScriptCanvas_MultipleRaycastNode)