Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1da5ef16a8 | |||
| 57b201b0da | |||
| f8d39e2671 | |||
| 575faa4443 | |||
| 43603cad5e | |||
| bb52475ce8 | |||
| 697dfad486 | |||
| 650e1ab44d | |||
| d9cce28a53 | |||
| 486ba58628 | |||
| e7f787572e | |||
| 837e1c7370 | |||
| efcbe2c4a1 | |||
| d30de01752 |
@@ -1,5 +1,5 @@
|
||||
---
|
||||
name: Automated Review bug report
|
||||
name: ar_bug_report.md
|
||||
about: Create a bug for a an issue found in the Automated Review
|
||||
title: 'AR Bug Report'
|
||||
labels: 'needs-triage,kind/bug,kind/automation'
|
||||
|
||||
+8
-2
@@ -2,14 +2,17 @@
|
||||
.vs/
|
||||
.vscode/
|
||||
__pycache__
|
||||
AssetProcessorTemp/**
|
||||
[Bb]uild/
|
||||
[Oo]ut/**
|
||||
CMakeUserPresets.json
|
||||
[Cc]ache/
|
||||
/[Ii]nstall/
|
||||
Editor/EditorEventLog.xml
|
||||
Editor/EditorLayout.xml
|
||||
**/*egg-info/**
|
||||
**/*egg-link
|
||||
**/[Rr]estricted
|
||||
UserSettings.xml
|
||||
[Uu]ser/
|
||||
FrameCapture/**
|
||||
.DS_Store
|
||||
@@ -18,6 +21,9 @@ client*.cfg
|
||||
server*.cfg
|
||||
.mayaSwatches/
|
||||
_savebackup/
|
||||
#Output folder for test results when running Automated Tests
|
||||
TestResults/**
|
||||
*.swatches
|
||||
/imgui.ini
|
||||
|
||||
/scripts/project_manager/logs/
|
||||
/AutomatedTesting/Gem/PythonTests/scripting/TestResults
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
||||
<path d="M3.145,8.433c0-1.47,1.196-2.666,2.666-2.666h9.544c-0.158-0.819-0.88-1.443-1.744-1.443H3.487
|
||||
c-0.978,0-1.778,0.8-1.778,1.778v5.356c0,0.861,0.62,1.582,1.436,1.743V8.433z" fill="#FFFFFF"/>
|
||||
<g>
|
||||
<path d="M6.833,11.654c0-1.47,1.196-2.666,2.666-2.666h9.069c-0.158-0.819-0.88-1.443-1.744-1.443H6.7
|
||||
c-0.978,0-1.778,0.8-1.778,1.778v5.356c0,0.978,0.8,1.778,1.778,1.778h0.133V11.654z" fill="#FFFFFF"/>
|
||||
</g>
|
||||
<path d="M20.513,10.765H10.388c-0.978,0-1.778,0.8-1.778,1.777v5.356c0,0.978,0.8,1.778,1.778,1.778h10.125
|
||||
c0.978,0,1.778-0.8,1.778-1.778v-5.356C22.29,11.565,21.49,10.765,20.513,10.765z M19.332,15.967h-7.763
|
||||
c-0.264,0-0.478-0.355-0.478-0.793c0-0.438,0.214-0.793,0.478-0.793h7.763c0.264,0,0.478,0.355,0.478,0.793
|
||||
C19.81,15.612,19.597,15.967,19.332,15.967z" fill="#FFFFFF"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bfc2ef8c6dbf2fba078e27e4e94384099e090468e679327dd826a5cbf22b04ed
|
||||
size 1019
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:708b12d41229afab78e0f7d59097ae3de855fea8525a920c5c214fc0ce79f1bd
|
||||
size 1209
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fab63af9b50790dca25330058e70517987ea8bf11c00f9353dd951ebdbd1dbe5
|
||||
size 5008
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
"""
|
||||
This script loads every level in a game project and exports them. You will be prompted with the standard
|
||||
Check-Out/Overwrite/Cancel dialog for each level.
|
||||
This is useful when there is a version update to a file that requires re-exporting.
|
||||
"""
|
||||
import sys, os
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.legacy.checkout_dialog as checkout_dialog
|
||||
|
||||
|
||||
class CheckOutDialogEnableAll:
|
||||
"""
|
||||
Helper class to wrap enabling the "Apply to all" checkbox in the CheckOutDialog.
|
||||
Guarantees that the old setting will be restored.
|
||||
To use, do:
|
||||
|
||||
with CheckOutDialogEnableAll():
|
||||
# your code here
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.old_setting = False
|
||||
|
||||
def __enter__(self):
|
||||
self.old_setting = checkout_dialog.enable_for_all(True)
|
||||
print(self.old_setting)
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
checkout_dialog.enable_for_all(self.old_setting)
|
||||
|
||||
|
||||
level_list = []
|
||||
|
||||
|
||||
def is_in_special_folder(file_full_path):
|
||||
if file_full_path.find("_savebackup") >= 0:
|
||||
return True
|
||||
if file_full_path.find("_autobackup") >= 0:
|
||||
return True
|
||||
if file_full_path.find("_hold") >= 0:
|
||||
return True
|
||||
if file_full_path.find("_tmpresize") >= 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
game_folder = general.get_game_folder()
|
||||
|
||||
|
||||
# Recursively search every directory in the game project for files ending with .cry and .ly
|
||||
for root, dirs, files in os.walk(game_folder):
|
||||
for file in files:
|
||||
if file.endswith(".cry") or file.endswith(".ly"):
|
||||
# The engine expects the full path of the .cry file
|
||||
file_full_path = os.path.abspath(os.path.join(root, file))
|
||||
# Exclude files in special directories
|
||||
if not is_in_special_folder(file_full_path):
|
||||
level_list.append(file_full_path)
|
||||
|
||||
# make the checkout dialog enable the 'Apply to all' checkbox
|
||||
with CheckOutDialogEnableAll():
|
||||
|
||||
# For each valid .cry file found, open it in the editor and export it
|
||||
for level in level_list:
|
||||
if not isinstance(level, str):
|
||||
# general.open_level_no_prompt expects the file path in utf8 format
|
||||
level = level.encode("utf-8")
|
||||
|
||||
general.open_level_no_prompt(level)
|
||||
general.export_to_engine()
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
'''
|
||||
Generates a 50% lod for the selected model
|
||||
|
||||
@argument name="Lod Percentage", type="string", default="50.0f"
|
||||
'''
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
percentage = float(sys.argv[1])
|
||||
|
||||
selectedcgf = lodtools.getselected()
|
||||
selectedmaterial = lodtools.getselectedmaterial()
|
||||
|
||||
loadedmodel = lodtools.loadcgf(selectedcgf)
|
||||
loadedmaterial = lodtools.loadmaterial(selectedmaterial)
|
||||
|
||||
if loadedmodel == True and loadedmaterial == True:
|
||||
lodtools.generatelodchain()
|
||||
finished = 0.0
|
||||
while finished >= 0.0:
|
||||
finished = lodtools.generatetick()
|
||||
print 'Lod Chain Generation progress: ' + str(finished)
|
||||
time.sleep(1)
|
||||
if finished == 1.0:
|
||||
break
|
||||
|
||||
lodtools.createlod(1,percentage)
|
||||
lodtools.generatematerials(1,512,512)
|
||||
lodtools.savetextures(1)
|
||||
lodtools.savesettings()
|
||||
lodtools.reloadmodel()
|
||||
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
objects = general.get_all_objects("", "") # Get the name list of all objects in the level.
|
||||
# If there is any object with the geometry file of "objects\\default\\primitive_box.cgf",
|
||||
# change it to "objects\\default\\primitive_cube.cgf".
|
||||
for obj in objects:
|
||||
geometry_file = general.get_entity_geometry_file(obj)
|
||||
if geometry_file == "objects\\default\\primitive_box.cgf":
|
||||
general.set_entity_geometry_file(obj, "objects\\default\\primitive_cube.cgf")
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
objects = general.get_all_objects("AnimObject", "") # Get the name list of all anim objects in the level.
|
||||
general.clear_selection()
|
||||
# If there is any object with the geometry file whose name contains "\\story\\", select it
|
||||
for obj in objects:
|
||||
geometry_file = general.get_entity_geometry_file(obj)
|
||||
if geometry_file.find("\\story\\") != -1:
|
||||
general.select_object(obj)
|
||||
Executable
+508
@@ -0,0 +1,508 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
import __future__
|
||||
import time, re, os, sys, itertools, ast
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
global ctrlFile
|
||||
ctrlFile = 'setState.txt'
|
||||
global logfile
|
||||
logfile = 'Editor.log'
|
||||
|
||||
global HIDDEN_MASK_PREFIX
|
||||
HIDDEN_MASK_PREFIX= 'hidden_mask_for_'
|
||||
global HIDDEN_MASK_PREFIX_LENGTH
|
||||
HIDDEN_MASK_PREFIX_LENGTH = len(HIDDEN_MASK_PREFIX)
|
||||
|
||||
def getLogList(logfile):
|
||||
logList = [x for x in open(logfile, 'r')]
|
||||
return logList
|
||||
|
||||
def getCheckList(ctrlFile):
|
||||
try:
|
||||
with open(ctrlFile):
|
||||
stateList = open(ctrlFile, 'r')
|
||||
|
||||
except:
|
||||
open(ctrlFile, 'w').close()
|
||||
stateList = open(ctrlFile, 'r')
|
||||
|
||||
checkList = [x for x in stateList]
|
||||
return checkList
|
||||
|
||||
#Store/Restore CVars default values -----------------------------------------------------------------#
|
||||
if 'CVARS' not in globals():
|
||||
CVARS = {}
|
||||
|
||||
def saveDefaultValue(cVars, value):
|
||||
if cVars not in CVARS:
|
||||
CVARS[cVars] = value
|
||||
|
||||
def restoreDefaultValue(cVars):
|
||||
if cVars not in CVARS:
|
||||
return
|
||||
|
||||
defaultValue = CVARS[cVars]
|
||||
del CVARS[cVars]
|
||||
if cVars.startswith(HIDDEN_MASK_PREFIX):
|
||||
type = cVars[HIDDEN_MASK_PREFIX_LENGTH:]
|
||||
general.set_hidemask(type, defaultValue)
|
||||
else:
|
||||
general.set_cvar(cVars, defaultValue)
|
||||
|
||||
#toggle CVars--------------------------------------------------------------------#
|
||||
|
||||
def updateCvars(cVars, value):
|
||||
saveDefaultValue(cVars, value)
|
||||
general.set_cvar(cVars, value)
|
||||
|
||||
def toggleCvarsRestartCheck(log, state, mode, cVars, onValue, offValue, ctrlFile):
|
||||
if log in state:
|
||||
toggleCvarsV(mode, cVars, onValue, offValue, ctrlFile)
|
||||
else:
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(log)
|
||||
stateList = open(ctrlFile, 'r')
|
||||
toggleCvarsV(mode, cVars, onValue, offValue, ctrlFile)
|
||||
|
||||
def toggleCvarsV(mode, cVars, onValue, offValue, ctrlFile):
|
||||
stateList = open(ctrlFile, 'r')
|
||||
setState = [x for x in enumerate(stateList)]
|
||||
blankCheck = [x for x in setState]
|
||||
getList = [x for x in stateList]
|
||||
|
||||
if blankCheck == []:
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str("%s,{'%s': %s}" % (mode, cVars, offValue))+'\n'))
|
||||
general.set_cvar(cVars, offValue)
|
||||
else:
|
||||
stateList = open(ctrlFile, 'r')
|
||||
checkFor = str([x for x in stateList])
|
||||
|
||||
if mode not in str(checkFor):
|
||||
stateList = open(ctrlFile, 'r')
|
||||
getList = [x for x in stateList]
|
||||
getList.insert(1, str("%s,{'%s': %s}\n" % (mode, cVars , offValue)))
|
||||
print (str("{'%s': %s}\n" % (cVars , offValue)))
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(getList))
|
||||
general.set_cvar(cVars, offValue)
|
||||
|
||||
else:
|
||||
stateList = open(ctrlFile, 'r')
|
||||
for d in enumerate(stateList):
|
||||
values = d[1].split(',')
|
||||
stateList = open(ctrlFile, 'r')
|
||||
getList = [x for x in stateList]
|
||||
|
||||
if mode in values[0]:
|
||||
getDict = ast.literal_eval(values[1])
|
||||
getState = getDict.get(cVars)
|
||||
|
||||
if getState == offValue:
|
||||
getDict[cVars] = onValue
|
||||
joinStr = [mode,",",str(getDict), '\n']
|
||||
newLine = ''.join(joinStr)
|
||||
print (getDict)
|
||||
getList[d[0]] = newLine
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str(''.join(getList))))
|
||||
general.set_cvar(cVars, onValue)
|
||||
else:
|
||||
getDict[cVars] = offValue
|
||||
joinStr = [mode,",",str(getDict), '\n']
|
||||
newLine = ''.join(joinStr)
|
||||
print (getDict)
|
||||
getList[d[0]] = newLine
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str(''.join(getList))))
|
||||
general.set_cvar(cVars, offValue)
|
||||
|
||||
def toggleCvarsValue(mode, cVars, onValue, offValue):
|
||||
currentValue = general.get_cvar(cVars)
|
||||
|
||||
if type(onValue) is str:
|
||||
saveDefaultValue(cVars, currentValue)
|
||||
elif type(onValue) is int:
|
||||
saveDefaultValue(cVars, int(currentValue))
|
||||
elif type(onValue) is float:
|
||||
saveDefaultValue(cVars, float(currentValue))
|
||||
else:
|
||||
general.log('Failed to store default value for {0}'.format(cVars))
|
||||
|
||||
if currentValue == str(onValue):
|
||||
general.set_cvar(cVars, offValue)
|
||||
else:
|
||||
general.set_cvar(cVars, onValue)
|
||||
|
||||
#toggleConsol--------------------------------------------------------------------#
|
||||
|
||||
def toggleConsolRestartCheck(log,state, mode, onValue, offValue, ctrlFile):
|
||||
if log in state:
|
||||
toggleConsolV(mode, onValue, offValue, ctrlFile)
|
||||
else:
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(log)
|
||||
stateList = open(ctrlFile, 'r')
|
||||
toggleConsolV(mode, onValue, offValue, ctrlFile)
|
||||
|
||||
def toggleConsolV(mode, onValue, offValue):
|
||||
stateList = open(ctrlFile, 'r')
|
||||
setState = [x for x in enumerate(stateList)]
|
||||
blankCheck = [x for x in setState]
|
||||
getList = [x for x in stateList]
|
||||
onOffList = [onValue, offValue]
|
||||
|
||||
if blankCheck == []:
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str("%s,'%s'" % (mode, offValue))+'\n'))
|
||||
general.run_console(offValue)
|
||||
else:
|
||||
stateList = open(ctrlFile, 'r')
|
||||
checkFor = str([x for x in stateList])
|
||||
|
||||
if mode not in str(checkFor):
|
||||
stateList = open(ctrlFile, 'r')
|
||||
getList = [x for x in stateList]
|
||||
getList.insert(1, str("%s,'%s'\n" % (mode, offValue)))
|
||||
print (str("{'%s': %s}\n" % (cVars , offValue)))
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(getList))
|
||||
general.run_console(onValue)
|
||||
|
||||
else:
|
||||
stateList = open(ctrlFile, 'r')
|
||||
for d in enumerate(stateList):
|
||||
|
||||
values = d[1].split(',')
|
||||
|
||||
stateList = open(ctrlFile, 'r')
|
||||
getList = [x for x in stateList]
|
||||
|
||||
if mode in values[0]:
|
||||
getDict = values[1]
|
||||
off = ["'",str(offValue),"'", '\n']
|
||||
joinoff = ''.join(off)
|
||||
|
||||
if values[1] == joinoff:
|
||||
getDict = onValue
|
||||
joinStr = [mode,",","'",getDict,"'", '\n']
|
||||
newLine = ''.join(joinStr)
|
||||
print (getDict)
|
||||
getList[d[0]] = str(newLine)
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str(''.join(getList))))
|
||||
general.run_console(onValue)
|
||||
else:
|
||||
getDict = offValue
|
||||
joinStr = [mode,",","'",getDict,"'", '\n']
|
||||
newLine = ''.join(joinStr)
|
||||
print (getDict)
|
||||
getList[d[0]] = str(newLine)
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str(''.join(getList))))
|
||||
general.run_console(offValue)
|
||||
|
||||
def toggleConsolValue(log, state, mode, onValue, offValue):
|
||||
logList = getLogList(logfile)
|
||||
checkList = getCheckList(ctrlFile)
|
||||
toggleConsolRestartCheck(logList[1],checkList, mode, onValue, offValue, ctrlFile)
|
||||
|
||||
#cycleCvars----------------------------------------------------------------------#
|
||||
|
||||
def cycleCvarsRestartCheck(log, state, mode, cVars, cycleList, ctrlFile):
|
||||
if log in state:
|
||||
cycleCvarsV(mode, cVars, cycleList, ctrlFile)
|
||||
else:
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(log)
|
||||
stateList = open(ctrlFile, 'r')
|
||||
cycleCvarsV(mode, cVars, cycleList, ctrlFile)
|
||||
|
||||
def cycleCvarsV(mode, cVars, cycleList, ctrlFile):
|
||||
stateList = open(ctrlFile, 'r')
|
||||
setState = [x for x in enumerate(stateList)]
|
||||
blankCheck = [x for x in setState]
|
||||
getList = [x for x in stateList]
|
||||
|
||||
if blankCheck == []:
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str("%s,{'%s': %s}" % (mode, cVars, cycleList[1]))+'\n'))
|
||||
general.set_cvar(cVars, cycleList[1])
|
||||
else:
|
||||
stateList = open(ctrlFile, 'r')
|
||||
checkFor = str([x for x in stateList])
|
||||
|
||||
if mode not in str(checkFor):
|
||||
stateList = open(ctrlFile, 'r')
|
||||
getList = [x for x in stateList]
|
||||
getList.insert(1, str("%s,{'%s': %s}\n" % (mode, cVars , cycleList[1])))
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(getList))
|
||||
general.set_cvar(cVars, cycleList[1])
|
||||
|
||||
else:
|
||||
stateList = open(ctrlFile, 'r')
|
||||
|
||||
for d in enumerate(stateList):
|
||||
stateList = open(ctrlFile, 'r')
|
||||
getList = [x for x in stateList]
|
||||
values = d[1].split(',')
|
||||
|
||||
if mode in values[0]:
|
||||
getDict = ast.literal_eval(values[1])
|
||||
getState = getDict.get(cVars)
|
||||
|
||||
cycleL = [x for x in enumerate(cycleList)]
|
||||
|
||||
for x in cycleL:
|
||||
if getState == x[1]:
|
||||
number = [n[1] for n in cycleL]
|
||||
getMax = max(number)
|
||||
nextNum = x[0]+1
|
||||
|
||||
if nextNum > getMax:
|
||||
getDict[cVars] = cycleList[0]
|
||||
joinStr = [mode,",",str(getDict), '\n']
|
||||
newLine = ''.join(joinStr)
|
||||
getList[d[0]] = newLine
|
||||
print (getDict)
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str(''.join(getList))))
|
||||
general.set_cvar(cVars, cycleList[0])
|
||||
else:
|
||||
getDict[cVars] = cycleList[x[0]+1]
|
||||
joinStr = [mode,",",str(getDict), '\n']
|
||||
newLine = ''.join(joinStr)
|
||||
getList[d[0]] = newLine
|
||||
print (getDict)
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str(''.join(getList))))
|
||||
general.set_cvar(cVars, cycleList[x[0]+1])
|
||||
|
||||
def cycleCvarsValue(log, state, mode, cVars, cycleList):
|
||||
logList = getLogList(logfile)
|
||||
checkList = getCheckList(ctrlFile)
|
||||
cycleCvarsRestartCheck(logList[1],checkList, mode, cVars, cycleList, ctrlFile)
|
||||
|
||||
def cycleCvarsFloatValue(cVars, cycleList):
|
||||
currentValueAsString = general.get_cvar(cVars)
|
||||
try:
|
||||
currentValue = float(currentValueAsString)
|
||||
except:
|
||||
currentValue = -1.0
|
||||
|
||||
saveDefaultValue(cVars, currentValue)
|
||||
|
||||
# make sure we sort the list in ascending fashion
|
||||
cycleList = sorted(cycleList)
|
||||
|
||||
# find out what the next closest index is
|
||||
newIndex = 0
|
||||
for x in cycleList:
|
||||
if (currentValue < x):
|
||||
break
|
||||
newIndex = newIndex + 1
|
||||
|
||||
# loop around, if we need to
|
||||
if newIndex >= len(cycleList):
|
||||
newIndex = 0
|
||||
|
||||
general.set_cvar(cVars, cycleList[newIndex])
|
||||
|
||||
|
||||
def cycleCvarsIntValue(cVars, cycleList):
|
||||
currentValueAsString = general.get_cvar(cVars)
|
||||
try:
|
||||
currentValue = int(currentValueAsString)
|
||||
except:
|
||||
currentValue = 0
|
||||
|
||||
saveDefaultValue(cVars, currentValue)
|
||||
|
||||
# find out what index we're on already
|
||||
# default to -1 so that when we increment to the next, we'll be at 0
|
||||
newIndex = -1
|
||||
for x in cycleList:
|
||||
if (currentValue == x):
|
||||
break
|
||||
newIndex = newIndex + 1
|
||||
|
||||
# move to the next item
|
||||
newIndex = newIndex + 1
|
||||
|
||||
# validate
|
||||
if newIndex >= len(cycleList):
|
||||
newIndex = 0
|
||||
|
||||
general.set_cvar(cVars, cycleList[newIndex])
|
||||
|
||||
#cycleConsol----------------------------------------------------------------------#
|
||||
|
||||
def cycleConsolRestartCheck(log, state, mode, cycleList, ctrlFile):
|
||||
if log in state:
|
||||
cycleConsolV(mode, cycleList, ctrlFile)
|
||||
else:
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(log)
|
||||
stateList = open(ctrlFile, 'r')
|
||||
cycleConsolV(mode, cycleList, ctrlFile)
|
||||
|
||||
def cycleConsolV(mode, cycleList, ctrlFile):
|
||||
stateList = open(ctrlFile, 'r')
|
||||
setState = [x for x in enumerate(stateList)]
|
||||
blankCheck = [x for x in setState]
|
||||
getList = [x for x in stateList]
|
||||
|
||||
if blankCheck == []:
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str("%s,'%s'" % (mode, cycleList[0]))+'\n'))
|
||||
general.run_console(cycleList[0])
|
||||
else:
|
||||
stateList = open(ctrlFile, 'r')
|
||||
checkFor = str([x for x in stateList])
|
||||
|
||||
if mode not in str(checkFor):
|
||||
stateList = open(ctrlFile, 'r')
|
||||
getList = [x for x in stateList]
|
||||
getList.insert(1, str("%s,'%s'\n" % (mode, cycleList[0])))
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(getList))
|
||||
general.run_console(cycleList[0])
|
||||
|
||||
else:
|
||||
stateList = open(ctrlFile, 'r')
|
||||
for d in enumerate(stateList):
|
||||
stateList = open(ctrlFile, 'r')
|
||||
getList = [x for x in stateList]
|
||||
values = d[1].split(',')
|
||||
|
||||
if mode in values[0]:
|
||||
newValue = ''.join(values[1].split('\n'))
|
||||
cycleL = [e for e in enumerate(cycleList)]
|
||||
getDict = ''.join(values[1].split('\n'))
|
||||
|
||||
for x in cycleL:
|
||||
|
||||
if newValue in "'%s'" % x[1]:
|
||||
number = [n[0] for n in cycleL]
|
||||
getMax = max(number)
|
||||
nextNum = x[0]+1
|
||||
|
||||
if nextNum > getMax:
|
||||
getDict = '%s' % cycleList[0]
|
||||
joinStr = [mode,",","'",getDict,"'", '\n']
|
||||
newLine = ''.join(joinStr)
|
||||
getList[d[0]] = newLine
|
||||
print (getDict)
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str(''.join(getList))))
|
||||
general.run_console(getDict)
|
||||
else:
|
||||
getDict = '%s' % cycleList[x[0]+1]
|
||||
joinStr = [mode,",","'",getDict,"'", '\n']
|
||||
newLine = ''.join(joinStr)
|
||||
getList[d[0]] = newLine
|
||||
print (getDict)
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str(''.join(getList))))
|
||||
general.run_console(getDict)
|
||||
|
||||
def cycleConsolValue(mode, cycleList):
|
||||
logList = getLogList(logfile)
|
||||
checkList = getCheckList(ctrlFile)
|
||||
cycleConsolRestartCheck(logList[1],checkList, mode, cycleList, ctrlFile)
|
||||
|
||||
def toggleHideMaskValues(type):
|
||||
cVars = "%s%s" % (HIDDEN_MASK_PREFIX, type)
|
||||
currentValue = general.get_hidemask(type)
|
||||
saveDefaultValue(cVars, int(currentValue))
|
||||
if (currentValue):
|
||||
general.set_hidemask(type, 0)
|
||||
else:
|
||||
general.set_hidemask(type, 1)
|
||||
|
||||
#toggleHide------------------------------------------------------------------------#
|
||||
|
||||
def toggleHideRestartCheck(log, state, mode, type, onValue, offValue, ctrlFile):
|
||||
if log in state:
|
||||
toggleHideByT(mode, type, onValue, offValue, ctrlFile)
|
||||
else:
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(log)
|
||||
stateList = open(ctrlFile, 'r')
|
||||
toggleHideByT(mode, type, onValue, offValue, ctrlFile)
|
||||
|
||||
def toggleHideByType(mode, type, onValue, offValue):
|
||||
logList = getLogList(logfile)
|
||||
checkList = getCheckList(ctrlFile)
|
||||
toggleHideRestartCheck(logList[1],checkList, mode, type, onValue, offValue, ctrlFile)
|
||||
|
||||
def toggleHideByT(mode, type, onValue, offValue, ctrlFile):
|
||||
stateList = open(ctrlFile, 'r')
|
||||
setState = [x for x in enumerate(stateList)]
|
||||
blankCheck = [x for x in setState]
|
||||
getList = [x for x in stateList]
|
||||
|
||||
if blankCheck == []:
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str("%s,{'%s': %s}" % (mode, type, offValue))+'\n'))
|
||||
|
||||
hideByType(type)
|
||||
else:
|
||||
stateList = open(ctrlFile, 'r')
|
||||
checkFor = str([x for x in stateList])
|
||||
|
||||
if mode not in str(checkFor):
|
||||
stateList = open(ctrlFile, 'r')
|
||||
getList = [x for x in stateList]
|
||||
getList.insert(1, str("%s,{'%s': %s}\n" % (mode, type , offValue)))
|
||||
print (str("{'%s': %s}\n" % (type , offValue)))
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(getList))
|
||||
hideByType(type)
|
||||
|
||||
else:
|
||||
stateList = open(ctrlFile, 'r')
|
||||
for d in enumerate(stateList):
|
||||
values = d[1].split(',')
|
||||
stateList = open(ctrlFile, 'r')
|
||||
getList = [x for x in stateList]
|
||||
|
||||
if mode in values[0]:
|
||||
getDict = ast.literal_eval(values[1])
|
||||
getState = getDict.get(type)
|
||||
|
||||
if getState == offValue:
|
||||
getDict[type] = onValue
|
||||
joinStr = [mode,",",str(getDict), '\n']
|
||||
newLine = ''.join(joinStr)
|
||||
print (getDict)
|
||||
getList[d[0]] = newLine
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str(''.join(getList))))
|
||||
unHideByType(type)
|
||||
else:
|
||||
getDict[type] = offValue
|
||||
joinStr = [mode,",",str(getDict), '\n']
|
||||
newLine = ''.join(joinStr)
|
||||
print (getDict)
|
||||
getList[d[0]] = newLine
|
||||
stateList = open(ctrlFile, 'w')
|
||||
stateList.write(''.join(str(''.join(getList))))
|
||||
hideByType(type)
|
||||
|
||||
def hideByType(type):
|
||||
typeList = general.get_all_objects(str(type), "")
|
||||
for x in typeList:
|
||||
general.hide_object(x)
|
||||
|
||||
def unHideByType(type):
|
||||
typeList = general.get_all_objects(str(type), "")
|
||||
for x in typeList:
|
||||
general.unhide_object(x)
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7f94f2634eacb4d7bee20dacc45edef96e4d268f1adb7960b8aa8f3b6e2906ed
|
||||
size 6867609
|
||||
@@ -1,129 +0,0 @@
|
||||
{
|
||||
"ContainerEntity": {
|
||||
"Id": "ContainerEntity",
|
||||
"Name": "Bush",
|
||||
"Components": {
|
||||
"Component_[1140272189295067758]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 1140272189295067758
|
||||
},
|
||||
"Component_[13437832196484687256]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 13437832196484687256
|
||||
},
|
||||
"Component_[1553903646452669645]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 1553903646452669645
|
||||
},
|
||||
"Component_[15914009348632444632]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 15914009348632444632,
|
||||
"Child Entity Order": [
|
||||
"Entity_[7511491868318]"
|
||||
]
|
||||
},
|
||||
"Component_[18046340308818780248]": {
|
||||
"$type": "EditorPrefabComponent",
|
||||
"Id": 18046340308818780248
|
||||
},
|
||||
"Component_[1948833233489872938]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 1948833233489872938,
|
||||
"Parent Entity": ""
|
||||
},
|
||||
"Component_[2903632350157981339]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 2903632350157981339
|
||||
},
|
||||
"Component_[48827510535192710]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 48827510535192710
|
||||
},
|
||||
"Component_[5609536793322429681]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 5609536793322429681
|
||||
},
|
||||
"Component_[5859168386298620990]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 5859168386298620990
|
||||
},
|
||||
"Component_[6604616929271524505]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 6604616929271524505
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entities": {
|
||||
"Entity_[7511491868318]": {
|
||||
"Id": "Entity_[7511491868318]",
|
||||
"Name": "Bush",
|
||||
"Components": {
|
||||
"Component_[10227459330338484901]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 10227459330338484901,
|
||||
"ComponentOrderEntryArray": [
|
||||
{
|
||||
"ComponentId": 4998941225335869157
|
||||
},
|
||||
{
|
||||
"ComponentId": 9922994635792843826,
|
||||
"SortIndex": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"Component_[10972351222359420947]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 10972351222359420947
|
||||
},
|
||||
"Component_[12101122374155214392]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 12101122374155214392
|
||||
},
|
||||
"Component_[1535264614652988260]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 1535264614652988260
|
||||
},
|
||||
"Component_[16367811417907891218]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 16367811417907891218
|
||||
},
|
||||
"Component_[17044216787716682880]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 17044216787716682880
|
||||
},
|
||||
"Component_[2129822594969629430]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 2129822594969629430
|
||||
},
|
||||
"Component_[2838015156782745450]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 2838015156782745450
|
||||
},
|
||||
"Component_[4998941225335869157]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 4998941225335869157,
|
||||
"Parent Entity": "ContainerEntity"
|
||||
},
|
||||
"Component_[8773358049076362578]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 8773358049076362578
|
||||
},
|
||||
"Component_[9922994635792843826]": {
|
||||
"$type": "AZ::Render::EditorMeshComponent",
|
||||
"Id": 9922994635792843826,
|
||||
"Controller": {
|
||||
"Configuration": {
|
||||
"ModelAsset": {
|
||||
"assetId": {
|
||||
"guid": "{1201406D-FB20-5B5F-B9B5-6A6E8DE00A14}",
|
||||
"subId": 276506120
|
||||
},
|
||||
"assetHint": "assets/objects/foliage/bush_privet_01.azmodel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,131 +0,0 @@
|
||||
{
|
||||
"ContainerEntity": {
|
||||
"Id": "ContainerEntity",
|
||||
"Name": "PinkFlower",
|
||||
"Components": {
|
||||
"Component_[10444337162843472597]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 10444337162843472597
|
||||
},
|
||||
"Component_[14431042590323756177]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 14431042590323756177,
|
||||
"ChildEntityOrderEntryArray": [
|
||||
{
|
||||
"EntityId": "Entity_[491002114939]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Component_[14577735453176806353]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 14577735453176806353
|
||||
},
|
||||
"Component_[15674021346798629563]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 15674021346798629563
|
||||
},
|
||||
"Component_[16784074985702513600]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 16784074985702513600,
|
||||
"Parent Entity": ""
|
||||
},
|
||||
"Component_[3351614541100572773]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 3351614541100572773
|
||||
},
|
||||
"Component_[3600658560328167663]": {
|
||||
"$type": "EditorPrefabComponent",
|
||||
"Id": 3600658560328167663
|
||||
},
|
||||
"Component_[6155673728651558934]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 6155673728651558934
|
||||
},
|
||||
"Component_[8458684662170321289]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 8458684662170321289
|
||||
},
|
||||
"Component_[8705192117416252351]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 8705192117416252351
|
||||
},
|
||||
"Component_[8801280051488695852]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 8801280051488695852
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entities": {
|
||||
"Entity_[491002114939]": {
|
||||
"Id": "Entity_[491002114939]",
|
||||
"Name": "PinkFlower",
|
||||
"Components": {
|
||||
"Component_[11083205340162142682]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 11083205340162142682
|
||||
},
|
||||
"Component_[11327363779873517]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 11327363779873517
|
||||
},
|
||||
"Component_[12717389211269537921]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 12717389211269537921
|
||||
},
|
||||
"Component_[12826285685970138542]": {
|
||||
"$type": "AZ::Render::EditorMeshComponent",
|
||||
"Id": 12826285685970138542,
|
||||
"Controller": {
|
||||
"Configuration": {
|
||||
"ModelAsset": {
|
||||
"assetId": {
|
||||
"guid": "{549F4C4D-A7D9-5F2A-A6BD-F24C8BC43BBF}",
|
||||
"subId": 280086017
|
||||
},
|
||||
"assetHint": "assets/objects/foliage/grass_flower_pink.azmodel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[14101419970865342875]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 14101419970865342875
|
||||
},
|
||||
"Component_[14770464075286403207]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 14770464075286403207
|
||||
},
|
||||
"Component_[15205142653091190082]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 15205142653091190082,
|
||||
"Parent Entity": "ContainerEntity"
|
||||
},
|
||||
"Component_[15510898811147803772]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 15510898811147803772,
|
||||
"ComponentOrderEntryArray": [
|
||||
{
|
||||
"ComponentId": 15205142653091190082
|
||||
},
|
||||
{
|
||||
"ComponentId": 12826285685970138542,
|
||||
"SortIndex": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"Component_[15988401742428977134]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 15988401742428977134
|
||||
},
|
||||
"Component_[4300550837037679336]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 4300550837037679336
|
||||
},
|
||||
"Component_[996914988793716659]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 996914988793716659
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
{
|
||||
"ContainerEntity": {
|
||||
"Id": "ContainerEntity",
|
||||
"Name": "PurpleFlower",
|
||||
"Components": {
|
||||
"Component_[10519928302743666073]": {
|
||||
"$type": "EditorPrefabComponent",
|
||||
"Id": 10519928302743666073
|
||||
},
|
||||
"Component_[13894087802180240181]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 13894087802180240181,
|
||||
"Parent Entity": ""
|
||||
},
|
||||
"Component_[15788541052719571801]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 15788541052719571801
|
||||
},
|
||||
"Component_[15842981265136092481]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 15842981265136092481
|
||||
},
|
||||
"Component_[16360384897559021149]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 16360384897559021149
|
||||
},
|
||||
"Component_[16713545675046303279]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 16713545675046303279
|
||||
},
|
||||
"Component_[1806734194268113785]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 1806734194268113785
|
||||
},
|
||||
"Component_[5392020700593853313]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 5392020700593853313,
|
||||
"Child Entity Order": [
|
||||
"Entity_[14335611090324]"
|
||||
]
|
||||
},
|
||||
"Component_[5995854518752659458]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 5995854518752659458
|
||||
},
|
||||
"Component_[6963022284400845376]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 6963022284400845376
|
||||
},
|
||||
"Component_[8055275578170091546]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 8055275578170091546
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entities": {
|
||||
"Entity_[14335611090324]": {
|
||||
"Id": "Entity_[14335611090324]",
|
||||
"Name": "PurpleFlower",
|
||||
"Components": {
|
||||
"Component_[10887353073528055802]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 10887353073528055802
|
||||
},
|
||||
"Component_[12641127425852859189]": {
|
||||
"$type": "AZ::Render::EditorMeshComponent",
|
||||
"Id": 12641127425852859189,
|
||||
"Controller": {
|
||||
"Configuration": {
|
||||
"ModelAsset": {
|
||||
"assetId": {
|
||||
"guid": "{D493A670-6D82-5AE9-A2C8-A2EB02684F71}",
|
||||
"subId": 284799939
|
||||
},
|
||||
"assetHint": "assets/objects/foliage/grass_flower_purple.azmodel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[14406733303466080015]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 14406733303466080015,
|
||||
"ComponentOrderEntryArray": [
|
||||
{
|
||||
"ComponentId": 9231452352781000222
|
||||
},
|
||||
{
|
||||
"ComponentId": 12641127425852859189,
|
||||
"SortIndex": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"Component_[1452384341905923012]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 1452384341905923012
|
||||
},
|
||||
"Component_[2215454016415585892]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 2215454016415585892
|
||||
},
|
||||
"Component_[4104108067383423623]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 4104108067383423623
|
||||
},
|
||||
"Component_[4197335450471807917]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 4197335450471807917
|
||||
},
|
||||
"Component_[6877680739064997650]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 6877680739064997650
|
||||
},
|
||||
"Component_[7372550507186490390]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 7372550507186490390
|
||||
},
|
||||
"Component_[7673532337364366244]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 7673532337364366244
|
||||
},
|
||||
"Component_[9231452352781000222]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 9231452352781000222,
|
||||
"Parent Entity": "ContainerEntity"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4c1d04d687bdce69965965c290c907b3f9a730a7ea73874b734e1c7ff41426d9
|
||||
size 3832768
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3789abdf439a6d70438fd4bb1e06881ae6686a4699209c6bc371d22d161e5347
|
||||
size 26476
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c987d7d79685fda83efcffb7e1afbcd356c37fc68ec5c663a89b02d4df10caea
|
||||
size 46412
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:27f87510ae07771dbad3e430e31502b1d1d13dee868f143b7f1de2a7febc8eb9
|
||||
size 7046400
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"values": [
|
||||
{
|
||||
"$type": "ScriptProcessorRule",
|
||||
"scriptFilename": "Assets/TestAnim/scene_export_actor.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,221 +0,0 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
import traceback, sys, uuid, os, json
|
||||
|
||||
#
|
||||
# Example for exporting ActorGroup scene rules
|
||||
#
|
||||
|
||||
def log_exception_traceback():
|
||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||
data = traceback.format_exception(exc_type, exc_value, exc_tb)
|
||||
print(str(data))
|
||||
|
||||
def get_node_names(sceneGraph, nodeTypeName, testEndPoint = False, validList = None):
|
||||
import azlmbr.scene.graph
|
||||
import scene_api.scene_data
|
||||
|
||||
node = sceneGraph.get_root()
|
||||
nodeList = []
|
||||
children = []
|
||||
paths = []
|
||||
|
||||
while node.IsValid():
|
||||
# store children to process after siblings
|
||||
if sceneGraph.has_node_child(node):
|
||||
children.append(sceneGraph.get_node_child(node))
|
||||
|
||||
nodeName = scene_api.scene_data.SceneGraphName(sceneGraph.get_node_name(node))
|
||||
paths.append(nodeName.get_path())
|
||||
|
||||
include = True
|
||||
|
||||
if (validList is not None):
|
||||
include = False # if a valid list filter provided, assume to not include node name
|
||||
name_parts = nodeName.get_path().split('.')
|
||||
for valid in validList:
|
||||
if (valid in name_parts[-1]):
|
||||
include = True
|
||||
break
|
||||
|
||||
# store any node that has provides specifc data content
|
||||
nodeContent = sceneGraph.get_node_content(node)
|
||||
if include and nodeContent.CastWithTypeName(nodeTypeName):
|
||||
if testEndPoint is not None:
|
||||
include = sceneGraph.is_node_end_point(node) is testEndPoint
|
||||
if include:
|
||||
if (len(nodeName.get_path())):
|
||||
nodeList.append(scene_api.scene_data.SceneGraphName(sceneGraph.get_node_name(node)))
|
||||
|
||||
# advance to next node
|
||||
if sceneGraph.has_node_sibling(node):
|
||||
node = sceneGraph.get_node_sibling(node)
|
||||
elif children:
|
||||
node = children.pop()
|
||||
else:
|
||||
node = azlmbr.scene.graph.NodeIndex()
|
||||
|
||||
return nodeList, paths
|
||||
|
||||
def generate_mesh_group(scene, sceneManifest, meshDataList, paths):
|
||||
# Compute the name of the scene file
|
||||
clean_filename = scene.sourceFilename.replace('.', '_')
|
||||
mesh_group_name = os.path.basename(clean_filename)
|
||||
|
||||
# make the mesh group
|
||||
mesh_group = sceneManifest.add_mesh_group(mesh_group_name)
|
||||
mesh_group['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, clean_filename)) + '}'
|
||||
|
||||
# add all nodes to this mesh group
|
||||
for activeMeshIndex in range(len(meshDataList)):
|
||||
mesh_name = meshDataList[activeMeshIndex]
|
||||
mesh_path = mesh_name.get_path()
|
||||
sceneManifest.mesh_group_select_node(mesh_group, mesh_path)
|
||||
|
||||
def create_shape_configuration(nodeName):
|
||||
import scene_api.physics_data
|
||||
|
||||
if(nodeName in ['_foot_','_wrist_']):
|
||||
shapeConfiguration = scene_api.physics_data.BoxShapeConfiguration()
|
||||
shapeConfiguration.scale = [1.1, 1.1, 1.1]
|
||||
shapeConfiguration.dimensions = [2.1, 3.1, 4.1]
|
||||
return shapeConfiguration
|
||||
else:
|
||||
shapeConfiguration = scene_api.physics_data.CapsuleShapeConfiguration()
|
||||
shapeConfiguration.scale = [1.0, 1.0, 1.0]
|
||||
shapeConfiguration.height = 1.0
|
||||
shapeConfiguration.radius = 1.0
|
||||
return shapeConfiguration
|
||||
|
||||
def create_collider_configuration(nodeName):
|
||||
import scene_api.physics_data
|
||||
|
||||
colliderConfiguration = scene_api.physics_data.ColliderConfiguration()
|
||||
colliderConfiguration.Position = [0.1, 0.1, 0.2]
|
||||
colliderConfiguration.Rotation = [45.0, 35.0, 25.0]
|
||||
return colliderConfiguration
|
||||
|
||||
def generate_physics_nodes(actorPhysicsSetupRule, nodeNameList):
|
||||
import scene_api.physics_data
|
||||
|
||||
hitDetectionConfig = scene_api.physics_data.CharacterColliderConfiguration()
|
||||
simulatedObjectColliderConfig = scene_api.physics_data.CharacterColliderConfiguration()
|
||||
clothConfig = scene_api.physics_data.CharacterColliderConfiguration()
|
||||
ragdollConfig = scene_api.physics_data.RagdollConfiguration()
|
||||
|
||||
for nodeName in nodeNameList:
|
||||
shapeConfiguration = create_shape_configuration(nodeName)
|
||||
colliderConfiguration = create_collider_configuration(nodeName)
|
||||
hitDetectionConfig.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration)
|
||||
simulatedObjectColliderConfig.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration)
|
||||
clothConfig.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration)
|
||||
#
|
||||
ragdollNode = scene_api.physics_data.RagdollNodeConfiguration()
|
||||
ragdollNode.JointConfig.Name = nodeName
|
||||
ragdollConfig.add_ragdoll_node_configuration(ragdollNode)
|
||||
ragdollConfig.colliders.add_character_collider_node_configuration_node(nodeName, colliderConfiguration, shapeConfiguration)
|
||||
|
||||
actorPhysicsSetupRule.set_simulated_object_collider_config(simulatedObjectColliderConfig)
|
||||
actorPhysicsSetupRule.set_hit_detection_config(hitDetectionConfig)
|
||||
actorPhysicsSetupRule.set_cloth_config(clothConfig)
|
||||
actorPhysicsSetupRule.set_ragdoll_config(ragdollConfig)
|
||||
|
||||
def generate_actor_group(scene, sceneManifest, meshDataList, paths):
|
||||
import scene_api.scene_data
|
||||
import scene_api.physics_data
|
||||
import scene_api.actor_group
|
||||
|
||||
# fetch bone data
|
||||
validNames = ['_neck_','_pelvis_','_leg_','_knee_','_spine_','_arm_','_clavicle_','_head_','_elbow_','_wrist_']
|
||||
graph = scene_api.scene_data.SceneGraph(scene.graph)
|
||||
nodeList, allNodePaths = get_node_names(graph, 'BoneData', validList = validNames)
|
||||
|
||||
nodeNameList = []
|
||||
for activeMeshIndex, nodeName in enumerate(nodeList):
|
||||
nodeNameList.append(nodeName.get_name())
|
||||
|
||||
# add comment
|
||||
commentRule = scene_api.actor_group.CommentRule()
|
||||
commentRule.text = str(nodeNameList)
|
||||
|
||||
# ActorPhysicsSetupRule
|
||||
actorPhysicsSetupRule = scene_api.actor_group.ActorPhysicsSetupRule()
|
||||
generate_physics_nodes(actorPhysicsSetupRule, nodeNameList)
|
||||
|
||||
# add scale of the Actor rule
|
||||
actorScaleRule = scene_api.actor_group.ActorScaleRule()
|
||||
actorScaleRule.scaleFactor = 2.0
|
||||
|
||||
# add coordinate system rule
|
||||
coordinateSystemRule = scene_api.actor_group.CoordinateSystemRule()
|
||||
coordinateSystemRule.useAdvancedData = False
|
||||
|
||||
# add morph target rule
|
||||
morphTargetRule = scene_api.actor_group.MorphTargetRule()
|
||||
morphTargetRule.targets.select_targets([nodeNameList[0]], nodeNameList)
|
||||
|
||||
# add skeleton optimization rule
|
||||
skeletonOptimizationRule = scene_api.actor_group.SkeletonOptimizationRule()
|
||||
skeletonOptimizationRule.autoSkeletonLOD = True
|
||||
skeletonOptimizationRule.criticalBonesList.select_targets([nodeNameList[0:2]], nodeNameList)
|
||||
|
||||
# add LOD rule
|
||||
lodRule = scene_api.actor_group.LodRule()
|
||||
lodRule0 = lodRule.add_lod_level(0)
|
||||
lodRule0.select_targets([nodeNameList[1:4]], nodeNameList)
|
||||
|
||||
actorGroup = scene_api.actor_group.ActorGroup()
|
||||
actorGroup.name = os.path.basename(scene.sourceFilename)
|
||||
actorGroup.add_rule(actorScaleRule)
|
||||
actorGroup.add_rule(coordinateSystemRule)
|
||||
actorGroup.add_rule(skeletonOptimizationRule)
|
||||
actorGroup.add_rule(morphTargetRule)
|
||||
actorGroup.add_rule(lodRule)
|
||||
actorGroup.add_rule(actorPhysicsSetupRule)
|
||||
actorGroup.add_rule(commentRule)
|
||||
sceneManifest.manifest['values'].append(actorGroup.to_dict())
|
||||
|
||||
def update_manifest(scene):
|
||||
import json, uuid, os
|
||||
import azlmbr.scene.graph
|
||||
import scene_api.scene_data
|
||||
|
||||
graph = scene_api.scene_data.SceneGraph(scene.graph)
|
||||
mesh_name_list, all_node_paths = get_node_names(graph, 'MeshData')
|
||||
scene_manifest = scene_api.scene_data.SceneManifest()
|
||||
generate_actor_group(scene, scene_manifest, mesh_name_list, all_node_paths)
|
||||
generate_mesh_group(scene, scene_manifest, mesh_name_list, all_node_paths)
|
||||
|
||||
# Convert the manifest to a JSON string and return it
|
||||
return scene_manifest.export()
|
||||
|
||||
sceneJobHandler = None
|
||||
|
||||
def on_update_manifest(args):
|
||||
try:
|
||||
scene = args[0]
|
||||
return update_manifest(scene)
|
||||
except RuntimeError as err:
|
||||
print (f'ERROR - {err}')
|
||||
log_exception_traceback()
|
||||
except:
|
||||
log_exception_traceback()
|
||||
|
||||
global sceneJobHandler
|
||||
sceneJobHandler.disconnect()
|
||||
sceneJobHandler = None
|
||||
|
||||
# try to create SceneAPI handler for processing
|
||||
try:
|
||||
import azlmbr.scene
|
||||
|
||||
sceneJobHandler = azlmbr.scene.ScriptBuildingNotificationBusHandler()
|
||||
sceneJobHandler.connect()
|
||||
sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
|
||||
except:
|
||||
sceneJobHandler = None
|
||||
@@ -1,66 +0,0 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
import traceback, sys, uuid, os, json
|
||||
|
||||
import scene_export_utils
|
||||
import scene_api.motion_group
|
||||
|
||||
#
|
||||
# Example for exporting MotionGroup scene rules
|
||||
#
|
||||
|
||||
def update_manifest(scene):
|
||||
import azlmbr.scene.graph
|
||||
import scene_api.scene_data
|
||||
|
||||
# create a SceneManifest
|
||||
sceneManifest = scene_api.scene_data.SceneManifest()
|
||||
|
||||
# create a MotionGroup
|
||||
motionGroup = scene_api.motion_group.MotionGroup()
|
||||
motionGroup.name = os.path.basename(scene.sourceFilename.replace('.', '_'))
|
||||
|
||||
motionAdditiveRule = scene_api.motion_group.MotionAdditiveRule()
|
||||
motionAdditiveRule.sampleFrame = 2
|
||||
motionGroup.add_rule(motionAdditiveRule)
|
||||
|
||||
motionScaleRule = motionGroup.create_rule(scene_api.motion_group.MotionScaleRule())
|
||||
motionScaleRule.scaleFactor = 1.1
|
||||
motionGroup.add_rule(motionScaleRule)
|
||||
|
||||
# add motion group to scene manifest
|
||||
sceneManifest.add_motion_group(motionGroup)
|
||||
|
||||
# Convert the manifest to a JSON string and return it
|
||||
return sceneManifest.export()
|
||||
|
||||
sceneJobHandler = None
|
||||
|
||||
def on_update_manifest(args):
|
||||
try:
|
||||
scene = args[0]
|
||||
return update_manifest(scene)
|
||||
except RuntimeError as err:
|
||||
print (f'ERROR - {err}')
|
||||
scene_export_utils.log_exception_traceback()
|
||||
except:
|
||||
scene_export_utils.log_exception_traceback()
|
||||
|
||||
global sceneJobHandler
|
||||
sceneJobHandler.disconnect()
|
||||
sceneJobHandler = None
|
||||
|
||||
# try to create SceneAPI handler for processing
|
||||
try:
|
||||
import azlmbr.scene
|
||||
|
||||
sceneJobHandler = azlmbr.scene.ScriptBuildingNotificationBusHandler()
|
||||
sceneJobHandler.connect()
|
||||
sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
|
||||
except:
|
||||
sceneJobHandler = None
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"values": [
|
||||
{
|
||||
"$type": "ScriptProcessorRule",
|
||||
"scriptFilename": "Assets/TestAnim/scene_export_motion.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:011454252e40c927343cce16296412f02f45d1f345c75c036651bdcca473bda5
|
||||
size 2672
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7bafcc4aefab827e1414e64bcdde235500b51392e52c9ccd588b2d7a24b865a0
|
||||
size 20214
|
||||
@@ -2,11 +2,11 @@
|
||||
<Class name="DescriptorListAsset" type="{60961B36-E3CA-4877-B197-1462C1363F6E}">
|
||||
<Class name="AZStd::vector" field="Descriptors" type="{FC36C5E0-6152-5B06-AF30-3FC494B85FAB}">
|
||||
<Class name="Descriptor" field="element" version="8" type="{A5A5E7F7-FC36-4BD1-8A93-21362574B9DA}">
|
||||
<Class name="AZ::Uuid" field="SpawnerType" value="{74BEEDB5-81CF-409F-B375-0D93D81EF2E3}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
<Class name="AZ::Uuid" field="SpawnerType" value="{BBA5CC1E-B4CA-4792-89F7-93711E98FBD1}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
<Class name="AZStd::shared_ptr" field="InstanceSpawner" type="{7C7046DE-F8B1-529D-AD8C-829C6C0E2FCD}">
|
||||
<Class name="PrefabInstanceSpawner" field="element" type="{74BEEDB5-81CF-409F-B375-0D93D81EF2E3}">
|
||||
<Class name="DynamicSliceInstanceSpawner" field="element" type="{BBA5CC1E-B4CA-4792-89F7-93711E98FBD1}">
|
||||
<Class name="InstanceSpawner" field="BaseClass1" type="{01AD0758-B04A-4B43-BC2B-BDCD77F4EF6A}"/>
|
||||
<Class name="Asset" field="SpawnableAsset" value="id={80C0CF4E-9A5E-544B-B89E-BC980175A259}:e6f903d2,type={855E3021-D305-4845-B284-20C3F7FDF16B},hint={Assets/Prefabs/PinkFlower.prefab},loadBehavior=1" version="2" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
|
||||
<Class name="Asset" field="SliceAsset" value="id={EBFE34EB-D0A8-5E51-8234-3BE38082B28C}:2,type={78802ABF-9595-463A-8D2B-D022F906F9B1},hint={slices/pinkflower.dynamicslice}" version="1" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
|
||||
</Class>
|
||||
</Class>
|
||||
<Class name="float" field="Weight" value="1.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
|
||||
@@ -27,4 +27,5 @@ else()
|
||||
|
||||
set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${project_target_name})
|
||||
|
||||
add_subdirectory(Gem)
|
||||
endif()
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ac841c02e81c9ae23476522b7e517889d746d4ff32b3251ac4360168f39b30a3
|
||||
size 450708
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3653ca7fb42c7e5991815c17fc9ebeab14a1aa861bfb1d37e233ada66a835f00
|
||||
size 7188
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a30b85428202c548e77cdcc0a595f9f26e82d29622be26891d569f4779a75830
|
||||
size 1802388
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a3d76b7c93f8873ca7c4013dcc4eff887c25552c9c5847290481306656b22069
|
||||
size 3668
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:219f57137c5bd44093762ea9d0fc24308679956b980f26bf194edd3a1798fcda
|
||||
size 3668
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:96ed61c66d1d1f71e940ab75899ee253007e704004e1157c900c6308151a8bf1
|
||||
size 1802388
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:70a7dc4e2455624067e842b059954f6c4bb9b0debc3cb1ffa783b14bffc61786
|
||||
size 7188
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7f5a945c61f92f3da77dfd9fdd2c95aa257f4df6bcb82483c608ab660bb72e5f
|
||||
size 450708
|
||||
@@ -1,7 +0,0 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
@@ -1,30 +0,0 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
|
||||
import azlmbr.debug as debug
|
||||
|
||||
import pathlib
|
||||
|
||||
def test_profiler_system():
|
||||
if not debug.g_ProfilerSystem.IsValid():
|
||||
print('g_ProfilerSystem is INVALID')
|
||||
return
|
||||
|
||||
state = 'ACTIVE' if debug.g_ProfilerSystem.IsActive() else 'INACTIVE'
|
||||
print(f'Profiler system is currently {state}')
|
||||
|
||||
capture_location = pathlib.Path(debug.g_ProfilerSystem.GetCaptureLocation())
|
||||
print(f'Capture location set to {capture_location}')
|
||||
|
||||
print('Capturing single frame...' )
|
||||
capture_file = str(capture_location / 'script_capture_frame.json')
|
||||
debug.g_ProfilerSystem.CaptureFrame(capture_file)
|
||||
|
||||
# Invoke main function
|
||||
if __name__ == '__main__':
|
||||
test_profiler_system()
|
||||
@@ -1,124 +0,0 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
import os, traceback, binascii, sys, json, pathlib, logging
|
||||
import azlmbr.math
|
||||
import azlmbr.bus
|
||||
from scene_helpers import *
|
||||
|
||||
#
|
||||
# SceneAPI Processor
|
||||
#
|
||||
|
||||
def update_manifest(scene):
|
||||
import uuid
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
from scene_api import scene_data as sceneData
|
||||
|
||||
graph = sceneData.SceneGraph(scene.graph)
|
||||
# Get a list of all the mesh nodes, as well as all the nodes
|
||||
mesh_name_list, all_node_paths = get_mesh_node_names(graph)
|
||||
mesh_name_list.sort(key=lambda node: str.casefold(node.get_path()))
|
||||
scene_manifest = sceneData.SceneManifest()
|
||||
|
||||
clean_filename = scene.sourceFilename.replace('.', '_')
|
||||
|
||||
# Compute the filename of the scene file
|
||||
source_basepath = scene.watchFolder
|
||||
source_relative_path = os.path.dirname(os.path.relpath(clean_filename, source_basepath))
|
||||
source_filename_only = os.path.basename(clean_filename)
|
||||
|
||||
created_entities = []
|
||||
previous_entity_id = azlmbr.entity.InvalidEntityId
|
||||
first_mesh = True
|
||||
|
||||
# Make a list of mesh node paths
|
||||
mesh_path_list = list(map(lambda node: node.get_path(), mesh_name_list))
|
||||
|
||||
# Assume the first mesh is the main mesh
|
||||
main_mesh = mesh_name_list[0]
|
||||
mesh_path = main_mesh.get_path()
|
||||
|
||||
# Create a unique mesh group name using the filename + node name
|
||||
mesh_group_name = '{}_{}'.format(source_filename_only, main_mesh.get_name())
|
||||
# Remove forbidden filename characters from the name since this will become a file on disk later
|
||||
mesh_group_name = "".join(char for char in mesh_group_name if char not in "|<>:\"/?*\\")
|
||||
# Add the MeshGroup to the manifest and give it a unique ID
|
||||
mesh_group = scene_manifest.add_mesh_group(mesh_group_name)
|
||||
mesh_group['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, source_filename_only + mesh_path)) + '}'
|
||||
# Set our current node as the only node that is included in this MeshGroup
|
||||
scene_manifest.mesh_group_select_node(mesh_group, mesh_path)
|
||||
|
||||
# Explicitly remove all other nodes to prevent implicit inclusions
|
||||
for node in mesh_path_list:
|
||||
if node != mesh_path:
|
||||
scene_manifest.mesh_group_unselect_node(mesh_group, node)
|
||||
|
||||
# Create a LOD rule
|
||||
lod_rule = scene_manifest.mesh_group_add_lod_rule(mesh_group)
|
||||
|
||||
# Loop all the mesh nodes after the first
|
||||
for x in mesh_path_list[1:]:
|
||||
# Add a new LOD level
|
||||
lod = scene_manifest.lod_rule_add_lod(lod_rule)
|
||||
# Select the current mesh for this LOD level
|
||||
scene_manifest.lod_select_node(lod, x)
|
||||
|
||||
# Unselect every other mesh for this LOD level
|
||||
for y in mesh_path_list:
|
||||
if y != x:
|
||||
scene_manifest.lod_unselect_node(lod, y)
|
||||
|
||||
# Create an editor entity
|
||||
entity_id = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "CreateEditorReadyEntity", mesh_group_name)
|
||||
# Add an EditorMeshComponent to the entity
|
||||
editor_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "AZ::Render::EditorMeshComponent")
|
||||
# Set the ModelAsset assetHint to the relative path of the input asset + the name of the MeshGroup we just created + the azmodel extension
|
||||
# The MeshGroup we created will be output as a product in the asset's path named mesh_group_name.azmodel
|
||||
# The assetHint will be converted to an AssetId later during prefab loading
|
||||
json_update = json.dumps({
|
||||
"Controller": { "Configuration": { "ModelAsset": {
|
||||
"assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}}
|
||||
});
|
||||
# Apply the JSON above to the component we created
|
||||
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_mesh_component, json_update)
|
||||
|
||||
if not result:
|
||||
raise RuntimeError("UpdateComponentForEntity failed for Mesh component")
|
||||
|
||||
create_prefab(scene_manifest, source_filename_only, [entity_id])
|
||||
|
||||
# Convert the manifest to a JSON string and return it
|
||||
new_manifest = scene_manifest.export()
|
||||
|
||||
return new_manifest
|
||||
|
||||
sceneJobHandler = None
|
||||
|
||||
def on_update_manifest(args):
|
||||
try:
|
||||
scene = args[0]
|
||||
return update_manifest(scene)
|
||||
except RuntimeError as err:
|
||||
print (f'ERROR - {err}')
|
||||
log_exception_traceback()
|
||||
except:
|
||||
log_exception_traceback()
|
||||
|
||||
global sceneJobHandler
|
||||
sceneJobHandler = None
|
||||
|
||||
# try to create SceneAPI handler for processing
|
||||
try:
|
||||
import azlmbr.scene as sceneApi
|
||||
if (sceneJobHandler == None):
|
||||
sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler()
|
||||
sceneJobHandler.connect()
|
||||
sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
|
||||
except:
|
||||
sceneJobHandler = None
|
||||
@@ -1,63 +0,0 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
import traceback, sys, uuid, os, json
|
||||
|
||||
#
|
||||
# Utility methods for processing scenes
|
||||
#
|
||||
|
||||
def log_exception_traceback():
|
||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||
data = traceback.format_exception(exc_type, exc_value, exc_tb)
|
||||
print(str(data))
|
||||
|
||||
def get_node_names(sceneGraph, nodeTypeName, testEndPoint = False, validList = None):
|
||||
import azlmbr.scene.graph
|
||||
import scene_api.scene_data
|
||||
|
||||
node = sceneGraph.get_root()
|
||||
nodeList = []
|
||||
children = []
|
||||
paths = []
|
||||
|
||||
while node.IsValid():
|
||||
# store children to process after siblings
|
||||
if sceneGraph.has_node_child(node):
|
||||
children.append(sceneGraph.get_node_child(node))
|
||||
|
||||
nodeName = scene_api.scene_data.SceneGraphName(sceneGraph.get_node_name(node))
|
||||
paths.append(nodeName.get_path())
|
||||
|
||||
include = True
|
||||
|
||||
if (validList is not None):
|
||||
include = False # if a valid list filter provided, assume to not include node name
|
||||
name_parts = nodeName.get_path().split('.')
|
||||
for valid in validList:
|
||||
if (valid in name_parts[-1]):
|
||||
include = True
|
||||
break
|
||||
|
||||
# store any node that has provides specifc data content
|
||||
nodeContent = sceneGraph.get_node_content(node)
|
||||
if include and nodeContent.CastWithTypeName(nodeTypeName):
|
||||
if testEndPoint is not None:
|
||||
include = sceneGraph.is_node_end_point(node) is testEndPoint
|
||||
if include:
|
||||
if (len(nodeName.get_path())):
|
||||
nodeList.append(scene_api.scene_data.SceneGraphName(sceneGraph.get_node_name(node)))
|
||||
|
||||
# advance to next node
|
||||
if sceneGraph.has_node_sibling(node):
|
||||
node = sceneGraph.get_node_sibling(node)
|
||||
elif children:
|
||||
node = children.pop()
|
||||
else:
|
||||
node = azlmbr.scene.graph.NodeIndex()
|
||||
|
||||
return nodeList, paths
|
||||
@@ -1,109 +0,0 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
import traceback, logging, json
|
||||
from typing import Tuple, List
|
||||
|
||||
import azlmbr.bus
|
||||
from scene_api import scene_data as sceneData
|
||||
from scene_api.scene_data import SceneGraphName
|
||||
|
||||
|
||||
def log_exception_traceback():
|
||||
"""Outputs an exception stacktrace."""
|
||||
data = traceback.format_exc()
|
||||
logger = logging.getLogger('python')
|
||||
logger.error(data)
|
||||
|
||||
|
||||
def sanitize_name_for_disk(name: str) -> str:
|
||||
"""Removes illegal filename characters from a string.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name :
|
||||
String to clean.
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
Name with illegal characters removed.
|
||||
|
||||
"""
|
||||
return "".join(char for char in name if char not in "|<>:\"/?*\\")
|
||||
|
||||
|
||||
def get_mesh_node_names(scene_graph: sceneData.SceneGraph) -> Tuple[List[SceneGraphName], List[str]]:
|
||||
"""Returns a tuple of all the mesh nodes as well as all the node paths
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scene_graph :
|
||||
Scene graph to search
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
Tuple[List[SceneGraphName], List[str]]
|
||||
Tuple of [Mesh Nodes, All Node Paths]
|
||||
|
||||
"""
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
|
||||
mesh_data_list = []
|
||||
node = scene_graph.get_root()
|
||||
children = []
|
||||
paths = []
|
||||
|
||||
while node.IsValid():
|
||||
# store children to process after siblings
|
||||
if scene_graph.has_node_child(node):
|
||||
children.append(scene_graph.get_node_child(node))
|
||||
|
||||
node_name = sceneData.SceneGraphName(scene_graph.get_node_name(node))
|
||||
paths.append(node_name.get_path())
|
||||
|
||||
# store any node that has mesh data content
|
||||
node_content = scene_graph.get_node_content(node)
|
||||
if node_content.CastWithTypeName('MeshData'):
|
||||
if scene_graph.is_node_end_point(node) is False:
|
||||
if len(node_name.get_path()):
|
||||
mesh_data_list.append(sceneData.SceneGraphName(scene_graph.get_node_name(node)))
|
||||
|
||||
# advance to next node
|
||||
if scene_graph.has_node_sibling(node):
|
||||
node = scene_graph.get_node_sibling(node)
|
||||
elif children:
|
||||
node = children.pop()
|
||||
else:
|
||||
node = azlmbr.scene.graph.NodeIndex()
|
||||
|
||||
return mesh_data_list, paths
|
||||
|
||||
|
||||
def create_prefab(scene_manifest: sceneData.SceneManifest, prefab_name: str, entities: list) -> None:
|
||||
prefab_filename = prefab_name + ".prefab"
|
||||
created_template_id = azlmbr.prefab.PrefabSystemScriptingBus(azlmbr.bus.Broadcast, "CreatePrefab", entities,
|
||||
prefab_filename)
|
||||
|
||||
if created_template_id is None or created_template_id == azlmbr.prefab.InvalidTemplateId:
|
||||
raise RuntimeError("CreatePrefab {} failed".format(prefab_filename))
|
||||
|
||||
# Convert the prefab to a JSON string
|
||||
output = azlmbr.prefab.PrefabLoaderScriptingBus(azlmbr.bus.Broadcast, "SaveTemplateToString", created_template_id)
|
||||
|
||||
if output is not None and output.IsSuccess():
|
||||
json_string = output.GetValue()
|
||||
uuid = azlmbr.math.Uuid_CreateRandom().ToString()
|
||||
json_result = json.loads(json_string)
|
||||
# Add a PrefabGroup to the manifest and store the JSON on it
|
||||
scene_manifest.add_prefab_group(prefab_name, uuid, json_result)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"SaveTemplateToString failed for template id {}, prefab {}".format(created_template_id, prefab_filename))
|
||||
@@ -5,17 +5,55 @@
|
||||
# SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
#
|
||||
#
|
||||
import azlmbr.bus
|
||||
import os, traceback, binascii, sys, json, pathlib
|
||||
import azlmbr.math
|
||||
|
||||
from scene_api.scene_data import PrimitiveShape, DecompositionMode, ColorChannel, TangentSpaceSource, TangentSpaceMethod
|
||||
from scene_helpers import *
|
||||
|
||||
import azlmbr.bus
|
||||
|
||||
#
|
||||
# SceneAPI Processor
|
||||
#
|
||||
|
||||
|
||||
def log_exception_traceback():
|
||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||
data = traceback.format_exception(exc_type, exc_value, exc_tb)
|
||||
print(str(data))
|
||||
|
||||
def get_mesh_node_names(sceneGraph):
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
from scene_api import scene_data as sceneData
|
||||
|
||||
meshDataList = []
|
||||
node = sceneGraph.get_root()
|
||||
children = []
|
||||
paths = []
|
||||
|
||||
while node.IsValid():
|
||||
# store children to process after siblings
|
||||
if sceneGraph.has_node_child(node):
|
||||
children.append(sceneGraph.get_node_child(node))
|
||||
|
||||
nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node))
|
||||
paths.append(nodeName.get_path())
|
||||
|
||||
# store any node that has mesh data content
|
||||
nodeContent = sceneGraph.get_node_content(node)
|
||||
if nodeContent.CastWithTypeName('MeshData'):
|
||||
if sceneGraph.is_node_end_point(node) is False:
|
||||
if (len(nodeName.get_path())):
|
||||
meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node)))
|
||||
|
||||
# advance to next node
|
||||
if sceneGraph.has_node_sibling(node):
|
||||
node = sceneGraph.get_node_sibling(node)
|
||||
elif children:
|
||||
node = children.pop()
|
||||
else:
|
||||
node = azlmbr.scene.graph.NodeIndex()
|
||||
|
||||
return meshDataList, paths
|
||||
|
||||
def add_material_component(entity_id):
|
||||
# Create an override AZ::Render::EditorMaterialComponent
|
||||
editor_material_component = azlmbr.entity.EntityUtilityBus(
|
||||
@@ -26,54 +64,24 @@ def add_material_component(entity_id):
|
||||
|
||||
# this fills out the material asset to a known product AZMaterial asset relative path
|
||||
json_update = json.dumps({
|
||||
"Controller": {"Configuration": {"materials": [
|
||||
{
|
||||
"Key": {},
|
||||
"Value": {"MaterialAsset": {
|
||||
"assetHint": "materials/basic_grey.azmaterial"
|
||||
}}
|
||||
}]
|
||||
}}
|
||||
})
|
||||
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id,
|
||||
editor_material_component, json_update)
|
||||
"Controller": { "Configuration": { "materials": [
|
||||
{
|
||||
"Key": {},
|
||||
"Value": { "MaterialAsset":{
|
||||
"assetHint": "materials/basic_grey.azmaterial"
|
||||
}}
|
||||
}]
|
||||
}}
|
||||
});
|
||||
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_material_component, json_update)
|
||||
|
||||
if not result:
|
||||
raise RuntimeError("UpdateComponentForEntity for editor_material_component failed")
|
||||
|
||||
|
||||
def add_physx_meshes(scene_manifest: sceneData.SceneManifest, source_file_name: str, mesh_name_list: List, all_node_paths: List[str]):
|
||||
first_mesh = mesh_name_list[0].get_path()
|
||||
|
||||
# Add a Box Primitive PhysX mesh with a comment
|
||||
physx_box = scene_manifest.add_physx_primitive_mesh_group(source_file_name + "_box", PrimitiveShape.BOX, 0.0, None)
|
||||
scene_manifest.physx_mesh_group_add_comment(physx_box, "This is a box primitive")
|
||||
# Select the first mesh, unselect every other node
|
||||
scene_manifest.physx_mesh_group_add_selected_node(physx_box, first_mesh)
|
||||
|
||||
for node in all_node_paths:
|
||||
if node != first_mesh:
|
||||
scene_manifest.physx_mesh_group_add_unselected_node(physx_box, node)
|
||||
|
||||
# Add a Convex Mesh PhysX mesh with a comment
|
||||
convex_mesh = scene_manifest.add_physx_convex_mesh_group(source_file_name + "_convex", 0.08, .0004,
|
||||
True, True, True, True, True, 24, True, "Glass")
|
||||
scene_manifest.physx_mesh_group_add_comment(convex_mesh, "This is a convex mesh")
|
||||
# Select/Unselect nodes using lists
|
||||
all_except_first_mesh = [x for x in all_node_paths if x != first_mesh]
|
||||
scene_manifest.physx_mesh_group_add_selected_unselected_nodes(convex_mesh, [first_mesh], all_except_first_mesh)
|
||||
|
||||
# Configure mesh decomposition for this mesh
|
||||
scene_manifest.physx_mesh_group_decompose_meshes(convex_mesh, 512, 32, .002, 100100, DecompositionMode.TETRAHEDRON,
|
||||
0.06, 0.055, 0.00015, 3, 3, True, False)
|
||||
|
||||
# Add a Triangle mesh
|
||||
triangle = scene_manifest.add_physx_triangle_mesh_group(source_file_name + "_triangle", False, True, True, True, True, True)
|
||||
scene_manifest.physx_mesh_group_add_selected_unselected_nodes(triangle, [first_mesh], all_except_first_mesh)
|
||||
|
||||
|
||||
def update_manifest(scene):
|
||||
import json
|
||||
import uuid, os
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
from scene_api import scene_data as sceneData
|
||||
|
||||
@@ -81,9 +89,9 @@ def update_manifest(scene):
|
||||
# Get a list of all the mesh nodes, as well as all the nodes
|
||||
mesh_name_list, all_node_paths = get_mesh_node_names(graph)
|
||||
scene_manifest = sceneData.SceneManifest()
|
||||
|
||||
|
||||
clean_filename = scene.sourceFilename.replace('.', '_')
|
||||
|
||||
|
||||
# Compute the filename of the scene file
|
||||
source_basepath = scene.watchFolder
|
||||
source_relative_path = os.path.dirname(os.path.relpath(clean_filename, source_basepath))
|
||||
@@ -93,8 +101,6 @@ def update_manifest(scene):
|
||||
previous_entity_id = azlmbr.entity.InvalidEntityId
|
||||
first_mesh = True
|
||||
|
||||
add_physx_meshes(scene_manifest, source_filename_only, mesh_name_list, all_node_paths)
|
||||
|
||||
# Loop every mesh node in the scene
|
||||
for activeMeshIndex in range(len(mesh_name_list)):
|
||||
mesh_name = mesh_name_list[activeMeshIndex]
|
||||
@@ -102,83 +108,52 @@ def update_manifest(scene):
|
||||
# Create a unique mesh group name using the filename + node name
|
||||
mesh_group_name = '{}_{}'.format(source_filename_only, mesh_name.get_name())
|
||||
# Remove forbidden filename characters from the name since this will become a file on disk later
|
||||
mesh_group_name = sanitize_name_for_disk(mesh_group_name)
|
||||
mesh_group_name = "".join(char for char in mesh_group_name if char not in "|<>:\"/?*\\")
|
||||
# Add the MeshGroup to the manifest and give it a unique ID
|
||||
mesh_group = scene_manifest.add_mesh_group(mesh_group_name)
|
||||
mesh_group['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, source_filename_only + mesh_path)) + '}'
|
||||
# Set our current node as the only node that is included in this MeshGroup
|
||||
scene_manifest.mesh_group_select_node(mesh_group, mesh_path)
|
||||
scene_manifest.mesh_group_add_comment(mesh_group, "Hello World")
|
||||
|
||||
# Explicitly remove all other nodes to prevent implicit inclusions
|
||||
for node in all_node_paths:
|
||||
if node != mesh_path:
|
||||
scene_manifest.mesh_group_unselect_node(mesh_group, node)
|
||||
|
||||
scene_manifest.mesh_group_add_cloth_rule(mesh_group, mesh_path, "Col0", ColorChannel.GREEN, "Col0",
|
||||
ColorChannel.BLUE, "Col0", ColorChannel.BLUE, ColorChannel.ALPHA)
|
||||
scene_manifest.mesh_group_add_advanced_mesh_rule(mesh_group, True, False, True, "Col0")
|
||||
scene_manifest.mesh_group_add_skin_rule(mesh_group, 3, 0.002)
|
||||
scene_manifest.mesh_group_add_tangent_rule(mesh_group, TangentSpaceSource.MIKKT_GENERATION, TangentSpaceMethod.TSPACE_BASIC)
|
||||
|
||||
# Create an editor entity
|
||||
entity_id = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "CreateEditorReadyEntity", mesh_group_name)
|
||||
# Add an EditorMeshComponent to the entity
|
||||
editor_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName",
|
||||
entity_id, "AZ::Render::EditorMeshComponent")
|
||||
# Set the ModelAsset assetHint to the relative path of the input asset + the name of the MeshGroup we just
|
||||
# created + the azmodel extension The MeshGroup we created will be output as a product in the asset's path
|
||||
# named mesh_group_name.azmodel The assetHint will be converted to an AssetId later during prefab loading
|
||||
editor_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "AZ::Render::EditorMeshComponent")
|
||||
# Set the ModelAsset assetHint to the relative path of the input asset + the name of the MeshGroup we just created + the azmodel extension
|
||||
# The MeshGroup we created will be output as a product in the asset's path named mesh_group_name.azmodel
|
||||
# The assetHint will be converted to an AssetId later during prefab loading
|
||||
json_update = json.dumps({
|
||||
"Controller": {"Configuration": {"ModelAsset": {
|
||||
"assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel"}}}
|
||||
})
|
||||
"Controller": { "Configuration": { "ModelAsset": {
|
||||
"assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}}
|
||||
});
|
||||
# Apply the JSON above to the component we created
|
||||
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id,
|
||||
editor_mesh_component, json_update)
|
||||
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_mesh_component, json_update)
|
||||
|
||||
if not result:
|
||||
raise RuntimeError("UpdateComponentForEntity failed for Mesh component")
|
||||
|
||||
# Add a physics component referencing the triangle mesh we made for the first node
|
||||
if previous_entity_id is None:
|
||||
physx_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName",
|
||||
entity_id, "{FD429282-A075-4966-857F-D0BBF186CFE6} EditorColliderComponent")
|
||||
|
||||
json_update = json.dumps({
|
||||
"ShapeConfiguration": {
|
||||
"PhysicsAsset": {
|
||||
"Asset": {
|
||||
"assetHint": os.path.join(source_relative_path, source_filename_only + "_triangle.pxmesh")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, physx_mesh_component, json_update)
|
||||
|
||||
if not result:
|
||||
raise RuntimeError("UpdateComponentForEntity failed for PhysX mesh component")
|
||||
|
||||
# an example of adding a material component to override the default material
|
||||
if previous_entity_id is not None and first_mesh:
|
||||
first_mesh = False
|
||||
add_material_component(entity_id)
|
||||
|
||||
# Get the transform component
|
||||
transform_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName",
|
||||
entity_id, "27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0")
|
||||
transform_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0")
|
||||
|
||||
# Set this entity to be a child of the last entity we created
|
||||
# This is just an example of how to do parenting and isn't necessarily useful to parent everything like this
|
||||
if previous_entity_id is not None:
|
||||
transform_json = json.dumps({
|
||||
"Parent Entity": previous_entity_id.to_json()
|
||||
})
|
||||
"Parent Entity" : previous_entity_id.to_json()
|
||||
});
|
||||
|
||||
# Apply the JSON update
|
||||
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id,
|
||||
transform_component, transform_json)
|
||||
result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, transform_component, transform_json)
|
||||
|
||||
if not result:
|
||||
raise RuntimeError("UpdateComponentForEntity failed for Transform component")
|
||||
@@ -190,23 +165,37 @@ def update_manifest(scene):
|
||||
created_entities.append(entity_id)
|
||||
|
||||
# Create a prefab with all our entities
|
||||
create_prefab(scene_manifest, source_filename_only, created_entities)
|
||||
prefab_filename = source_filename_only + ".prefab"
|
||||
created_template_id = azlmbr.prefab.PrefabSystemScriptingBus(azlmbr.bus.Broadcast, "CreatePrefab", created_entities, prefab_filename)
|
||||
|
||||
if created_template_id == azlmbr.prefab.InvalidTemplateId:
|
||||
raise RuntimeError("CreatePrefab {} failed".format(prefab_filename))
|
||||
|
||||
# Convert the prefab to a JSON string
|
||||
output = azlmbr.prefab.PrefabLoaderScriptingBus(azlmbr.bus.Broadcast, "SaveTemplateToString", created_template_id)
|
||||
|
||||
if output.IsSuccess():
|
||||
jsonString = output.GetValue()
|
||||
uuid = azlmbr.math.Uuid_CreateRandom().ToString()
|
||||
jsonResult = json.loads(jsonString)
|
||||
# Add a PrefabGroup to the manifest and store the JSON on it
|
||||
scene_manifest.add_prefab_group(source_filename_only, uuid, jsonResult)
|
||||
else:
|
||||
raise RuntimeError("SaveTemplateToString failed for template id {}, prefab {}".format(created_template_id, prefab_filename))
|
||||
|
||||
# Convert the manifest to a JSON string and return it
|
||||
new_manifest = scene_manifest.export()
|
||||
|
||||
return new_manifest
|
||||
|
||||
|
||||
sceneJobHandler = None
|
||||
|
||||
|
||||
def on_update_manifest(args):
|
||||
try:
|
||||
scene = args[0]
|
||||
return update_manifest(scene)
|
||||
except RuntimeError as err:
|
||||
print(f'ERROR - {err}')
|
||||
print (f'ERROR - {err}')
|
||||
log_exception_traceback()
|
||||
except:
|
||||
log_exception_traceback()
|
||||
@@ -214,12 +203,10 @@ def on_update_manifest(args):
|
||||
global sceneJobHandler
|
||||
sceneJobHandler = None
|
||||
|
||||
|
||||
# try to create SceneAPI handler for processing
|
||||
try:
|
||||
import azlmbr.scene as sceneApi
|
||||
|
||||
if sceneJobHandler is None:
|
||||
if (sceneJobHandler == None):
|
||||
sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler()
|
||||
sceneJobHandler.connect()
|
||||
sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
"AssetProcessor": {
|
||||
"Settings": {
|
||||
"Exclude PythonTest Benchmark Settings Assets": {
|
||||
"pattern": "(^|.+/)PythonTests/.*benchmarksettings"
|
||||
"pattern": ".*\\\\/PythonTests\\\\/.*benchmarksettings"
|
||||
},
|
||||
"Exclude fbx_tests": {
|
||||
"pattern": "(^|.+/)fbx_tests/assets(/.+)$"
|
||||
"pattern": ".*\\\\/fbx_tests\\\\/assets\\\\/.*"
|
||||
},
|
||||
"Exclude wwise_bank_dependency_tests": {
|
||||
"pattern": "(^|.+/)wwise_bank_dependency_tests/assets(/.+)$"
|
||||
"pattern": ".*\\\\/wwise_bank_dependency_tests\\\\/assets\\\\/.*"
|
||||
},
|
||||
"Exclude AssetProcessorTestAssets": {
|
||||
"pattern": "(^|.+/)asset_processor_tests/assets(/.+)$"
|
||||
"pattern": ".*\\\\/asset_processor_tests\\\\/assets\\\\/.*"
|
||||
},
|
||||
"Exclude Restricted AssetProcessorTestAssets": {
|
||||
"pattern": "(^|.+/)asset_processor_tests/restricted(/.+)$"
|
||||
"pattern": ".*\\\\/asset_processor_tests\\\\/restricted\\\\/.*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
#
|
||||
#
|
||||
|
||||
set(gem_path ${CMAKE_CURRENT_LIST_DIR})
|
||||
set(gem_json ${gem_path}/gem.json)
|
||||
o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path)
|
||||
|
||||
add_subdirectory(Code)
|
||||
add_subdirectory(PythonTests)
|
||||
add_subdirectory(PythonTests)
|
||||
add_subdirectory(PythonCoverage)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
#
|
||||
|
||||
o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path})
|
||||
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
|
||||
|
||||
ly_add_target(
|
||||
NAME AutomatedTesting ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
|
||||
@@ -14,25 +14,15 @@ ly_add_target(
|
||||
FILES_CMAKE
|
||||
automatedtesting_files.cmake
|
||||
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
|
||||
automatedtesting_autogen_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
Source
|
||||
PUBLIC
|
||||
Include
|
||||
BUILD_DEPENDENCIES
|
||||
PUBLIC
|
||||
AZ::AzNetworking
|
||||
Gem::Multiplayer
|
||||
PRIVATE
|
||||
AZ::AzCore
|
||||
Gem::Atom_AtomBridge.Static
|
||||
Gem::Multiplayer.Static
|
||||
AUTOGEN_RULES
|
||||
*.AutoComponent.xml,AutoComponent_Header.jinja,$path/$fileprefix.AutoComponent.h
|
||||
*.AutoComponent.xml,AutoComponent_Source.jinja,$path/$fileprefix.AutoComponent.cpp
|
||||
*.AutoComponent.xml,AutoComponentTypes_Header.jinja,$path/AutoComponentTypes.h
|
||||
*.AutoComponent.xml,AutoComponentTypes_Source.jinja,$path/AutoComponentTypes.cpp
|
||||
)
|
||||
|
||||
# if enabled, AutomatedTesting is used by all kinds of applications
|
||||
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<Component
|
||||
Name="NetworkTestLevelEntityComponent"
|
||||
Namespace="AutomatedTesting"
|
||||
OverrideComponent="false"
|
||||
OverrideController="false"
|
||||
OverrideInclude=""
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<ComponentRelation Constraint="Required" HasController="true" Name="NetworkTransformComponent" Namespace="Multiplayer" Include="Multiplayer/Components/NetworkTransformComponent.h" />
|
||||
|
||||
<RemoteProcedure Name="AuthorityToClientNoParams_PlayFx" InvokeFrom="Authority" HandleOn="Client" IsPublic="false" IsReliable="true" GenerateEventBindings="true" Description="" />
|
||||
|
||||
</Component>
|
||||
@@ -1,39 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<Component
|
||||
Name="NetworkTestPlayerComponent"
|
||||
Namespace="AutomatedTesting"
|
||||
OverrideComponent="false"
|
||||
OverrideController="false"
|
||||
OverrideInclude=""
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<ComponentRelation Constraint="Required" HasController="true" Name="NetworkTransformComponent" Namespace="Multiplayer" Include="Multiplayer/Components/NetworkTransformComponent.h" />
|
||||
|
||||
<NetworkInput Type="float" Name="FwdBack" Init="0.0f" ExposeToScript="true"/>
|
||||
<NetworkInput Type="float" Name="LeftRight" Init="0.0f" ExposeToScript="true"/>
|
||||
|
||||
<RemoteProcedure Name="AutonomousToAuthority" InvokeFrom="Autonomous" HandleOn="Authority" IsPublic="false" IsReliable="false" GenerateEventBindings="true" Description="" >
|
||||
<Param Type="float" Name="SomeFloat" />
|
||||
</RemoteProcedure>
|
||||
|
||||
<RemoteProcedure Name="AutonomousToAuthorityNoParams" InvokeFrom="Autonomous" HandleOn="Authority" IsPublic="false" IsReliable="false" GenerateEventBindings="true" Description="" />
|
||||
|
||||
<RemoteProcedure Name="AuthorityToAutonomous_PlayerNumber" InvokeFrom="Authority" HandleOn="Autonomous" IsPublic="false" IsReliable="true" GenerateEventBindings="true" Description="" >
|
||||
<Param Type="int" Name="player_number" />
|
||||
</RemoteProcedure>
|
||||
|
||||
<RemoteProcedure Name="AuthorityToAutonomousNoParams" InvokeFrom="Authority" HandleOn="Autonomous" IsPublic="false" IsReliable="false" GenerateEventBindings="true" Description="" />
|
||||
|
||||
<RemoteProcedure Name="AuthorityToClient" InvokeFrom="Authority" HandleOn="Client" IsPublic="false" IsReliable="false" GenerateEventBindings="true" Description="" >
|
||||
<Param Type="float" Name="SomeFloat" />
|
||||
</RemoteProcedure>
|
||||
|
||||
<RemoteProcedure Name="ServerToAuthority_DealDamage" InvokeFrom="Server" HandleOn="Authority" IsPublic="false" IsReliable="true" GenerateEventBindings="true" Description="" >
|
||||
<Param Type="float" Name="damage" />
|
||||
</RemoteProcedure>
|
||||
|
||||
<RemoteProcedure Name="ServerToAuthorityNoParam" InvokeFrom="Server" HandleOn="Authority" IsPublic="false" IsReliable="false" GenerateEventBindings="true" Description="" />
|
||||
|
||||
|
||||
</Component>
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Module/Module.h>
|
||||
#include <Source/AutoGen/AutoComponentTypes.h>
|
||||
|
||||
#include <AutomatedTestingSystemComponent.h>
|
||||
|
||||
@@ -28,8 +27,6 @@ namespace AutomatedTesting
|
||||
m_descriptors.insert(m_descriptors.end(), {
|
||||
AutomatedTestingSystemComponent::CreateDescriptor(),
|
||||
});
|
||||
|
||||
CreateComponentDescriptors(m_descriptors); //< Register multiplayer components
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/EditContextConstants.inl>
|
||||
#include <Source/AutoGen/AutoComponentTypes.h>
|
||||
|
||||
#include <AutomatedTestingSystemComponent.h>
|
||||
|
||||
@@ -46,7 +45,7 @@ namespace AutomatedTesting
|
||||
|
||||
void AutomatedTestingSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC_CE("MultiplayerService"));
|
||||
AZ_UNUSED(required);
|
||||
}
|
||||
|
||||
void AutomatedTestingSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
@@ -61,7 +60,6 @@ namespace AutomatedTesting
|
||||
void AutomatedTestingSystemComponent::Activate()
|
||||
{
|
||||
AutomatedTestingRequestBus::Handler::BusConnect();
|
||||
RegisterMultiplayerComponents(); //< Register AutomatedTesting's multiplayer components to assign NetComponentIds
|
||||
}
|
||||
|
||||
void AutomatedTestingSystemComponent::Deactivate()
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
|
||||
set(FILES
|
||||
${LY_ROOT_FOLDER}/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Common.jinja
|
||||
${LY_ROOT_FOLDER}/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja
|
||||
${LY_ROOT_FOLDER}/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja
|
||||
${LY_ROOT_FOLDER}/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponentTypes_Header.jinja
|
||||
${LY_ROOT_FOLDER}/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponentTypes_Source.jinja
|
||||
)
|
||||
@@ -11,6 +11,4 @@ set(FILES
|
||||
Source/AutomatedTestingModule.cpp
|
||||
Source/AutomatedTestingSystemComponent.cpp
|
||||
Source/AutomatedTestingSystemComponent.h
|
||||
Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml
|
||||
Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml
|
||||
)
|
||||
|
||||
@@ -56,5 +56,4 @@ set(ENABLED_GEMS
|
||||
AudioSystem
|
||||
Terrain
|
||||
Profiler
|
||||
Multiplayer
|
||||
)
|
||||
|
||||
@@ -6,8 +6,4 @@
|
||||
#
|
||||
#
|
||||
|
||||
set(gem_path ${CMAKE_CURRENT_LIST_DIR})
|
||||
set(gem_json ${gem_path}/gem.json)
|
||||
o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path)
|
||||
|
||||
add_subdirectory(Code)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
#
|
||||
|
||||
o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path})
|
||||
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_gem_restricted_path} ${o3de_gem_path} ${o3de_gem_name})
|
||||
include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
|
||||
|
||||
if(PAL_TRAIT_PYTHONCOVERAGE_SUPPORTED)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
"license": "Apache-2.0 Or MIT",
|
||||
"license_url": "https://github.com/o3de/o3de/blob/development/LICENSE.txt",
|
||||
"origin": "Open 3D Engine - o3de.org",
|
||||
"origin_url": "https://github.com/o3de/o3de",
|
||||
"type": "Tool",
|
||||
"summary": "A tool for generating gem coverage for Python tests.",
|
||||
"canonical_tags": [
|
||||
@@ -14,8 +13,5 @@
|
||||
"PythonCoverage"
|
||||
],
|
||||
"icon_path": "preview.png",
|
||||
"requirements": "",
|
||||
"documentation_url": "",
|
||||
"dependencies": [
|
||||
]
|
||||
"requirements": ""
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:de0e6e480ece5b423222f4feacf56553d73713fe9afea8bbc9a2660a3cd54ec7
|
||||
size 1232
|
||||
oid sha256:6d6204c6730e5675791765ca194e9b1cbec282208e280507de830afc2805e5fa
|
||||
size 41127
|
||||
|
||||
@@ -12,12 +12,18 @@
|
||||
################################################################################
|
||||
|
||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
# Only enable AWS automated tests on Windows
|
||||
if(NOT "${PAL_PLATFORM_NAME}" STREQUAL "Windows")
|
||||
return()
|
||||
endif()
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::AWSTests
|
||||
TEST_SUITE awsi
|
||||
TEST_SERIAL
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/${PAL_PLATFORM_NAME}/
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
AZ::AssetProcessor
|
||||
AutomatedTesting.GameLauncher
|
||||
AutomatedTesting.Assets
|
||||
|
||||
@@ -2,61 +2,30 @@
|
||||
|
||||
## Prerequisites
|
||||
1. Build the O3DE Editor and AutomatedTesting.GameLauncher in Profile.
|
||||
2. Install the latest version of NodeJs.
|
||||
3. AWS CLI is installed and AWS crendentials are configured via [environment variables](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html) or [default profile](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html).
|
||||
4. [AWS Cloud Development Kit (CDK)](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html#getting_started_install) is installed.
|
||||
2. AWS CLI is installed and configured following [Configuration and Credential File Settings](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html).
|
||||
3. [AWS Cloud Development Kit (CDK)](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html#getting_started_install) is installed.
|
||||
|
||||
## Deploy CDK Applications
|
||||
1. Go to the AWS IAM console and create an IAM role called o3de-automation-tests which adds your own account as as a trusted entity and uses the "AdministratorAccess" permissions policy.
|
||||
2. Copy the following deployment script to your engine root folder:
|
||||
* Windows (Command Prompt)
|
||||
```
|
||||
{engine_root}\scripts\build\Platform\Windows\deploy_cdk_applications.cmd
|
||||
```
|
||||
* Linux
|
||||
```
|
||||
{engine_root}/scripts/build/Platform/Linux/deploy_cdk_applications.sh
|
||||
```
|
||||
3. Open a new CLI window at the engine root and set the following environment variables:
|
||||
* Windows
|
||||
```
|
||||
Set O3DE_AWS_PROJECT_NAME=AWSAUTO
|
||||
Set O3DE_AWS_DEPLOY_REGION=us-east-1
|
||||
Set ASSUME_ROLE_ARN=arn:aws:iam::{your_aws_account_id}:role/o3de-automation-tests
|
||||
Set COMMIT_ID=HEAD
|
||||
```
|
||||
* Linux
|
||||
```
|
||||
export O3DE_AWS_PROJECT_NAME=AWSAUTO
|
||||
export O3DE_AWS_DEPLOY_REGION=us-east-1
|
||||
export ASSUME_ROLE_ARN=arn:aws:iam::{your_aws_account_id}:role/o3de-automation-tests
|
||||
export COMMIT_ID=HEAD
|
||||
```
|
||||
4. In the same CLI window, Deploy the CDK applications for AWS gems by running deploy_cdk_applications.cmd.
|
||||
2. Copy {engine_root}\scripts\build\Platform\Windows\deploy_cdk_applications.cmd to your engine root folder.
|
||||
3. Open a new Command Prompt window at the engine root and set the following environment variables:
|
||||
```
|
||||
Set O3DE_AWS_PROJECT_NAME=AWSAUTO
|
||||
Set O3DE_AWS_DEPLOY_REGION=us-east-1
|
||||
Set O3DE_AWS_DEPLOY_ACCOUNT={your_aws_account_id}
|
||||
Set ASSUME_ROLE_ARN=arn:aws:iam::{your_aws_account_id}:role/o3de-automation-tests
|
||||
Set COMMIT_ID=HEAD
|
||||
```
|
||||
4. In the same Command Prompt window, Deploy the CDK applications for AWS gems by running deploy_cdk_applications.cmd.
|
||||
|
||||
## Run Automation Tests
|
||||
### CLI
|
||||
1. In the same CLI window, run the following CLI command:
|
||||
* Windows
|
||||
```
|
||||
python\python.cmd -m pytest {path_to_the_test_file} --build-directory {directory_to_the_profile_build}
|
||||
```
|
||||
* Linux
|
||||
```
|
||||
python/python.sh -m pytest {path_to_the_test_file} --build-directory {directory_to_the_profile_build}
|
||||
```
|
||||
In the same Command Prompt window, run the following CLI command:
|
||||
python\python.cmd -m pytest {path_to_the_test_file} --build-directory {directory_to_the_profile_build}
|
||||
|
||||
### Pycharm
|
||||
You can also run any specific automation test directly from Pycharm by providing the "--build-directory" argument in the Run Configuration.
|
||||
|
||||
## Destroy CDK Applications
|
||||
1. Copy the following destruction script to your engine root folder:
|
||||
* Windows
|
||||
```
|
||||
{engine_root}\scripts\build\Platform\Windows\destroy_cdk_applications.cmd
|
||||
```
|
||||
* Linux
|
||||
```
|
||||
{engine_root}/scripts/build/Platform/Linux/destroy_cdk_applications.sh
|
||||
```
|
||||
2. In the same CLI window, destroy the CDK applications for AWS gems by running destroy_cdk_applications.cmd.
|
||||
1. Copy {engine_root}\scripts\build\Platform\Windows\destroy_cdk_applications.cmd to your engine root folder.
|
||||
2. In the same Command Prompt window, destroy the CDK applications for AWS gems by running destroy_cdk_applications.cmd.
|
||||
@@ -0,0 +1,6 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
+289
-289
@@ -1,289 +1,289 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import pytest
|
||||
import typing
|
||||
from datetime import datetime
|
||||
|
||||
import ly_test_tools.log.log_monitor
|
||||
|
||||
from AWS.common import constants
|
||||
from AWS.common.resource_mappings import AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY
|
||||
from .aws_metrics_custom_thread import AWSMetricsThread
|
||||
|
||||
# fixture imports
|
||||
from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor
|
||||
from .aws_metrics_utils import aws_metrics_utils
|
||||
|
||||
AWS_METRICS_FEATURE_NAME = 'AWSMetrics'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup(launcher: pytest.fixture,
|
||||
asset_processor: pytest.fixture) -> pytest.fixture:
|
||||
"""
|
||||
Set up the resource mapping configuration and start the log monitor.
|
||||
:param launcher: Client launcher for running the test level.
|
||||
:param asset_processor: asset_processor fixture.
|
||||
:return log monitor object.
|
||||
"""
|
||||
asset_processor.start()
|
||||
asset_processor.wait_for_idle()
|
||||
|
||||
file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), constants.GAME_LOG_NAME)
|
||||
|
||||
# Initialize the log monitor.
|
||||
log_monitor = ly_test_tools.log.log_monitor.LogMonitor(launcher=launcher, log_file_path=file_to_monitor)
|
||||
|
||||
return log_monitor
|
||||
|
||||
|
||||
def monitor_metrics_submission(log_monitor: pytest.fixture) -> None:
|
||||
"""
|
||||
Monitor the messages and notifications for submitting metrics.
|
||||
:param log_monitor: Log monitor to check the log messages.
|
||||
"""
|
||||
expected_lines = [
|
||||
'(Script) - Submitted metrics without buffer.',
|
||||
'(Script) - Submitted metrics with buffer.',
|
||||
'(Script) - Flushed the buffered metrics.',
|
||||
'(Script) - Metrics is sent successfully.'
|
||||
]
|
||||
|
||||
unexpected_lines = [
|
||||
'(Script) - Failed to submit metrics without buffer.',
|
||||
'(Script) - Failed to submit metrics with buffer.',
|
||||
'(Script) - Failed to send metrics.'
|
||||
]
|
||||
|
||||
result = log_monitor.monitor_log_for_lines(
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True)
|
||||
|
||||
# Assert the log monitor detected expected lines and did not detect any unexpected lines.
|
||||
assert result, (
|
||||
f'Log monitoring failed. Used expected_lines values: {expected_lines} & '
|
||||
f'unexpected_lines values: {unexpected_lines}')
|
||||
|
||||
|
||||
def query_metrics_from_s3(aws_metrics_utils: pytest.fixture, resource_mappings: pytest.fixture) -> None:
|
||||
"""
|
||||
Verify that the metrics events are delivered to the S3 bucket and can be queried.
|
||||
:param aws_metrics_utils: aws_metrics_utils fixture.
|
||||
:param resource_mappings: resource_mappings fixture.
|
||||
"""
|
||||
aws_metrics_utils.verify_s3_delivery(
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsBucketName')
|
||||
)
|
||||
logger.info('Metrics are sent to S3.')
|
||||
|
||||
aws_metrics_utils.run_glue_crawler(
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.EventsCrawlerName'))
|
||||
|
||||
# Remove the events_json table if exists so that the sample query can create a table with the same name.
|
||||
aws_metrics_utils.delete_table(resource_mappings.get_resource_name_id('AWSMetrics.EventDatabaseName'), 'events_json')
|
||||
aws_metrics_utils.run_named_queries(resource_mappings.get_resource_name_id('AWSMetrics.AthenaWorkGroupName'))
|
||||
logger.info('Query metrics from S3 successfully.')
|
||||
|
||||
|
||||
def verify_operational_metrics(aws_metrics_utils: pytest.fixture,
|
||||
resource_mappings: pytest.fixture, start_time: datetime) -> None:
|
||||
"""
|
||||
Verify that operational health metrics are delivered to CloudWatch.
|
||||
:param aws_metrics_utils: aws_metrics_utils fixture.
|
||||
:param resource_mappings: resource_mappings fixture.
|
||||
:param start_time: Time when the game launcher starts.
|
||||
"""
|
||||
aws_metrics_utils.verify_cloud_watch_delivery(
|
||||
'AWS/Lambda',
|
||||
'Invocations',
|
||||
[{'Name': 'FunctionName',
|
||||
'Value': resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsProcessingLambdaName')}],
|
||||
start_time)
|
||||
logger.info('AnalyticsProcessingLambda metrics are sent to CloudWatch.')
|
||||
|
||||
aws_metrics_utils.verify_cloud_watch_delivery(
|
||||
'AWS/Lambda',
|
||||
'Invocations',
|
||||
[{'Name': 'FunctionName',
|
||||
'Value': resource_mappings.get_resource_name_id('AWSMetrics.EventProcessingLambdaName')}],
|
||||
start_time)
|
||||
logger.info('EventsProcessingLambda metrics are sent to CloudWatch.')
|
||||
|
||||
|
||||
def update_kinesis_analytics_application_status(aws_metrics_utils: pytest.fixture,
|
||||
resource_mappings: pytest.fixture, start_application: bool) -> None:
|
||||
"""
|
||||
Update the Kinesis analytics application to start or stop it.
|
||||
:param aws_metrics_utils: aws_metrics_utils fixture.
|
||||
:param resource_mappings: resource_mappings fixture.
|
||||
:param start_application: whether to start or stop the application.
|
||||
"""
|
||||
if start_application:
|
||||
aws_metrics_utils.start_kinesis_data_analytics_application(
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsApplicationName'))
|
||||
else:
|
||||
aws_metrics_utils.stop_kinesis_data_analytics_application(
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsApplicationName'))
|
||||
|
||||
@pytest.mark.SUITE_awsi
|
||||
@pytest.mark.usefixtures('automatic_process_killer')
|
||||
@pytest.mark.usefixtures('aws_credentials')
|
||||
@pytest.mark.usefixtures('resource_mappings')
|
||||
@pytest.mark.parametrize('assume_role_arn', [constants.ASSUME_ROLE_ARN])
|
||||
@pytest.mark.parametrize('feature_name', [AWS_METRICS_FEATURE_NAME])
|
||||
@pytest.mark.parametrize('profile_name', ['AWSAutomationTest'])
|
||||
@pytest.mark.parametrize('project', ['AutomatedTesting'])
|
||||
@pytest.mark.parametrize('region_name', [constants.AWS_REGION])
|
||||
@pytest.mark.parametrize('resource_mappings_filename', [constants.AWS_RESOURCE_MAPPING_FILE_NAME])
|
||||
@pytest.mark.parametrize('session_name', [constants.SESSION_NAME])
|
||||
@pytest.mark.parametrize('stacks', [[f'{constants.AWS_PROJECT_NAME}-{AWS_METRICS_FEATURE_NAME}-{constants.AWS_REGION}']])
|
||||
class TestAWSMetricsWindows(object):
|
||||
"""
|
||||
Test class to verify the real-time and batch analytics for metrics.
|
||||
"""
|
||||
@pytest.mark.parametrize('level', ['levels/aws/metrics/metrics.spawnable'])
|
||||
def test_realtime_and_batch_analytics(self,
|
||||
level: str,
|
||||
launcher: pytest.fixture,
|
||||
asset_processor: pytest.fixture,
|
||||
workspace: pytest.fixture,
|
||||
aws_utils: pytest.fixture,
|
||||
resource_mappings: pytest.fixture,
|
||||
aws_metrics_utils: pytest.fixture):
|
||||
"""
|
||||
Verify that the metrics events are sent to CloudWatch and S3 for analytics.
|
||||
"""
|
||||
# Start Kinesis analytics application on a separate thread to avoid blocking the test.
|
||||
kinesis_analytics_application_thread = AWSMetricsThread(target=update_kinesis_analytics_application_status,
|
||||
args=(aws_metrics_utils, resource_mappings, True))
|
||||
kinesis_analytics_application_thread.start()
|
||||
|
||||
log_monitor = setup(launcher, asset_processor)
|
||||
|
||||
# Kinesis analytics application needs to be in the running state before we start the game launcher.
|
||||
kinesis_analytics_application_thread.join()
|
||||
launcher.args = ['+LoadLevel', level]
|
||||
launcher.args.extend(['-rhi=null'])
|
||||
start_time = datetime.utcnow()
|
||||
with launcher.start(launch_ap=False):
|
||||
monitor_metrics_submission(log_monitor)
|
||||
|
||||
# Verify that real-time analytics metrics are delivered to CloudWatch.
|
||||
aws_metrics_utils.verify_cloud_watch_delivery(
|
||||
AWS_METRICS_FEATURE_NAME,
|
||||
'TotalLogins',
|
||||
[],
|
||||
start_time)
|
||||
logger.info('Real-time metrics are sent to CloudWatch.')
|
||||
|
||||
# Run time-consuming operations on separate threads to avoid blocking the test.
|
||||
operational_threads = list()
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=query_metrics_from_s3,
|
||||
args=(aws_metrics_utils, resource_mappings)))
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=verify_operational_metrics,
|
||||
args=(aws_metrics_utils, resource_mappings, start_time)))
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=update_kinesis_analytics_application_status,
|
||||
args=(aws_metrics_utils, resource_mappings, False)))
|
||||
for thread in operational_threads:
|
||||
thread.start()
|
||||
for thread in operational_threads:
|
||||
thread.join()
|
||||
|
||||
@pytest.mark.parametrize('level', ['levels/aws/metrics/metrics.spawnable'])
|
||||
def test_realtime_and_batch_analytics_no_global_accountid(self,
|
||||
level: str,
|
||||
launcher: pytest.fixture,
|
||||
asset_processor: pytest.fixture,
|
||||
workspace: pytest.fixture,
|
||||
aws_utils: pytest.fixture,
|
||||
resource_mappings: pytest.fixture,
|
||||
aws_metrics_utils: pytest.fixture):
|
||||
"""
|
||||
Verify that the metrics events are sent to CloudWatch and S3 for analytics.
|
||||
"""
|
||||
# Remove top-level account ID from resource mappings
|
||||
resource_mappings.clear_select_keys([AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY])
|
||||
# Start Kinesis analytics application on a separate thread to avoid blocking the test.
|
||||
kinesis_analytics_application_thread = AWSMetricsThread(target=update_kinesis_analytics_application_status,
|
||||
args=(aws_metrics_utils, resource_mappings, True))
|
||||
kinesis_analytics_application_thread.start()
|
||||
|
||||
log_monitor = setup(launcher, asset_processor)
|
||||
|
||||
# Kinesis analytics application needs to be in the running state before we start the game launcher.
|
||||
kinesis_analytics_application_thread.join()
|
||||
launcher.args = ['+LoadLevel', level]
|
||||
launcher.args.extend(['-rhi=null'])
|
||||
start_time = datetime.utcnow()
|
||||
with launcher.start(launch_ap=False):
|
||||
monitor_metrics_submission(log_monitor)
|
||||
|
||||
# Verify that real-time analytics metrics are delivered to CloudWatch.
|
||||
aws_metrics_utils.verify_cloud_watch_delivery(
|
||||
AWS_METRICS_FEATURE_NAME,
|
||||
'TotalLogins',
|
||||
[],
|
||||
start_time)
|
||||
logger.info('Real-time metrics are sent to CloudWatch.')
|
||||
|
||||
# Run time-consuming operations on separate threads to avoid blocking the test.
|
||||
operational_threads = list()
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=query_metrics_from_s3,
|
||||
args=(aws_metrics_utils, resource_mappings)))
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=verify_operational_metrics,
|
||||
args=(aws_metrics_utils, resource_mappings, start_time)))
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=update_kinesis_analytics_application_status,
|
||||
args=(aws_metrics_utils, resource_mappings, False)))
|
||||
for thread in operational_threads:
|
||||
thread.start()
|
||||
for thread in operational_threads:
|
||||
thread.join()
|
||||
|
||||
@pytest.mark.parametrize('level', ['levels/aws/metrics/metrics.spawnable'])
|
||||
def test_unauthorized_user_request_rejected(self,
|
||||
level: str,
|
||||
launcher: pytest.fixture,
|
||||
asset_processor: pytest.fixture,
|
||||
workspace: pytest.fixture):
|
||||
"""
|
||||
Verify that unauthorized users cannot send metrics events to the AWS backed backend.
|
||||
"""
|
||||
log_monitor = setup(launcher, asset_processor)
|
||||
|
||||
# Set invalid AWS credentials.
|
||||
launcher.args = ['+LoadLevel', level, '+cl_awsAccessKey', 'AKIAIOSFODNN7EXAMPLE',
|
||||
'+cl_awsSecretKey', 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY']
|
||||
launcher.args.extend(['-rhi=null'])
|
||||
|
||||
with launcher.start(launch_ap=False):
|
||||
result = log_monitor.monitor_log_for_lines(
|
||||
expected_lines=['(Script) - Failed to send metrics.'],
|
||||
unexpected_lines=['(Script) - Metrics is sent successfully.'],
|
||||
halt_on_unexpected=True)
|
||||
assert result, 'Metrics events are sent successfully by unauthorized user'
|
||||
logger.info('Unauthorized user is rejected to send metrics.')
|
||||
|
||||
def test_clean_up_s3_bucket(self,
|
||||
aws_utils: pytest.fixture,
|
||||
resource_mappings: pytest.fixture,
|
||||
aws_metrics_utils: pytest.fixture):
|
||||
"""
|
||||
Clear the analytics bucket objects so that the S3 bucket can be destroyed during tear down.
|
||||
"""
|
||||
aws_metrics_utils.empty_bucket(
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsBucketName'))
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import pytest
|
||||
import typing
|
||||
from datetime import datetime
|
||||
|
||||
import ly_test_tools.log.log_monitor
|
||||
|
||||
from AWS.common import constants
|
||||
from AWS.common.resource_mappings import AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY
|
||||
from .aws_metrics_custom_thread import AWSMetricsThread
|
||||
|
||||
# fixture imports
|
||||
from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor
|
||||
from .aws_metrics_utils import aws_metrics_utils
|
||||
|
||||
AWS_METRICS_FEATURE_NAME = 'AWSMetrics'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup(launcher: pytest.fixture,
|
||||
asset_processor: pytest.fixture) -> pytest.fixture:
|
||||
"""
|
||||
Set up the resource mapping configuration and start the log monitor.
|
||||
:param launcher: Client launcher for running the test level.
|
||||
:param asset_processor: asset_processor fixture.
|
||||
:return log monitor object.
|
||||
"""
|
||||
asset_processor.start()
|
||||
asset_processor.wait_for_idle()
|
||||
|
||||
file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), constants.GAME_LOG_NAME)
|
||||
|
||||
# Initialize the log monitor.
|
||||
log_monitor = ly_test_tools.log.log_monitor.LogMonitor(launcher=launcher, log_file_path=file_to_monitor)
|
||||
|
||||
return log_monitor
|
||||
|
||||
|
||||
def monitor_metrics_submission(log_monitor: pytest.fixture) -> None:
|
||||
"""
|
||||
Monitor the messages and notifications for submitting metrics.
|
||||
:param log_monitor: Log monitor to check the log messages.
|
||||
"""
|
||||
expected_lines = [
|
||||
'(Script) - Submitted metrics without buffer.',
|
||||
'(Script) - Submitted metrics with buffer.',
|
||||
'(Script) - Flushed the buffered metrics.',
|
||||
'(Script) - Metrics is sent successfully.'
|
||||
]
|
||||
|
||||
unexpected_lines = [
|
||||
'(Script) - Failed to submit metrics without buffer.',
|
||||
'(Script) - Failed to submit metrics with buffer.',
|
||||
'(Script) - Failed to send metrics.'
|
||||
]
|
||||
|
||||
result = log_monitor.monitor_log_for_lines(
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True)
|
||||
|
||||
# Assert the log monitor detected expected lines and did not detect any unexpected lines.
|
||||
assert result, (
|
||||
f'Log monitoring failed. Used expected_lines values: {expected_lines} & '
|
||||
f'unexpected_lines values: {unexpected_lines}')
|
||||
|
||||
|
||||
def query_metrics_from_s3(aws_metrics_utils: pytest.fixture, resource_mappings: pytest.fixture) -> None:
|
||||
"""
|
||||
Verify that the metrics events are delivered to the S3 bucket and can be queried.
|
||||
:param aws_metrics_utils: aws_metrics_utils fixture.
|
||||
:param resource_mappings: resource_mappings fixture.
|
||||
"""
|
||||
aws_metrics_utils.verify_s3_delivery(
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsBucketName')
|
||||
)
|
||||
logger.info('Metrics are sent to S3.')
|
||||
|
||||
aws_metrics_utils.run_glue_crawler(
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.EventsCrawlerName'))
|
||||
|
||||
# Remove the events_json table if exists so that the sample query can create a table with the same name.
|
||||
aws_metrics_utils.delete_table(resource_mappings.get_resource_name_id('AWSMetrics.EventDatabaseName'), 'events_json')
|
||||
aws_metrics_utils.run_named_queries(resource_mappings.get_resource_name_id('AWSMetrics.AthenaWorkGroupName'))
|
||||
logger.info('Query metrics from S3 successfully.')
|
||||
|
||||
|
||||
def verify_operational_metrics(aws_metrics_utils: pytest.fixture,
|
||||
resource_mappings: pytest.fixture, start_time: datetime) -> None:
|
||||
"""
|
||||
Verify that operational health metrics are delivered to CloudWatch.
|
||||
:param aws_metrics_utils: aws_metrics_utils fixture.
|
||||
:param resource_mappings: resource_mappings fixture.
|
||||
:param start_time: Time when the game launcher starts.
|
||||
"""
|
||||
aws_metrics_utils.verify_cloud_watch_delivery(
|
||||
'AWS/Lambda',
|
||||
'Invocations',
|
||||
[{'Name': 'FunctionName',
|
||||
'Value': resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsProcessingLambdaName')}],
|
||||
start_time)
|
||||
logger.info('AnalyticsProcessingLambda metrics are sent to CloudWatch.')
|
||||
|
||||
aws_metrics_utils.verify_cloud_watch_delivery(
|
||||
'AWS/Lambda',
|
||||
'Invocations',
|
||||
[{'Name': 'FunctionName',
|
||||
'Value': resource_mappings.get_resource_name_id('AWSMetrics.EventProcessingLambdaName')}],
|
||||
start_time)
|
||||
logger.info('EventsProcessingLambda metrics are sent to CloudWatch.')
|
||||
|
||||
|
||||
def update_kinesis_analytics_application_status(aws_metrics_utils: pytest.fixture,
|
||||
resource_mappings: pytest.fixture, start_application: bool) -> None:
|
||||
"""
|
||||
Update the Kinesis analytics application to start or stop it.
|
||||
:param aws_metrics_utils: aws_metrics_utils fixture.
|
||||
:param resource_mappings: resource_mappings fixture.
|
||||
:param start_application: whether to start or stop the application.
|
||||
"""
|
||||
if start_application:
|
||||
aws_metrics_utils.start_kinesis_data_analytics_application(
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsApplicationName'))
|
||||
else:
|
||||
aws_metrics_utils.stop_kinesis_data_analytics_application(
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsApplicationName'))
|
||||
|
||||
@pytest.mark.SUITE_awsi
|
||||
@pytest.mark.usefixtures('automatic_process_killer')
|
||||
@pytest.mark.usefixtures('aws_credentials')
|
||||
@pytest.mark.usefixtures('resource_mappings')
|
||||
@pytest.mark.parametrize('assume_role_arn', [constants.ASSUME_ROLE_ARN])
|
||||
@pytest.mark.parametrize('feature_name', [AWS_METRICS_FEATURE_NAME])
|
||||
@pytest.mark.parametrize('profile_name', ['AWSAutomationTest'])
|
||||
@pytest.mark.parametrize('project', ['AutomatedTesting'])
|
||||
@pytest.mark.parametrize('region_name', [constants.AWS_REGION])
|
||||
@pytest.mark.parametrize('resource_mappings_filename', [constants.AWS_RESOURCE_MAPPING_FILE_NAME])
|
||||
@pytest.mark.parametrize('session_name', [constants.SESSION_NAME])
|
||||
@pytest.mark.parametrize('stacks', [[f'{constants.AWS_PROJECT_NAME}-{AWS_METRICS_FEATURE_NAME}-{constants.AWS_REGION}']])
|
||||
class TestAWSMetricsWindows(object):
|
||||
"""
|
||||
Test class to verify the real-time and batch analytics for metrics.
|
||||
"""
|
||||
@pytest.mark.parametrize('level', ['AWS/Metrics'])
|
||||
def test_realtime_and_batch_analytics(self,
|
||||
level: str,
|
||||
launcher: pytest.fixture,
|
||||
asset_processor: pytest.fixture,
|
||||
workspace: pytest.fixture,
|
||||
aws_utils: pytest.fixture,
|
||||
resource_mappings: pytest.fixture,
|
||||
aws_metrics_utils: pytest.fixture):
|
||||
"""
|
||||
Verify that the metrics events are sent to CloudWatch and S3 for analytics.
|
||||
"""
|
||||
# Start Kinesis analytics application on a separate thread to avoid blocking the test.
|
||||
kinesis_analytics_application_thread = AWSMetricsThread(target=update_kinesis_analytics_application_status,
|
||||
args=(aws_metrics_utils, resource_mappings, True))
|
||||
kinesis_analytics_application_thread.start()
|
||||
|
||||
log_monitor = setup(launcher, asset_processor)
|
||||
|
||||
# Kinesis analytics application needs to be in the running state before we start the game launcher.
|
||||
kinesis_analytics_application_thread.join()
|
||||
launcher.args = ['+LoadLevel', level]
|
||||
launcher.args.extend(['-rhi=null'])
|
||||
start_time = datetime.utcnow()
|
||||
with launcher.start(launch_ap=False):
|
||||
monitor_metrics_submission(log_monitor)
|
||||
|
||||
# Verify that real-time analytics metrics are delivered to CloudWatch.
|
||||
aws_metrics_utils.verify_cloud_watch_delivery(
|
||||
AWS_METRICS_FEATURE_NAME,
|
||||
'TotalLogins',
|
||||
[],
|
||||
start_time)
|
||||
logger.info('Real-time metrics are sent to CloudWatch.')
|
||||
|
||||
# Run time-consuming operations on separate threads to avoid blocking the test.
|
||||
operational_threads = list()
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=query_metrics_from_s3,
|
||||
args=(aws_metrics_utils, resource_mappings)))
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=verify_operational_metrics,
|
||||
args=(aws_metrics_utils, resource_mappings, start_time)))
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=update_kinesis_analytics_application_status,
|
||||
args=(aws_metrics_utils, resource_mappings, False)))
|
||||
for thread in operational_threads:
|
||||
thread.start()
|
||||
for thread in operational_threads:
|
||||
thread.join()
|
||||
|
||||
@pytest.mark.parametrize('level', ['AWS/Metrics'])
|
||||
def test_realtime_and_batch_analytics_no_global_accountid(self,
|
||||
level: str,
|
||||
launcher: pytest.fixture,
|
||||
asset_processor: pytest.fixture,
|
||||
workspace: pytest.fixture,
|
||||
aws_utils: pytest.fixture,
|
||||
resource_mappings: pytest.fixture,
|
||||
aws_metrics_utils: pytest.fixture):
|
||||
"""
|
||||
Verify that the metrics events are sent to CloudWatch and S3 for analytics.
|
||||
"""
|
||||
# Remove top-level account ID from resource mappings
|
||||
resource_mappings.clear_select_keys([AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY])
|
||||
# Start Kinesis analytics application on a separate thread to avoid blocking the test.
|
||||
kinesis_analytics_application_thread = AWSMetricsThread(target=update_kinesis_analytics_application_status,
|
||||
args=(aws_metrics_utils, resource_mappings, True))
|
||||
kinesis_analytics_application_thread.start()
|
||||
|
||||
log_monitor = setup(launcher, asset_processor)
|
||||
|
||||
# Kinesis analytics application needs to be in the running state before we start the game launcher.
|
||||
kinesis_analytics_application_thread.join()
|
||||
launcher.args = ['+LoadLevel', level]
|
||||
launcher.args.extend(['-rhi=null'])
|
||||
start_time = datetime.utcnow()
|
||||
with launcher.start(launch_ap=False):
|
||||
monitor_metrics_submission(log_monitor)
|
||||
|
||||
# Verify that real-time analytics metrics are delivered to CloudWatch.
|
||||
aws_metrics_utils.verify_cloud_watch_delivery(
|
||||
AWS_METRICS_FEATURE_NAME,
|
||||
'TotalLogins',
|
||||
[],
|
||||
start_time)
|
||||
logger.info('Real-time metrics are sent to CloudWatch.')
|
||||
|
||||
# Run time-consuming operations on separate threads to avoid blocking the test.
|
||||
operational_threads = list()
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=query_metrics_from_s3,
|
||||
args=(aws_metrics_utils, resource_mappings)))
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=verify_operational_metrics,
|
||||
args=(aws_metrics_utils, resource_mappings, start_time)))
|
||||
operational_threads.append(
|
||||
AWSMetricsThread(target=update_kinesis_analytics_application_status,
|
||||
args=(aws_metrics_utils, resource_mappings, False)))
|
||||
for thread in operational_threads:
|
||||
thread.start()
|
||||
for thread in operational_threads:
|
||||
thread.join()
|
||||
|
||||
@pytest.mark.parametrize('level', ['AWS/Metrics'])
|
||||
def test_unauthorized_user_request_rejected(self,
|
||||
level: str,
|
||||
launcher: pytest.fixture,
|
||||
asset_processor: pytest.fixture,
|
||||
workspace: pytest.fixture):
|
||||
"""
|
||||
Verify that unauthorized users cannot send metrics events to the AWS backed backend.
|
||||
"""
|
||||
log_monitor = setup(launcher, asset_processor)
|
||||
|
||||
# Set invalid AWS credentials.
|
||||
launcher.args = ['+LoadLevel', level, '+cl_awsAccessKey', 'AKIAIOSFODNN7EXAMPLE',
|
||||
'+cl_awsSecretKey', 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY']
|
||||
launcher.args.extend(['-rhi=null'])
|
||||
|
||||
with launcher.start(launch_ap=False):
|
||||
result = log_monitor.monitor_log_for_lines(
|
||||
expected_lines=['(Script) - Failed to send metrics.'],
|
||||
unexpected_lines=['(Script) - Metrics is sent successfully.'],
|
||||
halt_on_unexpected=True)
|
||||
assert result, 'Metrics events are sent successfully by unauthorized user'
|
||||
logger.info('Unauthorized user is rejected to send metrics.')
|
||||
|
||||
def test_clean_up_s3_bucket(self,
|
||||
aws_utils: pytest.fixture,
|
||||
resource_mappings: pytest.fixture,
|
||||
aws_metrics_utils: pytest.fixture):
|
||||
"""
|
||||
Clear the analytics bucket objects so that the S3 bucket can be destroyed during tear down.
|
||||
"""
|
||||
aws_metrics_utils.empty_bucket(
|
||||
resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsBucketName'))
|
||||
+29
-29
@@ -1,29 +1,29 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
from threading import Thread
|
||||
|
||||
|
||||
class AWSMetricsThread(Thread):
|
||||
"""
|
||||
Custom thread for raising assertion errors on the main thread.
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self._error = None
|
||||
|
||||
def run(self) -> None:
|
||||
try:
|
||||
super().run()
|
||||
except AssertionError as e:
|
||||
self._error = e
|
||||
|
||||
def join(self, **kwargs) -> None:
|
||||
super().join(**kwargs)
|
||||
|
||||
if self._error:
|
||||
raise AssertionError(self._error)
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
from threading import Thread
|
||||
|
||||
|
||||
class AWSMetricsThread(Thread):
|
||||
"""
|
||||
Custom thread for raising assertion errors on the main thread.
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self._error = None
|
||||
|
||||
def run(self) -> None:
|
||||
try:
|
||||
super().run()
|
||||
except AssertionError as e:
|
||||
self._error = e
|
||||
|
||||
def join(self, **kwargs) -> None:
|
||||
super().join(**kwargs)
|
||||
|
||||
if self._error:
|
||||
raise AssertionError(self._error)
|
||||
+239
-239
@@ -1,239 +1,239 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import logging
|
||||
import pathlib
|
||||
import pytest
|
||||
import typing
|
||||
|
||||
from datetime import datetime
|
||||
from botocore.exceptions import WaiterError
|
||||
|
||||
from .aws_metrics_waiters import KinesisAnalyticsApplicationUpdatedWaiter, \
|
||||
CloudWatchMetricsDeliveredWaiter, DataLakeMetricsDeliveredWaiter, GlueCrawlerReadyWaiter
|
||||
|
||||
logging.getLogger('boto').setLevel(logging.CRITICAL)
|
||||
|
||||
# Expected directory and file extension for the S3 objects.
|
||||
EXPECTED_S3_DIRECTORY = 'firehose_events/'
|
||||
EXPECTED_S3_OBJECT_EXTENSION = '.parquet'
|
||||
|
||||
|
||||
class AWSMetricsUtils:
|
||||
"""
|
||||
Provide utils functions for the AWSMetrics gem to interact with the deployed resources.
|
||||
"""
|
||||
|
||||
def __init__(self, aws_utils: pytest.fixture):
|
||||
self._aws_util = aws_utils
|
||||
|
||||
def start_kinesis_data_analytics_application(self, application_name: str) -> None:
|
||||
"""
|
||||
Start the Kenisis Data Analytics application for real-time analytics.
|
||||
:param application_name: Name of the Kenisis Data Analytics application.
|
||||
"""
|
||||
input_id = self.get_kinesis_analytics_application_input_id(application_name)
|
||||
assert input_id, 'invalid Kinesis Data Analytics application input.'
|
||||
|
||||
client = self._aws_util.client('kinesisanalytics')
|
||||
try:
|
||||
client.start_application(
|
||||
ApplicationName=application_name,
|
||||
InputConfigurations=[
|
||||
{
|
||||
'Id': input_id,
|
||||
'InputStartingPositionConfiguration': {
|
||||
'InputStartingPosition': 'NOW'
|
||||
}
|
||||
},
|
||||
]
|
||||
)
|
||||
except client.exceptions.ResourceInUseException:
|
||||
# The application has been started.
|
||||
return
|
||||
|
||||
try:
|
||||
KinesisAnalyticsApplicationUpdatedWaiter(client, 'RUNNING').wait(application_name=application_name)
|
||||
except WaiterError as e:
|
||||
assert False, f'Failed to start the Kinesis Data Analytics application: {str(e)}.'
|
||||
|
||||
def get_kinesis_analytics_application_input_id(self, application_name: str) -> str:
|
||||
"""
|
||||
Get the input ID for the Kenisis Data Analytics application.
|
||||
:param application_name: Name of the Kenisis Data Analytics application.
|
||||
:return: Input ID for the Kenisis Data Analytics application.
|
||||
"""
|
||||
client = self._aws_util.client('kinesisanalytics')
|
||||
response = client.describe_application(
|
||||
ApplicationName=application_name
|
||||
)
|
||||
if not response:
|
||||
return ''
|
||||
input_descriptions = response.get('ApplicationDetail', {}).get('InputDescriptions', [])
|
||||
if len(input_descriptions) != 1:
|
||||
return ''
|
||||
|
||||
return input_descriptions[0].get('InputId', '')
|
||||
|
||||
def stop_kinesis_data_analytics_application(self, application_name: str) -> None:
|
||||
"""
|
||||
Stop the Kenisis Data Analytics application.
|
||||
:param application_name: Name of the Kenisis Data Analytics application.
|
||||
"""
|
||||
client = self._aws_util.client('kinesisanalytics')
|
||||
client.stop_application(
|
||||
ApplicationName=application_name
|
||||
)
|
||||
|
||||
try:
|
||||
KinesisAnalyticsApplicationUpdatedWaiter(client, 'READY').wait(application_name=application_name)
|
||||
except WaiterError as e:
|
||||
assert False, f'Failed to stop the Kinesis Data Analytics application: {str(e)}.'
|
||||
|
||||
def verify_cloud_watch_delivery(self, namespace: str, metrics_name: str,
|
||||
dimensions: typing.List[dict], start_time: datetime) -> None:
|
||||
"""
|
||||
Verify that the expected metrics is delivered to CloudWatch.
|
||||
:param namespace: Namespace of the metrics.
|
||||
:param metrics_name: Name of the metrics.
|
||||
:param dimensions: Dimensions of the metrics.
|
||||
:param start_time: Start time for generating the metrics.
|
||||
"""
|
||||
client = self._aws_util.client('cloudwatch')
|
||||
|
||||
try:
|
||||
CloudWatchMetricsDeliveredWaiter(client).wait(
|
||||
namespace=namespace,
|
||||
metrics_name=metrics_name,
|
||||
dimensions=dimensions,
|
||||
start_time=start_time
|
||||
)
|
||||
except WaiterError as e:
|
||||
assert False, f'Failed to deliver metrics to CloudWatch: {str(e)}.'
|
||||
|
||||
def verify_s3_delivery(self, analytics_bucket_name: str) -> None:
|
||||
"""
|
||||
Verify that metrics are delivered to S3 for batch analytics successfully.
|
||||
:param analytics_bucket_name: Name of the deployed S3 bucket.
|
||||
"""
|
||||
client = self._aws_util.client('s3')
|
||||
bucket_name = analytics_bucket_name
|
||||
|
||||
try:
|
||||
DataLakeMetricsDeliveredWaiter(client).wait(bucket_name=bucket_name, prefix=EXPECTED_S3_DIRECTORY)
|
||||
except WaiterError as e:
|
||||
assert False, f'Failed to find the S3 directory for storing metrics data: {str(e)}.'
|
||||
|
||||
# Check whether the data is converted to the expected data format.
|
||||
response = client.list_objects_v2(
|
||||
Bucket=bucket_name,
|
||||
Prefix=EXPECTED_S3_DIRECTORY
|
||||
)
|
||||
assert response.get('KeyCount', 0) != 0, f'Failed to deliver metrics to the S3 bucket {bucket_name}.'
|
||||
|
||||
s3_objects = response.get('Contents', [])
|
||||
for s3_object in s3_objects:
|
||||
key = s3_object.get('Key', '')
|
||||
assert pathlib.Path(key).suffix == EXPECTED_S3_OBJECT_EXTENSION, \
|
||||
f'Invalid data format is found in the S3 bucket {bucket_name}'
|
||||
|
||||
def run_glue_crawler(self, crawler_name: str) -> None:
|
||||
"""
|
||||
Run the Glue crawler and wait for it to finish.
|
||||
:param crawler_name: Name of the Glue crawler
|
||||
"""
|
||||
client = self._aws_util.client('glue')
|
||||
try:
|
||||
client.start_crawler(
|
||||
Name=crawler_name
|
||||
)
|
||||
except client.exceptions.CrawlerRunningException:
|
||||
# The crawler has already been started.
|
||||
return
|
||||
|
||||
try:
|
||||
GlueCrawlerReadyWaiter(client).wait(crawler_name=crawler_name)
|
||||
except WaiterError as e:
|
||||
assert False, f'Failed to run the Glue crawler: {str(e)}.'
|
||||
|
||||
def run_named_queries(self, work_group: str) -> None:
|
||||
"""
|
||||
Run the named queries under the specific Athena work group.
|
||||
:param work_group: Name of the Athena work group.
|
||||
"""
|
||||
client = self._aws_util.client('athena')
|
||||
# List all the named queries.
|
||||
response = client.list_named_queries(
|
||||
WorkGroup=work_group
|
||||
)
|
||||
named_query_ids = response.get('NamedQueryIds', [])
|
||||
|
||||
# Run each of the queries.
|
||||
for named_query_id in named_query_ids:
|
||||
get_named_query_response = client.get_named_query(
|
||||
NamedQueryId=named_query_id
|
||||
)
|
||||
named_query = get_named_query_response.get('NamedQuery', {})
|
||||
|
||||
start_query_execution_response = client.start_query_execution(
|
||||
QueryString=named_query.get('QueryString', ''),
|
||||
QueryExecutionContext={
|
||||
'Database': named_query.get('Database', '')
|
||||
},
|
||||
WorkGroup=work_group
|
||||
)
|
||||
|
||||
# Wait for the query to finish.
|
||||
state = 'RUNNING'
|
||||
while state == 'QUEUED' or state == 'RUNNING':
|
||||
get_query_execution_response = client.get_query_execution(
|
||||
QueryExecutionId=start_query_execution_response.get('QueryExecutionId', '')
|
||||
)
|
||||
|
||||
state = get_query_execution_response.get('QueryExecution', {}).get('Status', {}).get('State', '')
|
||||
|
||||
assert state == 'SUCCEEDED', f'Failed to run the named query {named_query.get("Name", {})}'
|
||||
|
||||
def empty_bucket(self, bucket_name: str) -> None:
|
||||
"""
|
||||
Empty the S3 bucket following:
|
||||
https://boto3.amazonaws.com/v1/documentation/api/latest/guide/migrations3.html
|
||||
|
||||
:param bucket_name: Name of the S3 bucket.
|
||||
"""
|
||||
s3 = self._aws_util.resource('s3')
|
||||
bucket = s3.Bucket(bucket_name)
|
||||
|
||||
for key in bucket.objects.all():
|
||||
key.delete()
|
||||
|
||||
def delete_table(self, database_name: str, table_name: str) -> None:
|
||||
"""
|
||||
Delete an existing Glue table.
|
||||
|
||||
:param database_name: Name of the Glue database.
|
||||
:param table_name: Name of the table to delete.
|
||||
"""
|
||||
client = self._aws_util.client('glue')
|
||||
client.delete_table(
|
||||
DatabaseName=database_name,
|
||||
Name=table_name
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def aws_metrics_utils(
|
||||
request: pytest.fixture,
|
||||
aws_utils: pytest.fixture):
|
||||
"""
|
||||
Fixture for the AWS metrics util functions.
|
||||
:param request: _pytest.fixtures.SubRequest class that handles getting
|
||||
a pytest fixture from a pytest function/fixture.
|
||||
:param aws_utils: aws_utils fixture.
|
||||
"""
|
||||
aws_utils_obj = AWSMetricsUtils(aws_utils)
|
||||
return aws_utils_obj
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import logging
|
||||
import pathlib
|
||||
import pytest
|
||||
import typing
|
||||
|
||||
from datetime import datetime
|
||||
from botocore.exceptions import WaiterError
|
||||
|
||||
from .aws_metrics_waiters import KinesisAnalyticsApplicationUpdatedWaiter, \
|
||||
CloudWatchMetricsDeliveredWaiter, DataLakeMetricsDeliveredWaiter, GlueCrawlerReadyWaiter
|
||||
|
||||
logging.getLogger('boto').setLevel(logging.CRITICAL)
|
||||
|
||||
# Expected directory and file extension for the S3 objects.
|
||||
EXPECTED_S3_DIRECTORY = 'firehose_events/'
|
||||
EXPECTED_S3_OBJECT_EXTENSION = '.parquet'
|
||||
|
||||
|
||||
class AWSMetricsUtils:
|
||||
"""
|
||||
Provide utils functions for the AWSMetrics gem to interact with the deployed resources.
|
||||
"""
|
||||
|
||||
def __init__(self, aws_utils: pytest.fixture):
|
||||
self._aws_util = aws_utils
|
||||
|
||||
def start_kinesis_data_analytics_application(self, application_name: str) -> None:
|
||||
"""
|
||||
Start the Kenisis Data Analytics application for real-time analytics.
|
||||
:param application_name: Name of the Kenisis Data Analytics application.
|
||||
"""
|
||||
input_id = self.get_kinesis_analytics_application_input_id(application_name)
|
||||
assert input_id, 'invalid Kinesis Data Analytics application input.'
|
||||
|
||||
client = self._aws_util.client('kinesisanalytics')
|
||||
try:
|
||||
client.start_application(
|
||||
ApplicationName=application_name,
|
||||
InputConfigurations=[
|
||||
{
|
||||
'Id': input_id,
|
||||
'InputStartingPositionConfiguration': {
|
||||
'InputStartingPosition': 'NOW'
|
||||
}
|
||||
},
|
||||
]
|
||||
)
|
||||
except client.exceptions.ResourceInUseException:
|
||||
# The application has been started.
|
||||
return
|
||||
|
||||
try:
|
||||
KinesisAnalyticsApplicationUpdatedWaiter(client, 'RUNNING').wait(application_name=application_name)
|
||||
except WaiterError as e:
|
||||
assert False, f'Failed to start the Kinesis Data Analytics application: {str(e)}.'
|
||||
|
||||
def get_kinesis_analytics_application_input_id(self, application_name: str) -> str:
|
||||
"""
|
||||
Get the input ID for the Kenisis Data Analytics application.
|
||||
:param application_name: Name of the Kenisis Data Analytics application.
|
||||
:return: Input ID for the Kenisis Data Analytics application.
|
||||
"""
|
||||
client = self._aws_util.client('kinesisanalytics')
|
||||
response = client.describe_application(
|
||||
ApplicationName=application_name
|
||||
)
|
||||
if not response:
|
||||
return ''
|
||||
input_descriptions = response.get('ApplicationDetail', {}).get('InputDescriptions', [])
|
||||
if len(input_descriptions) != 1:
|
||||
return ''
|
||||
|
||||
return input_descriptions[0].get('InputId', '')
|
||||
|
||||
def stop_kinesis_data_analytics_application(self, application_name: str) -> None:
|
||||
"""
|
||||
Stop the Kenisis Data Analytics application.
|
||||
:param application_name: Name of the Kenisis Data Analytics application.
|
||||
"""
|
||||
client = self._aws_util.client('kinesisanalytics')
|
||||
client.stop_application(
|
||||
ApplicationName=application_name
|
||||
)
|
||||
|
||||
try:
|
||||
KinesisAnalyticsApplicationUpdatedWaiter(client, 'READY').wait(application_name=application_name)
|
||||
except WaiterError as e:
|
||||
assert False, f'Failed to stop the Kinesis Data Analytics application: {str(e)}.'
|
||||
|
||||
def verify_cloud_watch_delivery(self, namespace: str, metrics_name: str,
|
||||
dimensions: typing.List[dict], start_time: datetime) -> None:
|
||||
"""
|
||||
Verify that the expected metrics is delivered to CloudWatch.
|
||||
:param namespace: Namespace of the metrics.
|
||||
:param metrics_name: Name of the metrics.
|
||||
:param dimensions: Dimensions of the metrics.
|
||||
:param start_time: Start time for generating the metrics.
|
||||
"""
|
||||
client = self._aws_util.client('cloudwatch')
|
||||
|
||||
try:
|
||||
CloudWatchMetricsDeliveredWaiter(client).wait(
|
||||
namespace=namespace,
|
||||
metrics_name=metrics_name,
|
||||
dimensions=dimensions,
|
||||
start_time=start_time
|
||||
)
|
||||
except WaiterError as e:
|
||||
assert False, f'Failed to deliver metrics to CloudWatch: {str(e)}.'
|
||||
|
||||
def verify_s3_delivery(self, analytics_bucket_name: str) -> None:
|
||||
"""
|
||||
Verify that metrics are delivered to S3 for batch analytics successfully.
|
||||
:param analytics_bucket_name: Name of the deployed S3 bucket.
|
||||
"""
|
||||
client = self._aws_util.client('s3')
|
||||
bucket_name = analytics_bucket_name
|
||||
|
||||
try:
|
||||
DataLakeMetricsDeliveredWaiter(client).wait(bucket_name=bucket_name, prefix=EXPECTED_S3_DIRECTORY)
|
||||
except WaiterError as e:
|
||||
assert False, f'Failed to find the S3 directory for storing metrics data: {str(e)}.'
|
||||
|
||||
# Check whether the data is converted to the expected data format.
|
||||
response = client.list_objects_v2(
|
||||
Bucket=bucket_name,
|
||||
Prefix=EXPECTED_S3_DIRECTORY
|
||||
)
|
||||
assert response.get('KeyCount', 0) != 0, f'Failed to deliver metrics to the S3 bucket {bucket_name}.'
|
||||
|
||||
s3_objects = response.get('Contents', [])
|
||||
for s3_object in s3_objects:
|
||||
key = s3_object.get('Key', '')
|
||||
assert pathlib.Path(key).suffix == EXPECTED_S3_OBJECT_EXTENSION, \
|
||||
f'Invalid data format is found in the S3 bucket {bucket_name}'
|
||||
|
||||
def run_glue_crawler(self, crawler_name: str) -> None:
|
||||
"""
|
||||
Run the Glue crawler and wait for it to finish.
|
||||
:param crawler_name: Name of the Glue crawler
|
||||
"""
|
||||
client = self._aws_util.client('glue')
|
||||
try:
|
||||
client.start_crawler(
|
||||
Name=crawler_name
|
||||
)
|
||||
except client.exceptions.CrawlerRunningException:
|
||||
# The crawler has already been started.
|
||||
return
|
||||
|
||||
try:
|
||||
GlueCrawlerReadyWaiter(client).wait(crawler_name=crawler_name)
|
||||
except WaiterError as e:
|
||||
assert False, f'Failed to run the Glue crawler: {str(e)}.'
|
||||
|
||||
def run_named_queries(self, work_group: str) -> None:
|
||||
"""
|
||||
Run the named queries under the specific Athena work group.
|
||||
:param work_group: Name of the Athena work group.
|
||||
"""
|
||||
client = self._aws_util.client('athena')
|
||||
# List all the named queries.
|
||||
response = client.list_named_queries(
|
||||
WorkGroup=work_group
|
||||
)
|
||||
named_query_ids = response.get('NamedQueryIds', [])
|
||||
|
||||
# Run each of the queries.
|
||||
for named_query_id in named_query_ids:
|
||||
get_named_query_response = client.get_named_query(
|
||||
NamedQueryId=named_query_id
|
||||
)
|
||||
named_query = get_named_query_response.get('NamedQuery', {})
|
||||
|
||||
start_query_execution_response = client.start_query_execution(
|
||||
QueryString=named_query.get('QueryString', ''),
|
||||
QueryExecutionContext={
|
||||
'Database': named_query.get('Database', '')
|
||||
},
|
||||
WorkGroup=work_group
|
||||
)
|
||||
|
||||
# Wait for the query to finish.
|
||||
state = 'RUNNING'
|
||||
while state == 'QUEUED' or state == 'RUNNING':
|
||||
get_query_execution_response = client.get_query_execution(
|
||||
QueryExecutionId=start_query_execution_response.get('QueryExecutionId', '')
|
||||
)
|
||||
|
||||
state = get_query_execution_response.get('QueryExecution', {}).get('Status', {}).get('State', '')
|
||||
|
||||
assert state == 'SUCCEEDED', f'Failed to run the named query {named_query.get("Name", {})}'
|
||||
|
||||
def empty_bucket(self, bucket_name: str) -> None:
|
||||
"""
|
||||
Empty the S3 bucket following:
|
||||
https://boto3.amazonaws.com/v1/documentation/api/latest/guide/migrations3.html
|
||||
|
||||
:param bucket_name: Name of the S3 bucket.
|
||||
"""
|
||||
s3 = self._aws_util.resource('s3')
|
||||
bucket = s3.Bucket(bucket_name)
|
||||
|
||||
for key in bucket.objects.all():
|
||||
key.delete()
|
||||
|
||||
def delete_table(self, database_name: str, table_name: str) -> None:
|
||||
"""
|
||||
Delete an existing Glue table.
|
||||
|
||||
:param database_name: Name of the Glue database.
|
||||
:param table_name: Name of the table to delete.
|
||||
"""
|
||||
client = self._aws_util.client('glue')
|
||||
client.delete_table(
|
||||
DatabaseName=database_name,
|
||||
Name=table_name
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def aws_metrics_utils(
|
||||
request: pytest.fixture,
|
||||
aws_utils: pytest.fixture):
|
||||
"""
|
||||
Fixture for the AWS metrics util functions.
|
||||
:param request: _pytest.fixtures.SubRequest class that handles getting
|
||||
a pytest fixture from a pytest function/fixture.
|
||||
:param aws_utils: aws_utils fixture.
|
||||
"""
|
||||
aws_utils_obj = AWSMetricsUtils(aws_utils)
|
||||
return aws_utils_obj
|
||||
+139
-139
@@ -1,139 +1,139 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import botocore.client
|
||||
import logging
|
||||
|
||||
from datetime import timedelta
|
||||
from AWS.common.custom_waiter import CustomWaiter, WaitState
|
||||
|
||||
logging.getLogger('boto').setLevel(logging.CRITICAL)
|
||||
|
||||
|
||||
class KinesisAnalyticsApplicationUpdatedWaiter(CustomWaiter):
|
||||
"""
|
||||
Subclass of the base custom waiter class.
|
||||
Wait for the Kinesis analytics application being updated to a specific status.
|
||||
"""
|
||||
def __init__(self, client: botocore.client, status: str):
|
||||
"""
|
||||
Initialize the waiter.
|
||||
|
||||
:param client: Boto3 client to use.
|
||||
:param status: Expected status.
|
||||
"""
|
||||
super().__init__(
|
||||
'KinesisAnalyticsApplicationUpdated',
|
||||
'DescribeApplication',
|
||||
'ApplicationDetail.ApplicationStatus',
|
||||
{status: WaitState.SUCCESS},
|
||||
client)
|
||||
|
||||
def wait(self, application_name: str):
|
||||
"""
|
||||
Wait for the expected status.
|
||||
|
||||
:param application_name: Name of the Kinesis analytics application.
|
||||
"""
|
||||
self._wait(ApplicationName=application_name)
|
||||
|
||||
|
||||
class GlueCrawlerReadyWaiter(CustomWaiter):
|
||||
"""
|
||||
Subclass of the base custom waiter class.
|
||||
Wait for the Glue crawler to finish its processing. Return when the crawler is in the "Stopping" status
|
||||
to avoid wasting too much time in the automation tests on its shutdown process.
|
||||
"""
|
||||
def __init__(self, client: botocore.client):
|
||||
"""
|
||||
Initialize the waiter.
|
||||
|
||||
:param client: Boto3 client to use.
|
||||
"""
|
||||
super().__init__(
|
||||
'GlueCrawlerReady',
|
||||
'GetCrawler',
|
||||
'Crawler.State',
|
||||
{'STOPPING': WaitState.SUCCESS},
|
||||
client)
|
||||
|
||||
def wait(self, crawler_name):
|
||||
"""
|
||||
Wait for the expected status.
|
||||
|
||||
:param crawler_name: Name of the Glue crawler.
|
||||
"""
|
||||
self._wait(Name=crawler_name)
|
||||
|
||||
|
||||
class DataLakeMetricsDeliveredWaiter(CustomWaiter):
|
||||
"""
|
||||
Subclass of the base custom waiter class.
|
||||
Wait for the expected directory being created in the S3 bucket.
|
||||
"""
|
||||
def __init__(self, client: botocore.client):
|
||||
"""
|
||||
Initialize the waiter.
|
||||
|
||||
:param client: Boto3 client to use.
|
||||
"""
|
||||
super().__init__(
|
||||
'DataLakeMetricsDelivered',
|
||||
'ListObjectsV2',
|
||||
'KeyCount > `0`',
|
||||
{True: WaitState.SUCCESS},
|
||||
client)
|
||||
|
||||
def wait(self, bucket_name, prefix):
|
||||
"""
|
||||
Wait for the expected directory being created.
|
||||
|
||||
:param bucket_name: Name of the S3 bucket.
|
||||
:param prefix: Name of the expected directory prefix.
|
||||
"""
|
||||
self._wait(Bucket=bucket_name, Prefix=prefix)
|
||||
|
||||
|
||||
class CloudWatchMetricsDeliveredWaiter(CustomWaiter):
|
||||
"""
|
||||
Subclass of the base custom waiter class.
|
||||
Wait for the expected metrics being delivered to CloudWatch.
|
||||
"""
|
||||
def __init__(self, client: botocore.client):
|
||||
"""
|
||||
Initialize the waiter.
|
||||
|
||||
:param client: Boto3 client to use.
|
||||
"""
|
||||
super().__init__(
|
||||
'CloudWatchMetricsDelivered',
|
||||
'GetMetricStatistics',
|
||||
'length(Datapoints) > `0`',
|
||||
{True: WaitState.SUCCESS},
|
||||
client)
|
||||
|
||||
def wait(self, namespace, metrics_name, dimensions, start_time):
|
||||
"""
|
||||
Wait for the expected metrics being delivered.
|
||||
|
||||
:param namespace: Namespace of the metrics.
|
||||
:param metrics_name: Name of the metrics.
|
||||
:param dimensions: Dimensions of the metrics.
|
||||
:param start_time: Start time for generating the metrics.
|
||||
"""
|
||||
self._wait(
|
||||
Namespace=namespace,
|
||||
MetricName=metrics_name,
|
||||
Dimensions=dimensions,
|
||||
StartTime=start_time,
|
||||
EndTime=start_time + timedelta(0, self.timeout),
|
||||
Period=60,
|
||||
Statistics=[
|
||||
'SampleCount'
|
||||
],
|
||||
Unit='Count'
|
||||
)
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import botocore.client
|
||||
import logging
|
||||
|
||||
from datetime import timedelta
|
||||
from AWS.common.custom_waiter import CustomWaiter, WaitState
|
||||
|
||||
logging.getLogger('boto').setLevel(logging.CRITICAL)
|
||||
|
||||
|
||||
class KinesisAnalyticsApplicationUpdatedWaiter(CustomWaiter):
|
||||
"""
|
||||
Subclass of the base custom waiter class.
|
||||
Wait for the Kinesis analytics application being updated to a specific status.
|
||||
"""
|
||||
def __init__(self, client: botocore.client, status: str):
|
||||
"""
|
||||
Initialize the waiter.
|
||||
|
||||
:param client: Boto3 client to use.
|
||||
:param status: Expected status.
|
||||
"""
|
||||
super().__init__(
|
||||
'KinesisAnalyticsApplicationUpdated',
|
||||
'DescribeApplication',
|
||||
'ApplicationDetail.ApplicationStatus',
|
||||
{status: WaitState.SUCCESS},
|
||||
client)
|
||||
|
||||
def wait(self, application_name: str):
|
||||
"""
|
||||
Wait for the expected status.
|
||||
|
||||
:param application_name: Name of the Kinesis analytics application.
|
||||
"""
|
||||
self._wait(ApplicationName=application_name)
|
||||
|
||||
|
||||
class GlueCrawlerReadyWaiter(CustomWaiter):
|
||||
"""
|
||||
Subclass of the base custom waiter class.
|
||||
Wait for the Glue crawler to finish its processing. Return when the crawler is in the "Stopping" status
|
||||
to avoid wasting too much time in the automation tests on its shutdown process.
|
||||
"""
|
||||
def __init__(self, client: botocore.client):
|
||||
"""
|
||||
Initialize the waiter.
|
||||
|
||||
:param client: Boto3 client to use.
|
||||
"""
|
||||
super().__init__(
|
||||
'GlueCrawlerReady',
|
||||
'GetCrawler',
|
||||
'Crawler.State',
|
||||
{'STOPPING': WaitState.SUCCESS},
|
||||
client)
|
||||
|
||||
def wait(self, crawler_name):
|
||||
"""
|
||||
Wait for the expected status.
|
||||
|
||||
:param crawler_name: Name of the Glue crawler.
|
||||
"""
|
||||
self._wait(Name=crawler_name)
|
||||
|
||||
|
||||
class DataLakeMetricsDeliveredWaiter(CustomWaiter):
|
||||
"""
|
||||
Subclass of the base custom waiter class.
|
||||
Wait for the expected directory being created in the S3 bucket.
|
||||
"""
|
||||
def __init__(self, client: botocore.client):
|
||||
"""
|
||||
Initialize the waiter.
|
||||
|
||||
:param client: Boto3 client to use.
|
||||
"""
|
||||
super().__init__(
|
||||
'DataLakeMetricsDelivered',
|
||||
'ListObjectsV2',
|
||||
'KeyCount > `0`',
|
||||
{True: WaitState.SUCCESS},
|
||||
client)
|
||||
|
||||
def wait(self, bucket_name, prefix):
|
||||
"""
|
||||
Wait for the expected directory being created.
|
||||
|
||||
:param bucket_name: Name of the S3 bucket.
|
||||
:param prefix: Name of the expected directory prefix.
|
||||
"""
|
||||
self._wait(Bucket=bucket_name, Prefix=prefix)
|
||||
|
||||
|
||||
class CloudWatchMetricsDeliveredWaiter(CustomWaiter):
|
||||
"""
|
||||
Subclass of the base custom waiter class.
|
||||
Wait for the expected metrics being delivered to CloudWatch.
|
||||
"""
|
||||
def __init__(self, client: botocore.client):
|
||||
"""
|
||||
Initialize the waiter.
|
||||
|
||||
:param client: Boto3 client to use.
|
||||
"""
|
||||
super().__init__(
|
||||
'CloudWatchMetricsDelivered',
|
||||
'GetMetricStatistics',
|
||||
'length(Datapoints) > `0`',
|
||||
{True: WaitState.SUCCESS},
|
||||
client)
|
||||
|
||||
def wait(self, namespace, metrics_name, dimensions, start_time):
|
||||
"""
|
||||
Wait for the expected metrics being delivered.
|
||||
|
||||
:param namespace: Namespace of the metrics.
|
||||
:param metrics_name: Name of the metrics.
|
||||
:param dimensions: Dimensions of the metrics.
|
||||
:param start_time: Start time for generating the metrics.
|
||||
"""
|
||||
self._wait(
|
||||
Namespace=namespace,
|
||||
MetricName=metrics_name,
|
||||
Dimensions=dimensions,
|
||||
StartTime=start_time,
|
||||
EndTime=start_time + timedelta(0, self.timeout),
|
||||
Period=60,
|
||||
Statistics=[
|
||||
'SampleCount'
|
||||
],
|
||||
Unit='Count'
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
+4
-4
@@ -40,7 +40,7 @@ class TestAWSClientAuthWindows(object):
|
||||
Test class to verify AWS Client Auth gem features on Windows.
|
||||
"""
|
||||
|
||||
@pytest.mark.parametrize('level', ['levels/aws/clientauth/clientauth.spawnable'])
|
||||
@pytest.mark.parametrize('level', ['AWS/ClientAuth'])
|
||||
def test_anonymous_credentials(self,
|
||||
level: str,
|
||||
launcher: pytest.fixture,
|
||||
@@ -72,7 +72,7 @@ class TestAWSClientAuthWindows(object):
|
||||
)
|
||||
assert result, 'Anonymous credentials fetched successfully.'
|
||||
|
||||
@pytest.mark.parametrize('level', ['levels/aws/clientauth/clientauth.spawnable'])
|
||||
@pytest.mark.parametrize('level', ['AWS/ClientAuth'])
|
||||
def test_anonymous_credentials_no_global_accountid(self,
|
||||
level: str,
|
||||
launcher: pytest.fixture,
|
||||
@@ -140,7 +140,7 @@ class TestAWSClientAuthWindows(object):
|
||||
except cognito_idp.exceptions.UserNotFoundException:
|
||||
pass
|
||||
|
||||
launcher.args = ['+LoadLevel', 'levels/aws/clientauthpasswordsignup/clientauthpasswordsignup.spawnable']
|
||||
launcher.args = ['+LoadLevel', 'AWS/ClientAuthPasswordSignUp']
|
||||
launcher.args.extend(['-rhi=null'])
|
||||
|
||||
with launcher.start(launch_ap=False):
|
||||
@@ -158,7 +158,7 @@ class TestAWSClientAuthWindows(object):
|
||||
Username='test1'
|
||||
)
|
||||
|
||||
launcher.args = ['+LoadLevel', 'levels/aws/clientauthpasswordsignin/clientauthpasswordsignin.spawnable']
|
||||
launcher.args = ['+LoadLevel', 'AWS/ClientAuthPasswordSignIn']
|
||||
launcher.args.extend(['-rhi=null'])
|
||||
|
||||
with launcher.start(launch_ap=False):
|
||||
+1
-1
@@ -84,7 +84,7 @@ def write_test_data_to_dynamodb_table(resource_mappings: pytest.fixture, aws_uti
|
||||
@pytest.mark.parametrize('session_name', [constants.SESSION_NAME])
|
||||
@pytest.mark.usefixtures('workspace')
|
||||
@pytest.mark.parametrize('project', ['AutomatedTesting'])
|
||||
@pytest.mark.parametrize('level', ['levels/aws/core/core.spawnable'])
|
||||
@pytest.mark.parametrize('level', ['AWS/Core'])
|
||||
@pytest.mark.usefixtures('resource_mappings')
|
||||
@pytest.mark.parametrize('resource_mappings_filename', [constants.AWS_RESOURCE_MAPPING_FILE_NAME])
|
||||
@pytest.mark.parametrize('stacks', [[f'{constants.AWS_PROJECT_NAME}-{AWS_CORE_FEATURE_NAME}',
|
||||
@@ -68,10 +68,6 @@ class AwsCredentials:
|
||||
if (len(self._credentials.sections()) == 0) and (not self._credentials_file_exists):
|
||||
os.remove(self._credentials_path)
|
||||
return
|
||||
|
||||
credentials_file_dir = os.path.dirname(self._credentials_path)
|
||||
if not os.path.isdir(credentials_file_dir):
|
||||
os.makedirs(credentials_file_dir)
|
||||
|
||||
with open(self._credentials_path, 'w+') as credential_file:
|
||||
self._credentials.write(credential_file)
|
||||
|
||||
@@ -16,7 +16,7 @@ logging.getLogger('nose').setLevel(logging.WARNING)
|
||||
class AwsUtils:
|
||||
|
||||
def __init__(self, arn: str, session_name: str, region_name: str):
|
||||
local_session = boto3.Session()
|
||||
local_session = boto3.Session(profile_name='default')
|
||||
local_sts_client = local_session.client('sts')
|
||||
self._local_account_id = local_sts_client.get_caller_identity()["Account"]
|
||||
logger.info(f'Local Account Id: {self._local_account_id}')
|
||||
|
||||
@@ -6,13 +6,11 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import platform
|
||||
|
||||
# ARN of the IAM role to assume for retrieving temporary AWS credentials
|
||||
ASSUME_ROLE_ARN = os.environ.get('ASSUME_ROLE_ARN', 'arn:aws:iam::645075835648:role/o3de-automation-tests')
|
||||
# Name of the AWS project deployed by the CDK applications
|
||||
AWS_PROJECT_NAME = os.environ.get('O3DE_AWS_PROJECT_NAME').upper() if os.environ.get('O3DE_AWS_PROJECT_NAME') else \
|
||||
(os.environ.get('BRANCH_NAME', '') + '-' + os.environ.get('PIPELINE_NAME', '') + '-' + platform.system()).upper()
|
||||
AWS_PROJECT_NAME = os.environ.get('O3DE_AWS_PROJECT_NAME', 'AWSAUTO')
|
||||
# Region for the existing CloudFormation stacks used by the automation tests
|
||||
AWS_REGION = os.environ.get('O3DE_AWS_DEPLOY_REGION', 'us-east-1')
|
||||
# Name of the default resource mapping config file used by the automation tests
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
@@ -20,6 +20,19 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
COMPONENT
|
||||
Atom
|
||||
)
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::Atom_TestSuite_Main_Optimized
|
||||
TEST_SUITE main
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_Optimized.py
|
||||
TEST_SERIAL
|
||||
TIMEOUT 600
|
||||
RUNTIME_DEPENDENCIES
|
||||
AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
Editor
|
||||
COMPONENT
|
||||
Atom
|
||||
)
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::Atom_TestSuite_Sandbox
|
||||
TEST_SUITE sandbox
|
||||
@@ -48,12 +61,12 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
Atom
|
||||
)
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::Atom_TestSuite_Benchmark_GPU
|
||||
NAME AutomatedTesting::Atom_TestSuite_Main_GPU_Optimized
|
||||
TEST_SUITE main
|
||||
TEST_REQUIRES gpu
|
||||
TEST_SERIAL
|
||||
TIMEOUT 700
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Benchmark_GPU.py
|
||||
TIMEOUT 1200
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_GPU_Optimized.py
|
||||
RUNTIME_DEPENDENCIES
|
||||
AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
import editor_python_test_tools.hydra_test_utils as hydra
|
||||
from ly_test_tools.benchmark.data_aggregator import BenchmarkDataAggregator
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('rhi', ['dx12', 'vulkan'])
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ["windows_editor"])
|
||||
@pytest.mark.parametrize("level", ["AtomFeatureIntegrationBenchmark"])
|
||||
class TestPerformanceBenchmarkSuite(object):
|
||||
def test_AtomFeatureIntegrationBenchmarkTest_UploadMetrics(
|
||||
self, request, editor, workspace, rhi, project, launcher_platform, level):
|
||||
"""
|
||||
Please review the hydra script run by this test for more specific test info.
|
||||
Tests the performance of the Simple level.
|
||||
"""
|
||||
expected_lines = [
|
||||
"Benchmark metadata captured.",
|
||||
"Pass timestamps captured.",
|
||||
"CPU frame time captured.",
|
||||
"Captured data successfully.",
|
||||
"Exited game mode"
|
||||
]
|
||||
|
||||
unexpected_lines = [
|
||||
"Failed to capture data.",
|
||||
"Failed to capture pass timestamps.",
|
||||
"Failed to capture CPU frame time.",
|
||||
"Failed to capture benchmark metadata."
|
||||
]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
os.path.join(os.path.dirname(__file__), "tests"),
|
||||
editor,
|
||||
"hydra_GPUTest_AtomFeatureIntegrationBenchmark.py",
|
||||
timeout=600,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
cfg_args=[level],
|
||||
null_renderer=False,
|
||||
enable_prefab_system=False,
|
||||
)
|
||||
|
||||
aggregator = BenchmarkDataAggregator(workspace, logger, 'periodic')
|
||||
aggregator.upload_metrics(rhi)
|
||||
@@ -6,12 +6,12 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
import ly_test_tools.environment.file_system as file_system
|
||||
import editor_python_test_tools.hydra_test_utils as hydra
|
||||
|
||||
from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
|
||||
from Atom.atom_utils.atom_constants import LIGHT_TYPES
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
|
||||
@@ -19,190 +19,237 @@ TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
|
||||
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
class TestAutomation(EditorTestSuite):
|
||||
@pytest.mark.parametrize("level", ["auto_test"])
|
||||
class TestAtomEditorComponentsMain(object):
|
||||
"""Holds tests for Atom components."""
|
||||
|
||||
enable_prefab_system = True
|
||||
|
||||
@pytest.mark.test_case_id("C36529679")
|
||||
class AtomLevelLoadTest_Editor(EditorSharedTest):
|
||||
from Atom.tests import hydra_Atom_LevelLoadTest as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525657")
|
||||
class AtomEditorComponents_BloomAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_BloomAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078118")
|
||||
class AtomEditorComponents_DecalAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525658")
|
||||
class AtomEditorComponents_DeferredFogAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DeferredFogAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078119")
|
||||
class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525659")
|
||||
class AtomEditorComponents_DiffuseProbeGridAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DiffuseProbeGridAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078120")
|
||||
class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525661")
|
||||
class AtomEditorComponents_EntityReferenceAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_EntityReferenceAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078121")
|
||||
class AtomEditorComponents_ExposureControlAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078115")
|
||||
class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078122")
|
||||
class AtomEditorComponents_GridAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_GridAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525671")
|
||||
class AtomEditorComponents_HDRColorGradingAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_HDRColorGradingAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078116")
|
||||
class AtomEditorComponents_HDRiSkyboxAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_HDRiSkyboxAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078117")
|
||||
class AtomEditorComponents_LightAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525662")
|
||||
class AtomEditorComponents_LookModificationAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_LookModificationAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078123")
|
||||
class AtomEditorComponents_MaterialAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_MaterialAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078124")
|
||||
class AtomEditorComponents_MeshAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525663")
|
||||
class AtomEditorComponents_OcclusionCullingPlaneAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_OcclusionCullingPlaneAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078125")
|
||||
class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525664")
|
||||
class AtomEditorComponents_PostFXGradientWeightModifierAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078127")
|
||||
class AtomEditorComponents_PostFXLayerAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PostFXLayerAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078131")
|
||||
class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest):
|
||||
from Atom.tests import (
|
||||
hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module)
|
||||
|
||||
@pytest.mark.test_case_id("C36525665")
|
||||
class AtomEditorComponents_PostFXShapeWeightModifierAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078128")
|
||||
class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525666")
|
||||
class AtomEditorComponents_SSAOAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_SSAOAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36529666")
|
||||
class AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525660")
|
||||
class AtomEditorComponentsLevel_DisplayMapperAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponentsLevel_DisplayMapperAdded as test_module
|
||||
|
||||
class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest):
|
||||
from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
|
||||
|
||||
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_generic'])
|
||||
class TestMaterialEditorBasicTests(object):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_teardown(self, request, workspace, project):
|
||||
def delete_files():
|
||||
file_system.delete(
|
||||
[
|
||||
os.path.join(workspace.paths.project(), "Materials", "test_material.material"),
|
||||
os.path.join(workspace.paths.project(), "Materials", "test_material_1.material"),
|
||||
os.path.join(workspace.paths.project(), "Materials", "test_material_2.material"),
|
||||
],
|
||||
True,
|
||||
True,
|
||||
)
|
||||
# Cleanup our newly created materials
|
||||
delete_files()
|
||||
|
||||
def teardown():
|
||||
# Cleanup our newly created materials
|
||||
delete_files()
|
||||
|
||||
request.addfinalizer(teardown)
|
||||
|
||||
@pytest.mark.parametrize("exe_file_name", ["MaterialEditor"])
|
||||
@pytest.mark.test_case_id("C34448113") # Creating a New Asset.
|
||||
@pytest.mark.test_case_id("C34448114") # Opening an Existing Asset.
|
||||
@pytest.mark.test_case_id("C34448115") # Closing Selected Material.
|
||||
@pytest.mark.test_case_id("C34448116") # Closing All Materials.
|
||||
@pytest.mark.test_case_id("C34448117") # Closing all but Selected Material.
|
||||
@pytest.mark.test_case_id("C34448118") # Saving Material.
|
||||
@pytest.mark.test_case_id("C34448119") # Saving as a New Material.
|
||||
@pytest.mark.test_case_id("C34448120") # Saving as a Child Material.
|
||||
@pytest.mark.test_case_id("C34448121") # Saving all Open Materials.
|
||||
def test_MaterialEditorBasicTests(
|
||||
self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name):
|
||||
@pytest.mark.test_case_id("C32078118") # Decal
|
||||
@pytest.mark.test_case_id("C32078119") # DepthOfField
|
||||
@pytest.mark.test_case_id("C32078120") # Directional Light
|
||||
@pytest.mark.test_case_id("C32078121") # Exposure Control
|
||||
@pytest.mark.test_case_id("C32078115") # Global Skylight (IBL)
|
||||
@pytest.mark.test_case_id("C32078125") # Physical Sky
|
||||
@pytest.mark.test_case_id("C32078127") # PostFX Layer
|
||||
@pytest.mark.test_case_id("C32078131") # PostFX Radius Weight Modifier
|
||||
@pytest.mark.test_case_id("C32078117") # Light
|
||||
@pytest.mark.test_case_id("C36525660") # Display Mapper
|
||||
def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform):
|
||||
"""
|
||||
Please review the hydra script run by this test for more specific test info.
|
||||
Tests the Atom components & verifies all "expected_lines" appear in Editor.log
|
||||
"""
|
||||
cfg_args = [level]
|
||||
|
||||
expected_lines = [
|
||||
"Material opened: True",
|
||||
"Test asset doesn't exist initially: True",
|
||||
"New asset created: True",
|
||||
"New Material opened: True",
|
||||
"Material closed: True",
|
||||
"All documents closed: True",
|
||||
"Close All Except Selected worked as expected: True",
|
||||
"Actual Document saved with changes: True",
|
||||
"Document saved as copy is saved with changes: True",
|
||||
"Document saved as child is saved with changes: True",
|
||||
"Save All worked as expected: True",
|
||||
"P1: Asset Browser visibility working as expected: True",
|
||||
"P1: Inspector visibility working as expected: True",
|
||||
# Decal Component
|
||||
"Decal Entity successfully created",
|
||||
"Decal_test: Component added to the entity: True",
|
||||
"Decal_test: Component removed after UNDO: True",
|
||||
"Decal_test: Component added after REDO: True",
|
||||
"Decal_test: Entered game mode: True",
|
||||
"Decal_test: Exit game mode: True",
|
||||
"Decal Controller|Configuration|Material: SUCCESS",
|
||||
"Decal_test: Entity is hidden: True",
|
||||
"Decal_test: Entity is shown: True",
|
||||
"Decal_test: Entity deleted: True",
|
||||
"Decal_test: UNDO entity deletion works: True",
|
||||
"Decal_test: REDO entity deletion works: True",
|
||||
# DepthOfField Component
|
||||
"DepthOfField Entity successfully created",
|
||||
"DepthOfField_test: Component added to the entity: True",
|
||||
"DepthOfField_test: Component removed after UNDO: True",
|
||||
"DepthOfField_test: Component added after REDO: True",
|
||||
"DepthOfField_test: Entered game mode: True",
|
||||
"DepthOfField_test: Exit game mode: True",
|
||||
"DepthOfField_test: Entity disabled initially: True",
|
||||
"DepthOfField_test: Entity enabled after adding required components: True",
|
||||
"DepthOfField Controller|Configuration|Camera Entity: SUCCESS",
|
||||
"DepthOfField_test: Entity is hidden: True",
|
||||
"DepthOfField_test: Entity is shown: True",
|
||||
"DepthOfField_test: Entity deleted: True",
|
||||
"DepthOfField_test: UNDO entity deletion works: True",
|
||||
"DepthOfField_test: REDO entity deletion works: True",
|
||||
# Directional Light Component
|
||||
"Directional Light Entity successfully created",
|
||||
"Directional Light_test: Component added to the entity: True",
|
||||
"Directional Light_test: Component removed after UNDO: True",
|
||||
"Directional Light_test: Component added after REDO: True",
|
||||
"Directional Light_test: Entered game mode: True",
|
||||
"Directional Light_test: Exit game mode: True",
|
||||
"Directional Light_test: Entity is hidden: True",
|
||||
"Directional Light_test: Entity is shown: True",
|
||||
"Directional Light_test: Entity deleted: True",
|
||||
"Directional Light_test: UNDO entity deletion works: True",
|
||||
"Directional Light_test: REDO entity deletion works: True",
|
||||
# Exposure Control Component
|
||||
"Exposure Control Entity successfully created",
|
||||
"Exposure Control_test: Component added to the entity: True",
|
||||
"Exposure Control_test: Component removed after UNDO: True",
|
||||
"Exposure Control_test: Component added after REDO: True",
|
||||
"Exposure Control_test: Entered game mode: True",
|
||||
"Exposure Control_test: Exit game mode: True",
|
||||
"Exposure Control_test: Entity disabled initially: True",
|
||||
"Exposure Control_test: Entity enabled after adding required components: True",
|
||||
"Exposure Control_test: Entity is hidden: True",
|
||||
"Exposure Control_test: Entity is shown: True",
|
||||
"Exposure Control_test: Entity deleted: True",
|
||||
"Exposure Control_test: UNDO entity deletion works: True",
|
||||
"Exposure Control_test: REDO entity deletion works: True",
|
||||
# Global Skylight (IBL) Component
|
||||
"Global Skylight (IBL) Entity successfully created",
|
||||
"Global Skylight (IBL)_test: Component added to the entity: True",
|
||||
"Global Skylight (IBL)_test: Component removed after UNDO: True",
|
||||
"Global Skylight (IBL)_test: Component added after REDO: True",
|
||||
"Global Skylight (IBL)_test: Entered game mode: True",
|
||||
"Global Skylight (IBL)_test: Exit game mode: True",
|
||||
"Global Skylight (IBL) Controller|Configuration|Diffuse Image: SUCCESS",
|
||||
"Global Skylight (IBL) Controller|Configuration|Specular Image: SUCCESS",
|
||||
"Global Skylight (IBL)_test: Entity is hidden: True",
|
||||
"Global Skylight (IBL)_test: Entity is shown: True",
|
||||
"Global Skylight (IBL)_test: Entity deleted: True",
|
||||
"Global Skylight (IBL)_test: UNDO entity deletion works: True",
|
||||
"Global Skylight (IBL)_test: REDO entity deletion works: True",
|
||||
# Physical Sky Component
|
||||
"Physical Sky Entity successfully created",
|
||||
"Physical Sky component was added to entity",
|
||||
"Entity has a Physical Sky component",
|
||||
"Physical Sky_test: Component added to the entity: True",
|
||||
"Physical Sky_test: Component removed after UNDO: True",
|
||||
"Physical Sky_test: Component added after REDO: True",
|
||||
"Physical Sky_test: Entered game mode: True",
|
||||
"Physical Sky_test: Exit game mode: True",
|
||||
"Physical Sky_test: Entity is hidden: True",
|
||||
"Physical Sky_test: Entity is shown: True",
|
||||
"Physical Sky_test: Entity deleted: True",
|
||||
"Physical Sky_test: UNDO entity deletion works: True",
|
||||
"Physical Sky_test: REDO entity deletion works: True",
|
||||
# PostFX Layer Component
|
||||
"PostFX Layer Entity successfully created",
|
||||
"PostFX Layer_test: Component added to the entity: True",
|
||||
"PostFX Layer_test: Component removed after UNDO: True",
|
||||
"PostFX Layer_test: Component added after REDO: True",
|
||||
"PostFX Layer_test: Entered game mode: True",
|
||||
"PostFX Layer_test: Exit game mode: True",
|
||||
"PostFX Layer_test: Entity is hidden: True",
|
||||
"PostFX Layer_test: Entity is shown: True",
|
||||
"PostFX Layer_test: Entity deleted: True",
|
||||
"PostFX Layer_test: UNDO entity deletion works: True",
|
||||
"PostFX Layer_test: REDO entity deletion works: True",
|
||||
# PostFX Radius Weight Modifier Component
|
||||
"PostFX Radius Weight Modifier Entity successfully created",
|
||||
"PostFX Radius Weight Modifier_test: Component added to the entity: True",
|
||||
"PostFX Radius Weight Modifier_test: Component removed after UNDO: True",
|
||||
"PostFX Radius Weight Modifier_test: Component added after REDO: True",
|
||||
"PostFX Radius Weight Modifier_test: Entered game mode: True",
|
||||
"PostFX Radius Weight Modifier_test: Exit game mode: True",
|
||||
"PostFX Radius Weight Modifier_test: Entity is hidden: True",
|
||||
"PostFX Radius Weight Modifier_test: Entity is shown: True",
|
||||
"PostFX Radius Weight Modifier_test: Entity deleted: True",
|
||||
"PostFX Radius Weight Modifier_test: UNDO entity deletion works: True",
|
||||
"PostFX Radius Weight Modifier_test: REDO entity deletion works: True",
|
||||
# Light Component
|
||||
"Light Entity successfully created",
|
||||
"Light_test: Component added to the entity: True",
|
||||
"Light_test: Component removed after UNDO: True",
|
||||
"Light_test: Component added after REDO: True",
|
||||
"Light_test: Entered game mode: True",
|
||||
"Light_test: Exit game mode: True",
|
||||
"Light_test: Entity is hidden: True",
|
||||
"Light_test: Entity is shown: True",
|
||||
"Light_test: Entity deleted: True",
|
||||
"Light_test: UNDO entity deletion works: True",
|
||||
"Light_test: REDO entity deletion works: True",
|
||||
# Display Mapper Component
|
||||
"Display Mapper Entity successfully created",
|
||||
"Display Mapper_test: Component added to the entity: True",
|
||||
"Display Mapper_test: Component removed after UNDO: True",
|
||||
"Display Mapper_test: Component added after REDO: True",
|
||||
"Display Mapper_test: Entered game mode: True",
|
||||
"Display Mapper_test: Exit game mode: True",
|
||||
"Display Mapper_test: Entity is hidden: True",
|
||||
"Display Mapper_test: Entity is shown: True",
|
||||
"Display Mapper_test: Entity deleted: True",
|
||||
"Display Mapper_test: UNDO entity deletion works: True",
|
||||
"Display Mapper_test: REDO entity deletion works: True",
|
||||
]
|
||||
|
||||
unexpected_lines = [
|
||||
# Including any lines in unexpected_lines will cause the test to run for the duration of the timeout
|
||||
"Trace::Assert",
|
||||
"Trace::Error",
|
||||
"Traceback (most recent call last):",
|
||||
]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
generic_launcher,
|
||||
"hydra_AtomMaterialEditor_BasicTests.py",
|
||||
run_python="--runpython",
|
||||
timeout=43,
|
||||
editor,
|
||||
"hydra_AtomEditorComponents_AddedToEntity.py",
|
||||
timeout=120,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
log_file_name="MaterialEditor.log",
|
||||
enable_prefab_system=False,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
|
||||
@pytest.mark.test_case_id("C34525095")
|
||||
def test_AtomEditorComponents_LightComponent(
|
||||
self, request, editor, workspace, project, launcher_platform, level):
|
||||
"""
|
||||
Please review the hydra script run by this test for more specific test info.
|
||||
Tests that the Light component has the expected property options available to it.
|
||||
"""
|
||||
cfg_args = [level]
|
||||
|
||||
expected_lines = [
|
||||
"light_entity Entity successfully created",
|
||||
"Entity has a Light component",
|
||||
"light_entity_test: Component added to the entity: True",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['sphere']} which matches {LIGHT_TYPES['sphere']}",
|
||||
"Controller|Configuration|Shadows|Enable shadow set to True",
|
||||
"light_entity Controller|Configuration|Shadows|Shadowmap size: SUCCESS",
|
||||
"Controller|Configuration|Shadows|Shadow filter method set to 1", # PCF
|
||||
"Controller|Configuration|Shadows|Filtering sample count set to 4",
|
||||
"Controller|Configuration|Shadows|Filtering sample count set to 64",
|
||||
"Controller|Configuration|Shadows|Shadow filter method set to 2", # ESM
|
||||
"Controller|Configuration|Shadows|ESM exponent set to 50.0",
|
||||
"Controller|Configuration|Shadows|ESM exponent set to 5000.0",
|
||||
"Controller|Configuration|Shadows|Shadow filter method set to 3", # ESM+PCF
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['spot_disk']} which matches {LIGHT_TYPES['spot_disk']}",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['capsule']} which matches {LIGHT_TYPES['capsule']}",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['quad']} which matches {LIGHT_TYPES['quad']}",
|
||||
"light_entity Controller|Configuration|Fast approximation: SUCCESS",
|
||||
"light_entity Controller|Configuration|Both directions: SUCCESS",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['polygon']} which matches {LIGHT_TYPES['polygon']}",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['simple_point']} "
|
||||
f"which matches {LIGHT_TYPES['simple_point']}",
|
||||
"Controller|Configuration|Attenuation radius|Mode set to 0",
|
||||
"Controller|Configuration|Attenuation radius|Radius set to 100.0",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['simple_spot']} "
|
||||
f"which matches {LIGHT_TYPES['simple_spot']}",
|
||||
"Controller|Configuration|Shutters|Outer angle set to 45.0",
|
||||
"Controller|Configuration|Shutters|Outer angle set to 90.0",
|
||||
"light_entity_test: Component added to the entity: True",
|
||||
"Light component test (non-GPU) completed.",
|
||||
]
|
||||
|
||||
unexpected_lines = [
|
||||
"Trace::Assert",
|
||||
"Trace::Error",
|
||||
"Traceback (most recent call last):",
|
||||
]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_AtomEditorComponents_LightComponent.py",
|
||||
timeout=120,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -4,159 +4,222 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import zipfile
|
||||
|
||||
import pytest
|
||||
|
||||
import editor_python_test_tools.hydra_test_utils as hydra
|
||||
import ly_test_tools.environment.file_system as file_system
|
||||
from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorTestSuite
|
||||
from Atom.atom_utils.atom_component_helper import compare_screenshot_to_golden_image, golden_images_directory
|
||||
from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots
|
||||
from ly_test_tools.benchmark.data_aggregator import BenchmarkDataAggregator
|
||||
|
||||
import editor_python_test_tools.hydra_test_utils as hydra
|
||||
|
||||
DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots'
|
||||
logger = logging.getLogger(__name__)
|
||||
DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots'
|
||||
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
|
||||
|
||||
|
||||
def golden_images_directory():
|
||||
"""
|
||||
Uses this file location to return the valid location for golden image files.
|
||||
:return: The path to the golden_images directory, but raises an IOError if the golden_images directory is missing.
|
||||
"""
|
||||
current_file_directory = os.path.join(os.path.dirname(__file__))
|
||||
golden_images_dir = os.path.join(current_file_directory, 'golden_images')
|
||||
|
||||
if not os.path.exists(golden_images_dir):
|
||||
raise IOError(
|
||||
f'golden_images" directory was not found at path "{golden_images_dir}"'
|
||||
f'Please add a "golden_images" directory inside: "{current_file_directory}"'
|
||||
)
|
||||
|
||||
return golden_images_dir
|
||||
|
||||
|
||||
def create_screenshots_archive(screenshot_path):
|
||||
"""
|
||||
Creates a new zip file archive at archive_path containing all files listed within archive_path.
|
||||
:param screenshot_path: location containing the files to archive, the zip archive file will also be saved here.
|
||||
:return: None, but creates a new zip file archive inside path containing all of the files inside archive_path.
|
||||
"""
|
||||
files_to_archive = []
|
||||
|
||||
# Search for .png and .ppm files to add to the zip archive file.
|
||||
for (folder_name, sub_folders, file_names) in os.walk(screenshot_path):
|
||||
for file_name in file_names:
|
||||
if file_name.endswith(".png") or file_name.endswith(".ppm"):
|
||||
file_path = os.path.join(folder_name, file_name)
|
||||
files_to_archive.append(file_path)
|
||||
|
||||
# Setup variables for naming the zip archive file.
|
||||
timestamp = datetime.datetime.now().timestamp()
|
||||
formatted_timestamp = datetime.datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d_%H-%M-%S")
|
||||
screenshots_file = os.path.join(screenshot_path, f'zip_archive_{formatted_timestamp}.zip')
|
||||
|
||||
# Write all of the valid .png and .ppm files to the archive file.
|
||||
with zipfile.ZipFile(screenshots_file, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as zip_archive:
|
||||
for file_path in files_to_archive:
|
||||
file_name = os.path.basename(file_path)
|
||||
zip_archive.write(file_path, file_name)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
class TestAutomation(EditorTestSuite):
|
||||
# Remove -autotest_mode from global_extra_cmdline_args since we need rendering for these tests.
|
||||
global_extra_cmdline_args = ["-autotest_mode"] # Default is ["-BatchMode", "-autotest_mode"]
|
||||
use_null_renderer = False # Default is True
|
||||
enable_prefab_system = False
|
||||
@pytest.mark.parametrize("launcher_platform", ["windows_editor"])
|
||||
@pytest.mark.parametrize("level", ["auto_test"])
|
||||
class TestAllComponentsIndepthTests(object):
|
||||
|
||||
@staticmethod
|
||||
def screenshot_setup(screenshot_directory, screenshot_names):
|
||||
@pytest.mark.parametrize("screenshot_name", ["AtomBasicLevelSetup.ppm"])
|
||||
@pytest.mark.test_case_id("C34603773")
|
||||
def test_BasicLevelSetup_SetsUpLevel(
|
||||
self, request, editor, workspace, project, launcher_platform, level, screenshot_name):
|
||||
"""
|
||||
:param screenshot_names: list of screenshot file names with extensions
|
||||
:return: tuple test_screenshots, golden_images each a list of full file paths
|
||||
Please review the hydra script run by this test for more specific test info.
|
||||
Tests that a basic rendering level setup can be created (lighting, meshes, materials, etc.).
|
||||
"""
|
||||
# Clear existing test screenshots before starting test.
|
||||
screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
test_screenshots = [os.path.join(screenshot_directory, screenshot_name)]
|
||||
file_system.delete(test_screenshots, True, True)
|
||||
|
||||
golden_images = [os.path.join(golden_images_directory(), screenshot_name)]
|
||||
|
||||
level_creation_expected_lines = [
|
||||
"Viewport is set to the expected size: True",
|
||||
"Exited game mode"
|
||||
]
|
||||
unexpected_lines = [
|
||||
"Trace::Assert",
|
||||
"Trace::Error",
|
||||
"Traceback (most recent call last):",
|
||||
"Screenshot failed"
|
||||
]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_GPUTest_BasicLevelSetup.py",
|
||||
timeout=180,
|
||||
expected_lines=level_creation_expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
cfg_args=[level],
|
||||
null_renderer=False,
|
||||
)
|
||||
|
||||
for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images):
|
||||
compare_screenshots(test_screenshot, golden_screenshot)
|
||||
|
||||
create_screenshots_archive(screenshot_directory)
|
||||
|
||||
@pytest.mark.test_case_id("C34525095")
|
||||
def test_LightComponent_ScreenshotMatchesGoldenImage(
|
||||
self, request, editor, workspace, project, launcher_platform, level):
|
||||
"""
|
||||
Please review the hydra script run by this test for more specific test info.
|
||||
Tests that the Light component screenshots in a rendered level appear the same as the golden images.
|
||||
"""
|
||||
screenshot_names = [
|
||||
"AreaLight_1.ppm",
|
||||
"AreaLight_2.ppm",
|
||||
"AreaLight_3.ppm",
|
||||
"AreaLight_4.ppm",
|
||||
"AreaLight_5.ppm",
|
||||
"SpotLight_1.ppm",
|
||||
"SpotLight_2.ppm",
|
||||
"SpotLight_3.ppm",
|
||||
"SpotLight_4.ppm",
|
||||
"SpotLight_5.ppm",
|
||||
"SpotLight_6.ppm",
|
||||
]
|
||||
screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
test_screenshots = []
|
||||
golden_images = []
|
||||
for screenshot in screenshot_names:
|
||||
screenshot_path = os.path.join(screenshot_directory, screenshot)
|
||||
test_screenshots.append(screenshot_path)
|
||||
file_system.delete(test_screenshots, True, True)
|
||||
|
||||
golden_images = []
|
||||
for golden_image in screenshot_names:
|
||||
golden_image_path = os.path.join(golden_images_directory(), golden_image)
|
||||
golden_images.append(golden_image_path)
|
||||
return test_screenshots, golden_images
|
||||
|
||||
expected_lines = ["spot_light Controller|Configuration|Shadows|Shadowmap size: SUCCESS"]
|
||||
unexpected_lines = [
|
||||
"Trace::Assert",
|
||||
"Trace::Error",
|
||||
"Traceback (most recent call last):",
|
||||
"Screenshot failed",
|
||||
]
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_GPUTest_LightComponent.py",
|
||||
timeout=180,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
cfg_args=[level],
|
||||
null_renderer=False,
|
||||
)
|
||||
|
||||
for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images):
|
||||
compare_screenshots(test_screenshot, golden_screenshot)
|
||||
|
||||
create_screenshots_archive(screenshot_directory)
|
||||
|
||||
|
||||
@pytest.mark.test_case_id("C34525095")
|
||||
class AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages_DX12(EditorSingleTest):
|
||||
from Atom.tests import hydra_AtomGPU_AreaLightScreenshotTest as test_module
|
||||
@pytest.mark.parametrize('rhi', ['dx12', 'vulkan'])
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ["windows_editor"])
|
||||
@pytest.mark.parametrize("level", ["AtomFeatureIntegrationBenchmark"])
|
||||
class TestPerformanceBenchmarkSuite(object):
|
||||
def test_AtomFeatureIntegrationBenchmark(
|
||||
self, request, editor, workspace, rhi, project, launcher_platform, level):
|
||||
"""
|
||||
Please review the hydra script run by this test for more specific test info.
|
||||
Tests the performance of the Simple level.
|
||||
"""
|
||||
expected_lines = [
|
||||
"Benchmark metadata captured.",
|
||||
"Pass timestamps captured.",
|
||||
"CPU frame time captured.",
|
||||
"Captured data successfully.",
|
||||
"Exited game mode"
|
||||
]
|
||||
|
||||
extra_cmdline_args = ["-rhi=dx12"]
|
||||
unexpected_lines = [
|
||||
"Failed to capture data.",
|
||||
"Failed to capture pass timestamps.",
|
||||
"Failed to capture CPU frame time.",
|
||||
"Failed to capture benchmark metadata."
|
||||
]
|
||||
|
||||
# Custom setup/teardown to remove old screenshots and establish paths to golden images
|
||||
def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
self.screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
self.screenshot_names = [
|
||||
"AreaLight_1.ppm",
|
||||
"AreaLight_2.ppm",
|
||||
"AreaLight_3.ppm",
|
||||
"AreaLight_4.ppm",
|
||||
"AreaLight_5.ppm",
|
||||
]
|
||||
self.test_screenshots, self.golden_images = TestAutomation.screenshot_setup(
|
||||
screenshot_directory=self.screenshot_directory,
|
||||
screenshot_names=self.screenshot_names)
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_GPUTest_AtomFeatureIntegrationBenchmark.py",
|
||||
timeout=600,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
cfg_args=[level],
|
||||
null_renderer=False,
|
||||
)
|
||||
|
||||
def wrap_run(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
yield
|
||||
assert compare_screenshot_to_golden_image(self.screenshot_directory,
|
||||
self.test_screenshots,
|
||||
self.golden_images,
|
||||
similarity_threshold=0.96) is True
|
||||
|
||||
@pytest.mark.test_case_id("C34525095")
|
||||
class AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages_Vulkan(EditorSingleTest):
|
||||
from Atom.tests import hydra_AtomGPU_AreaLightScreenshotTest as test_module
|
||||
|
||||
extra_cmdline_args = ["-rhi=vulkan"]
|
||||
|
||||
# Custom setup/teardown to remove old screenshots and establish paths to golden images
|
||||
def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
self.screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
self.screenshot_names = [
|
||||
"AreaLight_1.ppm",
|
||||
"AreaLight_2.ppm",
|
||||
"AreaLight_3.ppm",
|
||||
"AreaLight_4.ppm",
|
||||
"AreaLight_5.ppm",
|
||||
]
|
||||
self.test_screenshots, self.golden_images = TestAutomation.screenshot_setup(
|
||||
screenshot_directory=self.screenshot_directory,
|
||||
screenshot_names=self.screenshot_names)
|
||||
|
||||
def wrap_run(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
yield
|
||||
assert compare_screenshot_to_golden_image(self.screenshot_directory,
|
||||
self.test_screenshots,
|
||||
self.golden_images,
|
||||
similarity_threshold=0.96) is True
|
||||
|
||||
@pytest.mark.test_case_id("C34525110")
|
||||
class AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages_DX12(EditorSingleTest):
|
||||
from Atom.tests import hydra_AtomGPU_SpotLightScreenshotTest as test_module
|
||||
|
||||
extra_cmdline_args = ["-rhi=dx12"]
|
||||
|
||||
# Custom setup/teardown to remove old screenshots and establish paths to golden images
|
||||
def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
self.screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
self.screenshot_names = [
|
||||
"SpotLight_1.ppm",
|
||||
"SpotLight_2.ppm",
|
||||
"SpotLight_3.ppm",
|
||||
"SpotLight_4.ppm",
|
||||
"SpotLight_5.ppm",
|
||||
"SpotLight_6.ppm",
|
||||
]
|
||||
self.test_screenshots, self.golden_images = TestAutomation.screenshot_setup(
|
||||
screenshot_directory=self.screenshot_directory,
|
||||
screenshot_names=self.screenshot_names)
|
||||
|
||||
def wrap_run(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
yield
|
||||
assert compare_screenshot_to_golden_image(self.screenshot_directory,
|
||||
self.test_screenshots,
|
||||
self.golden_images,
|
||||
similarity_threshold=0.96) is True
|
||||
|
||||
@pytest.mark.test_case_id("C34525110")
|
||||
class AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages_Vulkan(EditorSingleTest):
|
||||
from Atom.tests import hydra_AtomGPU_SpotLightScreenshotTest as test_module
|
||||
|
||||
extra_cmdline_args = ["-rhi=vulkan"]
|
||||
|
||||
# Custom setup/teardown to remove old screenshots and establish paths to golden images
|
||||
def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
self.screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
self.screenshot_names = [
|
||||
"SpotLight_1.ppm",
|
||||
"SpotLight_2.ppm",
|
||||
"SpotLight_3.ppm",
|
||||
"SpotLight_4.ppm",
|
||||
"SpotLight_5.ppm",
|
||||
"SpotLight_6.ppm",
|
||||
]
|
||||
self.test_screenshots, self.golden_images = TestAutomation.screenshot_setup(
|
||||
screenshot_directory=self.screenshot_directory,
|
||||
screenshot_names=self.screenshot_names)
|
||||
|
||||
def wrap_run(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
yield
|
||||
assert compare_screenshot_to_golden_image(self.screenshot_directory,
|
||||
self.test_screenshots,
|
||||
self.golden_images,
|
||||
similarity_threshold=0.96) is True
|
||||
aggregator = BenchmarkDataAggregator(workspace, logger, 'periodic')
|
||||
aggregator.upload_metrics(rhi)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_generic'])
|
||||
@pytest.mark.system
|
||||
class TestMaterialEditor(object):
|
||||
|
||||
@pytest.mark.parametrize("cfg_args,expected_lines", [
|
||||
@@ -176,7 +239,7 @@ class TestMaterialEditor(object):
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
os.path.join(os.path.dirname(__file__), "tests"),
|
||||
TEST_DIRECTORY,
|
||||
generic_launcher,
|
||||
editor_script="",
|
||||
run_python="--runpython",
|
||||
@@ -186,6 +249,5 @@ class TestMaterialEditor(object):
|
||||
halt_on_unexpected=False,
|
||||
null_renderer=False,
|
||||
cfg_args=[cfg_args],
|
||||
log_file_name="MaterialEditor.log",
|
||||
enable_prefab_system=False,
|
||||
log_file_name="MaterialEditor.log"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
import ly_test_tools.environment.file_system as file_system
|
||||
from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
|
||||
from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots
|
||||
from .atom_utils.atom_component_helper import create_screenshots_archive, golden_images_directory
|
||||
|
||||
DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots'
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
class TestAutomation(EditorTestSuite):
|
||||
# Remove -autotest_mode from global_extra_cmdline_args since we need rendering for these tests.
|
||||
global_extra_cmdline_args = ["-BatchMode"] # Default is ["-BatchMode", "-autotest_mode"]
|
||||
|
||||
@pytest.mark.test_case_id("C34603773")
|
||||
class AtomGPU_BasicLevelSetup_SetsUpLevel(EditorSharedTest):
|
||||
use_null_renderer = False # Default is True
|
||||
screenshot_name = "AtomBasicLevelSetup.ppm"
|
||||
test_screenshots = [] # Gets set by setup()
|
||||
screenshot_directory = "" # Gets set by setup()
|
||||
|
||||
# Clear existing test screenshots before starting test.
|
||||
def setup(self, workspace):
|
||||
screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
test_screenshots = [os.path.join(screenshot_directory, self.screenshot_name)]
|
||||
file_system.delete(test_screenshots, True, True)
|
||||
|
||||
from Atom.tests import hydra_AtomGPU_BasicLevelSetup as test_module
|
||||
|
||||
golden_images = [os.path.join(golden_images_directory(), screenshot_name)]
|
||||
for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images):
|
||||
compare_screenshots(test_screenshot, golden_screenshot)
|
||||
create_screenshots_archive(screenshot_directory)
|
||||
@@ -0,0 +1,79 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
class TestAutomation(EditorTestSuite):
|
||||
|
||||
@pytest.mark.test_case_id("C32078118")
|
||||
class AtomEditorComponents_DecalAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078119")
|
||||
class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078120")
|
||||
class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078121")
|
||||
class AtomEditorComponents_ExposureControlAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078115")
|
||||
class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078125")
|
||||
class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078131")
|
||||
class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest):
|
||||
from Atom.tests import (
|
||||
hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module)
|
||||
|
||||
@pytest.mark.test_case_id("C32078117")
|
||||
class AtomEditorComponents_LightAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525660")
|
||||
class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078128")
|
||||
class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078124")
|
||||
class AtomEditorComponents_MeshAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078123")
|
||||
class AtomEditorComponents_MaterialAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_MaterialAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C32078127")
|
||||
class AtomEditorComponents_PostFXLayerAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PostFXLayerAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525665")
|
||||
class AtomEditorComponents_PostFXShapeWeightModifierAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525664")
|
||||
class AtomEditorComponents_PostFXGradientWeightModifierAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded as test_module
|
||||
|
||||
class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest):
|
||||
from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
|
||||
@@ -9,25 +9,132 @@ import os
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
|
||||
import editor_python_test_tools.hydra_test_utils as hydra
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
|
||||
|
||||
class TestAtomEditorComponentsSandbox(object):
|
||||
|
||||
# It requires at least one test
|
||||
def test_Dummy(self, request, editor, level, workspace, project, launcher_platform):
|
||||
pass
|
||||
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("level", ["auto_test"])
|
||||
class TestAtomEditorComponentsMain(object):
|
||||
"""Holds tests for Atom components."""
|
||||
|
||||
@pytest.mark.test_case_id("C32078128")
|
||||
def test_AtomEditorComponents_ReflectionProbeAddedToEntity(
|
||||
self, request, editor, level, workspace, project, launcher_platform):
|
||||
"""
|
||||
Please review the hydra script run by this test for more specific test info.
|
||||
Tests the following Atom components and verifies all "expected_lines" appear in Editor.log:
|
||||
1. Reflection Probe
|
||||
"""
|
||||
cfg_args = [level]
|
||||
|
||||
expected_lines = [
|
||||
# Reflection Probe Component
|
||||
"Reflection Probe Entity successfully created",
|
||||
"Reflection Probe_test: Component added to the entity: True",
|
||||
"Reflection Probe_test: Component removed after UNDO: True",
|
||||
"Reflection Probe_test: Component added after REDO: True",
|
||||
"Reflection Probe_test: Entered game mode: True",
|
||||
"Reflection Probe_test: Exit game mode: True",
|
||||
"Reflection Probe_test: Entity disabled initially: True",
|
||||
"Reflection Probe_test: Entity enabled after adding required components: True",
|
||||
"Reflection Probe_test: Cubemap is generated: True",
|
||||
"Reflection Probe_test: Entity is hidden: True",
|
||||
"Reflection Probe_test: Entity is shown: True",
|
||||
"Reflection Probe_test: Entity deleted: True",
|
||||
"Reflection Probe_test: UNDO entity deletion works: True",
|
||||
"Reflection Probe_test: REDO entity deletion works: True",
|
||||
]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_AtomEditorComponents_AddedToEntity.py",
|
||||
timeout=120,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=[],
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
class TestAutomation(EditorTestSuite):
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_generic'])
|
||||
@pytest.mark.system
|
||||
class TestMaterialEditorBasicTests(object):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_teardown(self, request, workspace, project):
|
||||
def delete_files():
|
||||
file_system.delete(
|
||||
[
|
||||
os.path.join(workspace.paths.project(), "Materials", "test_material.material"),
|
||||
os.path.join(workspace.paths.project(), "Materials", "test_material_1.material"),
|
||||
os.path.join(workspace.paths.project(), "Materials", "test_material_2.material"),
|
||||
],
|
||||
True,
|
||||
True,
|
||||
)
|
||||
# Cleanup our newly created materials
|
||||
delete_files()
|
||||
|
||||
enable_prefab_system = True
|
||||
def teardown():
|
||||
# Cleanup our newly created materials
|
||||
delete_files()
|
||||
|
||||
# this test is intermittently timing out without ever having executed. sandboxing while we investigate cause.
|
||||
@pytest.mark.test_case_id("C36525660")
|
||||
class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module
|
||||
request.addfinalizer(teardown)
|
||||
|
||||
@pytest.mark.parametrize("exe_file_name", ["MaterialEditor"])
|
||||
@pytest.mark.test_case_id("C34448113") # Creating a New Asset.
|
||||
@pytest.mark.test_case_id("C34448114") # Opening an Existing Asset.
|
||||
@pytest.mark.test_case_id("C34448115") # Closing Selected Material.
|
||||
@pytest.mark.test_case_id("C34448116") # Closing All Materials.
|
||||
@pytest.mark.test_case_id("C34448117") # Closing all but Selected Material.
|
||||
@pytest.mark.test_case_id("C34448118") # Saving Material.
|
||||
@pytest.mark.test_case_id("C34448119") # Saving as a New Material.
|
||||
@pytest.mark.test_case_id("C34448120") # Saving as a Child Material.
|
||||
@pytest.mark.test_case_id("C34448121") # Saving all Open Materials.
|
||||
def test_MaterialEditorBasicTests(
|
||||
self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name):
|
||||
|
||||
expected_lines = [
|
||||
"Material opened: True",
|
||||
"Test asset doesn't exist initially: True",
|
||||
"New asset created: True",
|
||||
"New Material opened: True",
|
||||
"Material closed: True",
|
||||
"All documents closed: True",
|
||||
"Close All Except Selected worked as expected: True",
|
||||
"Actual Document saved with changes: True",
|
||||
"Document saved as copy is saved with changes: True",
|
||||
"Document saved as child is saved with changes: True",
|
||||
"Save All worked as expected: True",
|
||||
]
|
||||
unexpected_lines = [
|
||||
# "Trace::Assert",
|
||||
# "Trace::Error",
|
||||
"Traceback (most recent call last):"
|
||||
]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
generic_launcher,
|
||||
"hydra_AtomMaterialEditor_BasicTests.py",
|
||||
run_python="--runpython",
|
||||
timeout=120,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
log_file_name="MaterialEditor.log",
|
||||
)
|
||||
|
||||
# The "Sponza" level is failing with a hard lock 4-12% of the time, needs root causing and fixing.
|
||||
@pytest.mark.test_case_id("C36529679")
|
||||
class AtomLevelLoadTest_Editor_Sandbox(EditorSharedTest):
|
||||
from Atom.tests import hydra_Atom_LevelLoadTest_Sandbox as test_module
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""
|
||||
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.
|
||||
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
|
||||
|
||||
@@ -9,19 +8,12 @@ import datetime
|
||||
import os
|
||||
import zipfile
|
||||
|
||||
from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots
|
||||
|
||||
|
||||
class ImageComparisonTestFailure(Exception):
|
||||
"""Custom test failure for failed image comparisons."""
|
||||
pass
|
||||
|
||||
|
||||
def create_screenshots_archive(screenshot_path):
|
||||
"""
|
||||
Creates a new zip file archive at archive_path containing all files listed within archive_path.
|
||||
:param screenshot_path: location containing the files to archive, the zip archive file will also be saved here.
|
||||
:return: path to the created .zip file archive.
|
||||
:return: None, but creates a new zip file archive inside path containing all of the files inside archive_path.
|
||||
"""
|
||||
files_to_archive = []
|
||||
|
||||
@@ -35,16 +27,14 @@ def create_screenshots_archive(screenshot_path):
|
||||
# Setup variables for naming the zip archive file.
|
||||
timestamp = datetime.datetime.now().timestamp()
|
||||
formatted_timestamp = datetime.datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d_%H-%M-%S")
|
||||
screenshots_zip_file = os.path.join(screenshot_path, f'screenshots_{formatted_timestamp}.zip')
|
||||
screenshots_file = os.path.join(screenshot_path, f'screenshots_{formatted_timestamp}.zip')
|
||||
|
||||
# Write all of the valid .png and .ppm files to the archive file.
|
||||
with zipfile.ZipFile(screenshots_zip_file, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as zip_archive:
|
||||
with zipfile.ZipFile(screenshots_file, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as zip_archive:
|
||||
for file_path in files_to_archive:
|
||||
file_name = os.path.basename(file_path)
|
||||
zip_archive.write(file_path, file_name)
|
||||
|
||||
return screenshots_zip_file
|
||||
|
||||
|
||||
def golden_images_directory():
|
||||
"""
|
||||
@@ -63,201 +53,176 @@ def golden_images_directory():
|
||||
return golden_images_dir
|
||||
|
||||
|
||||
def compare_screenshot_similarity(
|
||||
test_screenshot, golden_image, similarity_threshold, create_zip_archive=False, screenshot_directory=""):
|
||||
def create_basic_atom_level(level_name):
|
||||
"""
|
||||
Compares the similarity between a test screenshot and a golden image.
|
||||
It returns a "Screenshots match" string if the comparison mean value is higher than the similarity threshold.
|
||||
Otherwise, it returns an error string.
|
||||
:param test_screenshot: path to the test screenshot to compare.
|
||||
:param golden_image: path to the golden image to compare.
|
||||
:param similarity_threshold: value for the comparison mean value to be asserted against.
|
||||
:param create_zip_archive: toggle to create a zip archive containing the screenshots if the assert check fails.
|
||||
:param screenshot_directory: directory containing screenshots to create zip archive from.
|
||||
:return: Error string if compared mean value < similarity threshold or screenshot_directory is missing for .zip,
|
||||
otherwise it returns a "Screenshots match" string.
|
||||
"""
|
||||
result = "Screenshots match"
|
||||
if create_zip_archive and not screenshot_directory:
|
||||
result = 'You must specify a screenshot_directory in order to create a zip archive.\n'
|
||||
|
||||
mean_similarity = compare_screenshots(test_screenshot, golden_image)
|
||||
if not mean_similarity > similarity_threshold:
|
||||
if create_zip_archive:
|
||||
create_screenshots_archive(screenshot_directory)
|
||||
result = (
|
||||
f"When comparing the test_screenshot: '{test_screenshot}' to golden_image: '{golden_image}'.\n"
|
||||
f"The mean similarity ({mean_similarity}) was lower than the similarity threshold ({similarity_threshold})")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def compare_screenshot_to_golden_image(
|
||||
screenshot_directory, test_screenshots, golden_images, similarity_threshold=0.99):
|
||||
"""
|
||||
Compares a list of test_screenshots to a list of golden_images and return True if they match within the
|
||||
similarity threshold set. Otherwise, it will raise ImageComparisonTestFailure with a failure message.
|
||||
:param screenshot_directory: path to the directory containing screenshots for creating .zip archives.
|
||||
:param test_screenshots: list of test screenshot path strings.
|
||||
:param golden_images: list of golden image path strings.
|
||||
:param similarity_threshold: float threshold tolerance to set when comparing screenshots to golden images.
|
||||
"""
|
||||
for test_screenshot, golden_image in zip(test_screenshots, golden_images):
|
||||
screenshot_comparison_result = compare_screenshot_similarity(
|
||||
test_screenshot, golden_image, similarity_threshold, True, screenshot_directory)
|
||||
if screenshot_comparison_result != "Screenshots match":
|
||||
raise ImageComparisonTestFailure(f"Screenshot test failed: {screenshot_comparison_result}")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def initial_viewport_setup(screen_width=1280, screen_height=720):
|
||||
"""
|
||||
For setting up the initial viewport resolution to expected default values before running a screenshot test.
|
||||
Defaults to 1280 x 720 resolution (in pixels).
|
||||
:param screen_width: Width in pixels to set the viewport width size to.
|
||||
:param screen_height: Height in pixels to set the viewport height size to.
|
||||
Creates a new level inside the Editor matching level_name & adds the following:
|
||||
1. "default_level" entity to hold all other entities.
|
||||
2. Adds Grid, Global Skylight (IBL), ground Mesh, Directional Light, Sphere w/ material+mesh, & Camera components.
|
||||
3. Each of these components has its settings tweaked slightly to match the ideal scene to test Atom rendering.
|
||||
:param level_name: name of the level to create and apply this basic setup to.
|
||||
:return: None
|
||||
"""
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.camera as camera
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
general.set_viewport_size(screen_width, screen_height)
|
||||
general.idle_wait_frames(1)
|
||||
general.update_viewport()
|
||||
general.idle_wait_frames(1)
|
||||
|
||||
|
||||
def enter_exit_game_mode_take_screenshot(screenshot_name, enter_game_tuple, exit_game_tuple, timeout_in_seconds=4):
|
||||
"""
|
||||
Enters game mode, takes a screenshot named screenshot_name (must include file extension), and exits game mode.
|
||||
:param screenshot_name: string representing the name of the screenshot file, including file extension.
|
||||
:param enter_game_tuple: tuple where the 1st string is success & 2nd string is failure for entering the game.
|
||||
:param exit_game_tuple: tuple where the 1st string is success & 2nd string is failure for exiting the game.
|
||||
:param timeout_in_seconds: int or float seconds to wait for entering/exiting game mode.
|
||||
:return: None
|
||||
"""
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from editor_python_test_tools.utils import TestHelper, Report
|
||||
|
||||
from Atom.atom_utils.screenshot_utils import ScreenshotHelper
|
||||
|
||||
screenshot_helper = ScreenshotHelper(general.idle_wait_frames)
|
||||
TestHelper.enter_game_mode(enter_game_tuple)
|
||||
TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=timeout_in_seconds)
|
||||
screenshot_helper.prepare_viewport_for_screenshot(1920, 1080)
|
||||
success_screenshot = TestHelper.wait_for_condition(
|
||||
function=lambda: screenshot_helper.capture_screenshot_blocking(screenshot_name),
|
||||
timeout_in_seconds=timeout_in_seconds)
|
||||
Report.result(("Screenshot taken", "Screenshot failed to be taken"), success_screenshot)
|
||||
TestHelper.exit_game_mode(exit_game_tuple)
|
||||
TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=timeout_in_seconds)
|
||||
|
||||
|
||||
def create_basic_atom_rendering_scene():
|
||||
"""
|
||||
Sets up a new scene inside the Editor for testing Atom rendering GPU output.
|
||||
Setup: Deletes all existing entities before creating the scene.
|
||||
The created scene includes:
|
||||
1. "Default Level" entity that holds all of the other entities.
|
||||
2. "Grid" entity: Contains a Grid component.
|
||||
3. "Global Skylight (IBL)" entity: Contains HDRI Skybox & Global Skylight (IBL) components.
|
||||
4. "Ground Plane" entity: Contains Material & Mesh components.
|
||||
5. "Directional Light" entity: Contains Directional Light component.
|
||||
6. "Sphere" entity: Contains Material & Mesh components.
|
||||
7. "Camera" entity: Contains Camera component.
|
||||
:return: None
|
||||
"""
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
import azlmbr.object
|
||||
|
||||
from editor_python_test_tools.asset_utils import Asset
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.editor_test_helper import EditorTestHelper
|
||||
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper")
|
||||
|
||||
DEGREE_RADIAN_FACTOR = 0.0174533
|
||||
# Create a new level.
|
||||
new_level_name = level_name
|
||||
heightmap_resolution = 512
|
||||
heightmap_meters_per_pixel = 1
|
||||
terrain_texture_resolution = 412
|
||||
use_terrain = False
|
||||
|
||||
# Setup: Deletes all existing entities before creating the scene.
|
||||
# Return codes are ECreateLevelResult defined in CryEdit.h
|
||||
return_code = general.create_level_no_prompt(
|
||||
new_level_name, heightmap_resolution, heightmap_meters_per_pixel, terrain_texture_resolution, use_terrain)
|
||||
if return_code == 1:
|
||||
general.log(f"{new_level_name} level already exists")
|
||||
elif return_code == 2:
|
||||
general.log("Failed to create directory")
|
||||
elif return_code == 3:
|
||||
general.log("Directory length is too long")
|
||||
elif return_code != 0:
|
||||
general.log("Unknown error, failed to create level")
|
||||
else:
|
||||
general.log(f"{new_level_name} level created successfully")
|
||||
|
||||
# Enable idle and update viewport.
|
||||
general.idle_enable(True)
|
||||
general.idle_wait(1.0)
|
||||
general.update_viewport()
|
||||
general.idle_wait(0.5) # half a second is more than enough for updating the viewport.
|
||||
|
||||
# Close out problematic windows, FPS meters, and anti-aliasing.
|
||||
if general.is_helpers_shown(): # Turn off the helper gizmos if visible
|
||||
general.toggle_helpers()
|
||||
general.idle_wait(1.0)
|
||||
if general.is_pane_visible("Error Report"): # Close Error Report windows that block focus.
|
||||
general.close_pane("Error Report")
|
||||
if general.is_pane_visible("Error Log"): # Close Error Log windows that block focus.
|
||||
general.close_pane("Error Log")
|
||||
general.idle_wait(1.0)
|
||||
general.run_console("r_displayInfo=0")
|
||||
general.idle_wait(1.0)
|
||||
|
||||
# Delete all existing entities & create default_level entity
|
||||
search_filter = azlmbr.entity.SearchFilter()
|
||||
all_entities = azlmbr.entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter)
|
||||
azlmbr.editor.ToolsApplicationRequestBus(azlmbr.bus.Broadcast, "DeleteEntities", all_entities)
|
||||
all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter)
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities)
|
||||
default_level = hydra.Entity("default_level")
|
||||
default_position = math.Vector3(0.0, 0.0, 0.0)
|
||||
default_level.create_entity(default_position, ["Grid"])
|
||||
default_level.get_set_test(0, "Controller|Configuration|Secondary Grid Spacing", 1.0)
|
||||
|
||||
# 1. "Default Level" entity that holds all of the other entities.
|
||||
default_level_entity_name = "Default Level"
|
||||
default_level_entity = EditorEntity.create_editor_entity_at(math.Vector3(0.0, 0.0, 0.0), default_level_entity_name)
|
||||
# Set the viewport up correctly after adding the parent default_level entity.
|
||||
screen_width = 1280
|
||||
screen_height = 720
|
||||
degree_radian_factor = 0.0174533 # Used by "Rotation" property for the Transform component.
|
||||
general.set_viewport_size(screen_width, screen_height)
|
||||
general.update_viewport()
|
||||
helper.wait_for_condition(
|
||||
function=lambda: helper.isclose(a=general.get_viewport_size().x, b=screen_width, rel_tol=0.1)
|
||||
and helper.isclose(a=general.get_viewport_size().y, b=screen_height, rel_tol=0.1),
|
||||
timeout_in_seconds=4.0
|
||||
)
|
||||
result = helper.isclose(a=general.get_viewport_size().x, b=screen_width, rel_tol=0.1) and helper.isclose(
|
||||
a=general.get_viewport_size().y, b=screen_height, rel_tol=0.1)
|
||||
general.log(general.get_viewport_size().x)
|
||||
general.log(general.get_viewport_size().y)
|
||||
general.log(general.get_viewport_size().z)
|
||||
general.log(f"Viewport is set to the expected size: {result}")
|
||||
general.log("Basic level created")
|
||||
general.run_console("r_DisplayInfo = 0")
|
||||
|
||||
# 2. "Grid" entity: Contains a Grid component.
|
||||
grid_entity = EditorEntity.create_editor_entity(AtomComponentProperties.grid(), default_level_entity.id)
|
||||
grid_component = grid_entity.add_component(AtomComponentProperties.grid())
|
||||
secondary_grid_spacing_value = 1.0
|
||||
grid_component.set_component_property_value(
|
||||
AtomComponentProperties.grid('Secondary Grid Spacing'), secondary_grid_spacing_value)
|
||||
# Create global_skylight entity and set the properties
|
||||
global_skylight = hydra.Entity("global_skylight")
|
||||
global_skylight.create_entity(
|
||||
entity_position=default_position,
|
||||
components=["HDRi Skybox", "Global Skylight (IBL)"],
|
||||
parent_id=default_level.id)
|
||||
global_skylight_asset_path = os.path.join("LightingPresets", "default_iblskyboxcm.exr.streamingimage")
|
||||
global_skylight_asset_value = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", global_skylight_asset_path, math.Uuid(), False)
|
||||
global_skylight.get_set_test(0, "Controller|Configuration|Cubemap Texture", global_skylight_asset_value)
|
||||
global_skylight.get_set_test(1, "Controller|Configuration|Diffuse Image", global_skylight_asset_value)
|
||||
global_skylight.get_set_test(1, "Controller|Configuration|Specular Image", global_skylight_asset_value)
|
||||
|
||||
# 3. "Global Skylight (IBL)" entity: Contains HDRI Skybox & Global Skylight (IBL) components.
|
||||
global_skylight_entity = EditorEntity.create_editor_entity(
|
||||
AtomComponentProperties.global_skylight(), default_level_entity.id)
|
||||
hdri_skybox_component = global_skylight_entity.add_component(AtomComponentProperties.hdri_skybox())
|
||||
global_skylight_component = global_skylight_entity.add_component(AtomComponentProperties.global_skylight())
|
||||
global_skylight_image_asset_path = os.path.join("LightingPresets", "default_iblskyboxcm.exr.streamingimage")
|
||||
global_skylight_image_asset = Asset.find_asset_by_path(global_skylight_image_asset_path, False)
|
||||
hdri_skybox_component.set_component_property_value(
|
||||
AtomComponentProperties.hdri_skybox('Cubemap Texture'), global_skylight_image_asset.id)
|
||||
global_skylight_diffuse_image_asset_path = os.path.join(
|
||||
"LightingPresets", "default_iblskyboxcm_ibldiffuse.exr.streamingimage")
|
||||
global_skylight_diffuse_image_asset = Asset.find_asset_by_path(global_skylight_diffuse_image_asset_path, False)
|
||||
global_skylight_component.set_component_property_value(
|
||||
AtomComponentProperties.global_skylight('Diffuse Image'), global_skylight_diffuse_image_asset.id)
|
||||
global_skylight_specular_image_asset_path = os.path.join(
|
||||
"LightingPresets", "default_iblskyboxcm_iblspecular.exr.streamingimage")
|
||||
global_skylight_specular_image_asset = Asset.find_asset_by_path(
|
||||
global_skylight_specular_image_asset_path, False)
|
||||
global_skylight_component.set_component_property_value(
|
||||
AtomComponentProperties.global_skylight('Specular Image'), global_skylight_specular_image_asset.id)
|
||||
# Create ground_plane entity and set the properties
|
||||
ground_plane = hydra.Entity("ground_plane")
|
||||
ground_plane.create_entity(
|
||||
entity_position=default_position,
|
||||
components=["Material"],
|
||||
parent_id=default_level.id)
|
||||
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", ground_plane.id, 32.0)
|
||||
ground_plane_material_asset_path = os.path.join(
|
||||
"Materials", "Presets", "PBR", "metal_chrome.azmaterial")
|
||||
ground_plane_material_asset_value = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", ground_plane_material_asset_path, math.Uuid(), False)
|
||||
ground_plane.get_set_test(0, "Default Material|Material Asset", ground_plane_material_asset_value)
|
||||
|
||||
# 4. "Ground Plane" entity: Contains Material & Mesh components.
|
||||
ground_plane_name = "Ground Plane"
|
||||
ground_plane_entity = EditorEntity.create_editor_entity(ground_plane_name, default_level_entity.id)
|
||||
ground_plane_material_component = ground_plane_entity.add_component(AtomComponentProperties.material())
|
||||
ground_plane_entity.set_local_uniform_scale(32.0)
|
||||
ground_plane_mesh_component = ground_plane_entity.add_component(AtomComponentProperties.mesh())
|
||||
ground_plane_mesh_asset_path = os.path.join("TestData", "Objects", "plane.azmodel")
|
||||
ground_plane_mesh_asset = Asset.find_asset_by_path(ground_plane_mesh_asset_path, False)
|
||||
ground_plane_mesh_component.set_component_property_value(
|
||||
AtomComponentProperties.mesh('Mesh Asset'), ground_plane_mesh_asset.id)
|
||||
ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial")
|
||||
ground_plane_material_asset = Asset.find_asset_by_path(ground_plane_material_asset_path, False)
|
||||
ground_plane_material_component.set_component_property_value(
|
||||
AtomComponentProperties.material('Material Asset'), ground_plane_material_asset.id)
|
||||
# Work around to add the correct Atom Mesh component
|
||||
mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId
|
||||
ground_plane.components.append(
|
||||
editor.EditorComponentAPIBus(
|
||||
bus.Broadcast, "AddComponentsOfType", ground_plane.id, [mesh_type_id]
|
||||
).GetValue()[0]
|
||||
)
|
||||
ground_plane_mesh_asset_path = os.path.join("Models", "plane.azmodel")
|
||||
ground_plane_mesh_asset_value = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", ground_plane_mesh_asset_path, math.Uuid(), False)
|
||||
ground_plane.get_set_test(1, "Controller|Configuration|Mesh Asset", ground_plane_mesh_asset_value)
|
||||
|
||||
# 5. "Directional Light" entity: Contains Directional Light component.
|
||||
directional_light_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(0.0, 0.0, 10.0), AtomComponentProperties.directional_light(), default_level_entity.id)
|
||||
directional_light_entity.add_component(AtomComponentProperties.directional_light())
|
||||
directional_light_entity_rotation = math.Vector3(DEGREE_RADIAN_FACTOR * -90.0, 0.0, 0.0)
|
||||
directional_light_entity.set_local_rotation(directional_light_entity_rotation)
|
||||
# Create directional_light entity and set the properties
|
||||
directional_light = hydra.Entity("directional_light")
|
||||
directional_light.create_entity(
|
||||
entity_position=math.Vector3(0.0, 0.0, 10.0),
|
||||
components=["Directional Light"],
|
||||
parent_id=default_level.id)
|
||||
directional_light_rotation = math.Vector3(degree_radian_factor * -90.0, 0.0, 0.0)
|
||||
azlmbr.components.TransformBus(
|
||||
azlmbr.bus.Event, "SetLocalRotation", directional_light.id, directional_light_rotation)
|
||||
|
||||
# 6. "Sphere" entity: Contains Material & Mesh components.
|
||||
sphere_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(0.0, 0.0, 1.0), "Sphere", default_level_entity.id)
|
||||
sphere_mesh_component = sphere_entity.add_component(AtomComponentProperties.mesh())
|
||||
sphere_mesh_asset_path = os.path.join("Models", "sphere.azmodel")
|
||||
sphere_mesh_asset = Asset.find_asset_by_path(sphere_mesh_asset_path, False)
|
||||
sphere_mesh_component.set_component_property_value(
|
||||
AtomComponentProperties.mesh('Mesh Asset'), sphere_mesh_asset.id)
|
||||
sphere_material_component = sphere_entity.add_component(AtomComponentProperties.material())
|
||||
# Create sphere entity and set the properties
|
||||
sphere_entity = hydra.Entity("sphere")
|
||||
sphere_entity.create_entity(
|
||||
entity_position=math.Vector3(0.0, 0.0, 1.0),
|
||||
components=["Material"],
|
||||
parent_id=default_level.id)
|
||||
sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial")
|
||||
sphere_material_asset = Asset.find_asset_by_path(sphere_material_asset_path, False)
|
||||
sphere_material_component.set_component_property_value(
|
||||
AtomComponentProperties.material('Material Asset'), sphere_material_asset.id)
|
||||
sphere_material_asset_value = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False)
|
||||
sphere_entity.get_set_test(0, "Default Material|Material Asset", sphere_material_asset_value)
|
||||
|
||||
# 7. "Camera" entity: Contains Camera component.
|
||||
camera_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(5.5, -12.0, 9.0), AtomComponentProperties.camera(), default_level_entity.id)
|
||||
camera_component = camera_entity.add_component(AtomComponentProperties.camera())
|
||||
camera_entity_rotation = math.Vector3(
|
||||
DEGREE_RADIAN_FACTOR * -27.0, DEGREE_RADIAN_FACTOR * -12.0, DEGREE_RADIAN_FACTOR * 25.0)
|
||||
camera_entity.set_local_rotation(camera_entity_rotation)
|
||||
camera_fov_value = 60.0
|
||||
camera_component.set_component_property_value(AtomComponentProperties.camera('Field of view'), camera_fov_value)
|
||||
azlmbr.camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id)
|
||||
# Work around to add the correct Atom Mesh component
|
||||
sphere_entity.components.append(
|
||||
editor.EditorComponentAPIBus(
|
||||
bus.Broadcast, "AddComponentsOfType", sphere_entity.id, [mesh_type_id]
|
||||
).GetValue()[0]
|
||||
)
|
||||
sphere_mesh_asset_path = os.path.join("Models", "sphere.azmodel")
|
||||
sphere_mesh_asset_value = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", sphere_mesh_asset_path, math.Uuid(), False)
|
||||
sphere_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_mesh_asset_value)
|
||||
|
||||
# Create camera component and set the properties
|
||||
camera_entity = hydra.Entity("camera")
|
||||
camera_entity.create_entity(
|
||||
entity_position=math.Vector3(5.5, -12.0, 9.0),
|
||||
components=["Camera"],
|
||||
parent_id=default_level.id)
|
||||
rotation = math.Vector3(
|
||||
degree_radian_factor * -27.0, degree_radian_factor * -12.0, degree_radian_factor * 25.0
|
||||
)
|
||||
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", camera_entity.id, rotation)
|
||||
camera_entity.get_set_test(0, "Controller|Configuration|Field of view", 60.0)
|
||||
camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id)
|
||||
|
||||
@@ -19,24 +19,6 @@ LIGHT_TYPES = {
|
||||
}
|
||||
|
||||
|
||||
# Attenuation Radius Mode options for the Light component.
|
||||
ATTENUATION_RADIUS_MODE = {
|
||||
'automatic': 1,
|
||||
'explicit': 0,
|
||||
}
|
||||
|
||||
# Qualiity Level settings for Diffuse Global Illumination level component
|
||||
GLOBAL_ILLUMINATION_QUALITY = {
|
||||
'Low': 0,
|
||||
'Medium': 1,
|
||||
'High': 2,
|
||||
}
|
||||
|
||||
# Level list used in Editor Level Load Test
|
||||
# WARNING: "Sponza" level is sandboxed due to an intermittent failure.
|
||||
LEVEL_LIST = ["hermanubis", "hermanubis_high", "macbeth_shaderballs", "PbrMaterialChart", "ShadowTest"]
|
||||
|
||||
|
||||
class AtomComponentProperties:
|
||||
"""
|
||||
Holds Atom component related constants
|
||||
@@ -60,14 +42,12 @@ class AtomComponentProperties:
|
||||
Bloom component properties. Requires PostFX Layer component.
|
||||
- 'requires' a list of component names as strings required by this component.
|
||||
Use editor_entity_utils EditorEntity.add_components(list) to add this list of requirements.\n
|
||||
- 'Enable Bloom' Toggle active state of the component True/False
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
properties = {
|
||||
'name': 'Bloom',
|
||||
'requires': [AtomComponentProperties.postfx_layer()],
|
||||
'Enable Bloom': 'Controller|Configuration|Enable Bloom',
|
||||
}
|
||||
return properties[property]
|
||||
|
||||
@@ -89,18 +69,12 @@ class AtomComponentProperties:
|
||||
def decal(property: str = 'name') -> str:
|
||||
"""
|
||||
Decal component properties.
|
||||
- 'Attenuation Angle' controls how much the angle between geometry and decal impacts opacity. 0-1 Radians
|
||||
- 'Opacity' where one is opaque and zero is transparent
|
||||
- 'Sort Key' 0-255 stacking z-sort like key to define which decal is on top of another
|
||||
- 'Material' the material Asset.id of the decal.
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
properties = {
|
||||
'name': 'Decal',
|
||||
'Attenuation Angle': 'Controller|Configuration|Attenuation Angle',
|
||||
'Opacity': 'Controller|Configuration|Opacity',
|
||||
'Sort Key': 'Controller|Configuration|Sort Key',
|
||||
'Material': 'Controller|Configuration|Material',
|
||||
}
|
||||
return properties[property]
|
||||
@@ -111,14 +85,12 @@ class AtomComponentProperties:
|
||||
Deferred Fog component properties. Requires PostFX Layer component.
|
||||
- 'requires' a list of component names as strings required by this component.
|
||||
Use editor_entity_utils EditorEntity.add_components(list) to add this list of requirements.\n
|
||||
- 'Enable Deferred Fog' Toggle active state of the component True/False
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
properties = {
|
||||
'name': 'Deferred Fog',
|
||||
'requires': [AtomComponentProperties.postfx_layer()],
|
||||
'Enable Deferred Fog': 'Controller|Configuration|Enable Deferred Fog',
|
||||
}
|
||||
return properties[property]
|
||||
|
||||
@@ -141,22 +113,7 @@ class AtomComponentProperties:
|
||||
return properties[property]
|
||||
|
||||
@staticmethod
|
||||
def diffuse_global_illumination(property: str = 'name') -> str:
|
||||
"""
|
||||
Diffuse Global Illumination level component properties.
|
||||
Controls global settings for Diffuse Probe Grid components.
|
||||
- 'Quality Level' from atom_constants.py GLOBAL_ILLUMINATION_QUALITY
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
properties = {
|
||||
'name': 'Diffuse Global Illumination',
|
||||
'Quality Level': 'Controller|Configuration|Quality Level'
|
||||
}
|
||||
return properties[property]
|
||||
|
||||
@staticmethod
|
||||
def diffuse_probe_grid(property: str = 'name') -> str:
|
||||
def diffuse_probe(property: str = 'name') -> str:
|
||||
"""
|
||||
Diffuse Probe Grid component properties. Requires one of 'shapes'.
|
||||
- 'shapes' a list of supported shapes as component names.
|
||||
@@ -187,17 +144,12 @@ class AtomComponentProperties:
|
||||
@staticmethod
|
||||
def display_mapper(property: str = 'name') -> str:
|
||||
"""
|
||||
Display Mapper level component properties.
|
||||
- 'Enable LDR color grading LUT' toggles the use of LDR color grading LUT
|
||||
- 'LDR color Grading LUT' is the Low Definition Range (LDR) color grading for Look-up Textures (LUT) which is
|
||||
an Asset.id value corresponding to a lighting asset file.
|
||||
Display Mapper component properties.
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
properties = {
|
||||
'name': 'Display Mapper',
|
||||
'Enable LDR color grading LUT': 'Controller|Configuration|Enable LDR color grading LUT',
|
||||
'LDR color Grading LUT': 'Controller|Configuration|LDR color Grading LUT',
|
||||
}
|
||||
return properties[property]
|
||||
|
||||
@@ -205,13 +157,11 @@ class AtomComponentProperties:
|
||||
def entity_reference(property: str = 'name') -> str:
|
||||
"""
|
||||
Entity Reference component properties.
|
||||
- 'EntityIdReferences' component container of entityId references. Initially empty.
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
properties = {
|
||||
'name': 'Entity Reference',
|
||||
'EntityIdReferences': 'Controller|Configuration|EntityIdReferences',
|
||||
}
|
||||
return properties[property]
|
||||
|
||||
@@ -250,14 +200,12 @@ class AtomComponentProperties:
|
||||
def grid(property: str = 'name') -> str:
|
||||
"""
|
||||
Grid component properties.
|
||||
- 'Grid Size': The size of the grid, default value is 32
|
||||
- 'Secondary Grid Spacing': The spacing value for the secondary grid, i.e. 1.0
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
properties = {
|
||||
'name': 'Grid',
|
||||
'Grid Size': 'Controller|Configuration|Grid Size',
|
||||
'Secondary Grid Spacing': 'Controller|Configuration|Secondary Grid Spacing',
|
||||
}
|
||||
return properties[property]
|
||||
@@ -268,14 +216,12 @@ class AtomComponentProperties:
|
||||
HDR Color Grading component properties. Requires PostFX Layer component.
|
||||
- 'requires' a list of component names as strings required by this component.
|
||||
Use editor_entity_utils EditorEntity.add_components(list) to add this list of requirements.\n
|
||||
- 'Enable HDR color grading' Toggle active state of the component True/False
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
properties = {
|
||||
'name': 'HDR Color Grading',
|
||||
'requires': [AtomComponentProperties.postfx_layer()],
|
||||
'Enable HDR color grading': 'Controller|Configuration|Enable HDR color grading',
|
||||
}
|
||||
return properties[property]
|
||||
|
||||
@@ -297,27 +243,13 @@ class AtomComponentProperties:
|
||||
def light(property: str = 'name') -> str:
|
||||
"""
|
||||
Light component properties.
|
||||
- 'Attenuation Radius Mode' controls whether the attenuation radius is calculated automatically or explicitly.
|
||||
- 'Color' the RGB value to set for the color of the light.
|
||||
- 'Enable shadow' toggle for enabling shadows for the light.
|
||||
- 'Enable shutters' toggle for enabling shutters for the light.
|
||||
- 'Inner angle' inner angle value for the shutters (in degrees)
|
||||
- 'Intensity' the intensity of the light in the set photometric unit (float with no ceiling).
|
||||
- 'Light type' from atom_constants.py LIGHT_TYPES
|
||||
- 'Outer angle' outer angle value for the shutters (in degrees)
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
properties = {
|
||||
'name': 'Light',
|
||||
'Attenuation Radius Mode': 'Controller|Configuration|Attenuation radius|Mode',
|
||||
'Color': 'Controller|Configuration|Color',
|
||||
'Enable shadow': 'Controller|Configuration|Shadows|Enable shadow',
|
||||
'Enable shutters': 'Controller|Configuration|Shutters|Enable shutters',
|
||||
'Inner angle': 'Controller|Configuration|Shutters|Inner angle',
|
||||
'Intensity': 'Controller|Configuration|Intensity',
|
||||
'Light type': 'Controller|Configuration|Light type',
|
||||
'Outer angle': 'Controller|Configuration|Shutters|Outer angle',
|
||||
}
|
||||
return properties[property]
|
||||
|
||||
@@ -327,16 +259,12 @@ class AtomComponentProperties:
|
||||
Look Modification component properties. Requires PostFX Layer component.
|
||||
- 'requires' a list of component names as strings required by this component.
|
||||
Use editor_entity_utils EditorEntity.add_components(list) to add this list of requirements.\n
|
||||
- 'Enable look modification' Toggle active state of the component True/False
|
||||
- 'Color Grading LUT' Asset.id for the LUT used for affecting level look.
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
properties = {
|
||||
'name': 'Look Modification',
|
||||
'requires': [AtomComponentProperties.postfx_layer()],
|
||||
'Enable look modification': 'Controller|Configuration|Enable look modification',
|
||||
'Color Grading LUT': 'Controller|Configuration|Color Grading LUT',
|
||||
}
|
||||
return properties[property]
|
||||
|
||||
@@ -388,13 +316,11 @@ class AtomComponentProperties:
|
||||
def physical_sky(property: str = 'name') -> str:
|
||||
"""
|
||||
Physical Sky component properties.
|
||||
- 'Sky Intensity' float that determines sky intensity value, default value is 4.
|
||||
:param property: From the last element of the property tree path. Default 'name' for component name string.
|
||||
:return: Full property path OR component name if no property specified.
|
||||
"""
|
||||
properties = {
|
||||
'name': 'Physical Sky',
|
||||
'Sky Intensity': 'Controller|Configuration|Sky Intensity',
|
||||
}
|
||||
return properties[property]
|
||||
|
||||
@@ -454,7 +380,7 @@ class AtomComponentProperties:
|
||||
'name': 'PostFX Shape Weight Modifier',
|
||||
'requires': [AtomComponentProperties.postfx_layer()],
|
||||
'shapes': ['Axis Aligned Box Shape', 'Box Shape', 'Capsule Shape', 'Compound Shape', 'Cylinder Shape',
|
||||
'Disk Shape', 'Polygon Prism Shape', 'Quad Shape', 'Sphere Shape', 'Shape Reference'],
|
||||
'Disk Shape', 'Polygon Prism Shape', 'Quad Shape', 'Sphere Shape', 'Vegetation Reference Shape'],
|
||||
}
|
||||
return properties[property]
|
||||
|
||||
|
||||
@@ -114,22 +114,22 @@ def get_property(document_id, property_name):
|
||||
"""
|
||||
:return: property value or invalid value if the document is not open or the property_name can't be found
|
||||
"""
|
||||
return azlmbr.materialeditor.MaterialDocumentRequestBus(bus.Event, "GetPropertyValue", document_id, property_name)
|
||||
return azlmbr.atomtools.AtomToolsDocumentRequestBus(bus.Event, "GetPropertyValue", document_id, property_name)
|
||||
|
||||
|
||||
def set_property(document_id, property_name, value):
|
||||
azlmbr.materialeditor.MaterialDocumentRequestBus(bus.Event, "SetPropertyValue", document_id, property_name, value)
|
||||
azlmbr.atomtools.AtomToolsDocumentRequestBus(bus.Event, "SetPropertyValue", document_id, property_name, value)
|
||||
|
||||
|
||||
def is_pane_visible(pane_name):
|
||||
"""
|
||||
:return: bool
|
||||
"""
|
||||
return atomtools.AtomToolsMainWindowRequestBus(bus.Broadcast, "IsDockWidgetVisible", pane_name)
|
||||
return atomtools.AtomToolsWindowRequestBus(bus.Broadcast, "IsDockWidgetVisible", pane_name)
|
||||
|
||||
|
||||
def set_pane_visibility(pane_name, value):
|
||||
atomtools.AtomToolsMainWindowRequestBus(bus.Broadcast, "SetDockWidgetVisible", pane_name, value)
|
||||
atomtools.AtomToolsWindowRequestBus(bus.Broadcast, "SetDockWidgetVisible", pane_name, value)
|
||||
|
||||
|
||||
def select_lighting_config(config_name):
|
||||
@@ -162,13 +162,6 @@ def select_model_config(configname):
|
||||
azlmbr.materialeditor.MaterialViewportRequestBus(azlmbr.bus.Broadcast, "SelectModelPresetByName", configname)
|
||||
|
||||
|
||||
def exit():
|
||||
"""
|
||||
Closes the Material Editor
|
||||
"""
|
||||
azlmbr.atomtools.general.exit()
|
||||
|
||||
|
||||
def wait_for_condition(function, timeout_in_seconds=1.0):
|
||||
# type: (function, float) -> bool
|
||||
"""
|
||||
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
class Tests:
|
||||
creation_undo = (
|
||||
"UNDO Level component addition success",
|
||||
"UNDO Level component addition failed")
|
||||
creation_redo = (
|
||||
"REDO Level component addition success",
|
||||
"REDO Level component addition failed")
|
||||
diffuse_global_illumination_component = (
|
||||
"Level has a Diffuse Global Illumination component",
|
||||
"Level failed to find Diffuse Global Illumination component")
|
||||
diffuse_global_illumination_quality = (
|
||||
"Quality Level set",
|
||||
"Quality Level could not be set")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
|
||||
|
||||
def AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Diffuse Global Illumination level component can be added to the level entity and is stable.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Add Diffuse Global Illumination level component to the level entity.
|
||||
2) UNDO the level component addition.
|
||||
3) REDO the level component addition.
|
||||
4) Set Quality Level property to Low
|
||||
5) Enter/Exit game mode.
|
||||
6) Look for errors and asserts.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorLevelEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties, GLOBAL_ILLUMINATION_QUALITY
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Add Diffuse Global Illumination level component to the level entity.
|
||||
diffuse_global_illumination_component = EditorLevelEntity.add_component(
|
||||
AtomComponentProperties.diffuse_global_illumination())
|
||||
Report.critical_result(
|
||||
Tests.diffuse_global_illumination_component,
|
||||
EditorLevelEntity.has_component(AtomComponentProperties.diffuse_global_illumination()))
|
||||
|
||||
# 2. UNDO the level component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo,
|
||||
not EditorLevelEntity.has_component(AtomComponentProperties.diffuse_global_illumination()))
|
||||
|
||||
# 3. REDO the level component addition.
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo,
|
||||
EditorLevelEntity.has_component(AtomComponentProperties.diffuse_global_illumination()))
|
||||
|
||||
# 4. Set Quality Level property to Low
|
||||
diffuse_global_illumination_component.set_component_property_value(
|
||||
AtomComponentProperties.diffuse_global_illumination('Quality Level'), GLOBAL_ILLUMINATION_QUALITY['Low'])
|
||||
quality = diffuse_global_illumination_component.get_component_property_value(
|
||||
AtomComponentProperties.diffuse_global_illumination('Quality Level'))
|
||||
Report.result(Tests.diffuse_global_illumination_quality, quality == GLOBAL_ILLUMINATION_QUALITY['Low'])
|
||||
|
||||
# 5. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 6. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity)
|
||||
-124
@@ -1,124 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
|
||||
class Tests:
|
||||
creation_undo = (
|
||||
"UNDO level component addition success",
|
||||
"UNDO level component addition failed")
|
||||
creation_redo = (
|
||||
"REDO Level component addition success",
|
||||
"REDO Level component addition failed")
|
||||
display_mapper_component = (
|
||||
"Level has a Display Mapper component",
|
||||
"Level failed to find Display Mapper component")
|
||||
ldr_color_grading_lut = (
|
||||
"LDR color Grading LUT asset set",
|
||||
"LDR color Grading LUT asset could not be set")
|
||||
enable_ldr_color_grading_lut = (
|
||||
"Enable LDR color grading LUT set",
|
||||
"Enable LDR color grading LUT could not be set")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
|
||||
|
||||
def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Display Mapper level component can be added to the level entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Add Display Mapper level component to the level entity.
|
||||
2) UNDO the level component addition.
|
||||
3) REDO the level component addition.
|
||||
4) Set LDR color Grading LUT asset.
|
||||
5) Set Enable LDR color grading LUT property True
|
||||
6) Enter/Exit game mode.
|
||||
7) Look for errors and asserts.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from editor_python_test_tools.asset_utils import Asset
|
||||
from editor_python_test_tools.editor_entity_utils import EditorLevelEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Add Display Mapper level component to the level entity.
|
||||
display_mapper_component = EditorLevelEntity.add_component(AtomComponentProperties.display_mapper())
|
||||
Report.critical_result(
|
||||
Tests.display_mapper_component,
|
||||
EditorLevelEntity.has_component(AtomComponentProperties.display_mapper()))
|
||||
|
||||
# 2. UNDO the level component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not EditorLevelEntity.has_component(AtomComponentProperties.display_mapper()))
|
||||
|
||||
# 3. REDO the level component addition.
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, EditorLevelEntity.has_component(AtomComponentProperties.display_mapper()))
|
||||
|
||||
# 4. Set LDR color Grading LUT asset.
|
||||
display_mapper_asset_path = os.path.join("TestData", "test.lightingpreset.azasset")
|
||||
display_mapper_asset = Asset.find_asset_by_path(display_mapper_asset_path, False)
|
||||
display_mapper_component.set_component_property_value(
|
||||
AtomComponentProperties.display_mapper('LDR color Grading LUT'), display_mapper_asset.id)
|
||||
Report.result(
|
||||
Tests.ldr_color_grading_lut,
|
||||
display_mapper_component.get_component_property_value(
|
||||
AtomComponentProperties.display_mapper('LDR color Grading LUT')) == display_mapper_asset.id)
|
||||
|
||||
# 5. Set Enable LDR color grading LUT property True
|
||||
display_mapper_component.set_component_property_value(
|
||||
AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True)
|
||||
Report.result(
|
||||
Tests.enable_ldr_color_grading_lut,
|
||||
display_mapper_component.get_component_property_value(
|
||||
AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True)
|
||||
|
||||
# 6. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 7. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponentsLevel_DisplayMapper_AddedToEntity)
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.math as math
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.paths
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.render as render
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from editor_python_test_tools.utils import TestHelper
|
||||
|
||||
|
||||
def run():
|
||||
"""
|
||||
Summary:
|
||||
The below common tests are done for each of the components.
|
||||
1) Addition of component to the entity
|
||||
2) UNDO/REDO of addition of component
|
||||
3) Enter/Exit game mode
|
||||
4) Hide/Show entity containing component
|
||||
5) Deletion of component
|
||||
6) UNDO/REDO of deletion of component
|
||||
Some additional tests for specific components include
|
||||
1) Assigning value to some properties of each component
|
||||
2) Verifying if the component is activated only when the required components are added
|
||||
|
||||
Expected Result:
|
||||
1) Component can be added to an entity.
|
||||
2) The addition of component can be undone and redone.
|
||||
3) Game mode can be entered/exited without issue.
|
||||
4) Entity with component can be hidden/shown.
|
||||
5) Component can be deleted.
|
||||
6) The deletion of component can be undone and redone.
|
||||
7) Component is activated only when the required components are added
|
||||
8) Values can be assigned to the properties of the component
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def create_entity_undo_redo_component_addition(component_name):
|
||||
new_entity = hydra.Entity(f"{component_name}")
|
||||
new_entity.create_entity(math.Vector3(512.0, 512.0, 34.0), [component_name])
|
||||
general.log(f"{component_name}_test: Component added to the entity: "
|
||||
f"{hydra.has_components(new_entity.id, [component_name])}")
|
||||
|
||||
# undo component addition
|
||||
general.undo()
|
||||
TestHelper.wait_for_condition(lambda: not hydra.has_components(new_entity.id, [component_name]), 2.0)
|
||||
general.log(f"{component_name}_test: Component removed after UNDO: "
|
||||
f"{not hydra.has_components(new_entity.id, [component_name])}")
|
||||
|
||||
# redo component addition
|
||||
general.redo()
|
||||
TestHelper.wait_for_condition(lambda: hydra.has_components(new_entity.id, [component_name]), 2.0)
|
||||
general.log(f"{component_name}_test: Component added after REDO: "
|
||||
f"{hydra.has_components(new_entity.id, [component_name])}")
|
||||
|
||||
return new_entity
|
||||
|
||||
def verify_enter_exit_game_mode(component_name):
|
||||
general.enter_game_mode()
|
||||
TestHelper.wait_for_condition(lambda: general.is_in_game_mode(), 2.0)
|
||||
general.log(f"{component_name}_test: Entered game mode: {general.is_in_game_mode()}")
|
||||
general.exit_game_mode()
|
||||
TestHelper.wait_for_condition(lambda: not general.is_in_game_mode(), 2.0)
|
||||
general.log(f"{component_name}_test: Exit game mode: {not general.is_in_game_mode()}")
|
||||
|
||||
def verify_hide_unhide_entity(component_name, entity_obj):
|
||||
|
||||
def is_entity_hidden(entity_id):
|
||||
return editor.EditorEntityInfoRequestBus(bus.Event, "IsHidden", entity_id)
|
||||
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", entity_obj.id, False)
|
||||
general.idle_wait_frames(1)
|
||||
general.log(f"{component_name}_test: Entity is hidden: {is_entity_hidden(entity_obj.id)}")
|
||||
editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", entity_obj.id, True)
|
||||
general.idle_wait_frames(1)
|
||||
general.log(f"{component_name}_test: Entity is shown: {not is_entity_hidden(entity_obj.id)}")
|
||||
|
||||
def verify_deletion_undo_redo(component_name, entity_obj):
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntityById", entity_obj.id)
|
||||
TestHelper.wait_for_condition(lambda: not hydra.find_entity_by_name(entity_obj.name), 2.0)
|
||||
general.log(f"{component_name}_test: Entity deleted: {not hydra.find_entity_by_name(entity_obj.name)}")
|
||||
|
||||
general.undo()
|
||||
TestHelper.wait_for_condition(lambda: hydra.find_entity_by_name(entity_obj.name) is not None, 2.0)
|
||||
general.log(f"{component_name}_test: UNDO entity deletion works: "
|
||||
f"{hydra.find_entity_by_name(entity_obj.name) is not None}")
|
||||
|
||||
general.redo()
|
||||
TestHelper.wait_for_condition(lambda: not hydra.find_entity_by_name(entity_obj.name), 2.0)
|
||||
general.log(f"{component_name}_test: REDO entity deletion works: "
|
||||
f"{not hydra.find_entity_by_name(entity_obj.name)}")
|
||||
|
||||
def verify_required_component_addition(entity_obj, components_to_add, component_name):
|
||||
|
||||
def is_component_enabled(entity_componentid_pair):
|
||||
return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", entity_componentid_pair)
|
||||
|
||||
general.log(
|
||||
f"{component_name}_test: Entity disabled initially: "
|
||||
f"{not is_component_enabled(entity_obj.components[0])}")
|
||||
for component in components_to_add:
|
||||
entity_obj.add_component(component)
|
||||
TestHelper.wait_for_condition(lambda: is_component_enabled(entity_obj.components[0]), 2.0)
|
||||
general.log(
|
||||
f"{component_name}_test: Entity enabled after adding "
|
||||
f"required components: {is_component_enabled(entity_obj.components[0])}"
|
||||
)
|
||||
|
||||
def verify_set_property(entity_obj, path, value):
|
||||
entity_obj.get_set_test(0, path, value)
|
||||
|
||||
# Verify cubemap generation
|
||||
def verify_cubemap_generation(component_name, entity_obj):
|
||||
# Initially Check if the component has Reflection Probe component
|
||||
if not hydra.has_components(entity_obj.id, ["Reflection Probe"]):
|
||||
raise ValueError(f"Given entity {entity_obj.name} has no Reflection Probe component")
|
||||
render.EditorReflectionProbeBus(azlmbr.bus.Event, "BakeReflectionProbe", entity_obj.id)
|
||||
|
||||
def get_value():
|
||||
hydra.get_component_property_value(entity_obj.components[0], "Cubemap|Baked Cubemap Path")
|
||||
|
||||
TestHelper.wait_for_condition(lambda: get_value() != "", 20.0)
|
||||
general.log(f"{component_name}_test: Cubemap is generated: {get_value() != ''}")
|
||||
|
||||
# Wait for Editor idle loop before executing Python hydra scripts.
|
||||
TestHelper.init_idle()
|
||||
|
||||
# Delete all existing entities initially
|
||||
search_filter = azlmbr.entity.SearchFilter()
|
||||
all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter)
|
||||
editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities)
|
||||
|
||||
class ComponentTests:
|
||||
"""Test launcher for each component."""
|
||||
def __init__(self, component_name, *additional_tests):
|
||||
self.component_name = component_name
|
||||
self.additional_tests = additional_tests
|
||||
self.run_component_tests()
|
||||
|
||||
def run_component_tests(self):
|
||||
# Run common and additional tests
|
||||
entity_obj = create_entity_undo_redo_component_addition(self.component_name)
|
||||
|
||||
# Enter/Exit game mode test
|
||||
verify_enter_exit_game_mode(self.component_name)
|
||||
|
||||
# Any additional tests are executed here
|
||||
for test in self.additional_tests:
|
||||
test(entity_obj)
|
||||
|
||||
# Hide/Unhide entity test
|
||||
verify_hide_unhide_entity(self.component_name, entity_obj)
|
||||
|
||||
# Deletion/Undo/Redo test
|
||||
verify_deletion_undo_redo(self.component_name, entity_obj)
|
||||
|
||||
# DepthOfField Component
|
||||
camera_entity = hydra.Entity("camera_entity")
|
||||
camera_entity.create_entity(math.Vector3(512.0, 512.0, 34.0), ["Camera"])
|
||||
depth_of_field = "DepthOfField"
|
||||
ComponentTests(
|
||||
depth_of_field,
|
||||
lambda entity_obj: verify_required_component_addition(entity_obj, ["PostFX Layer"], depth_of_field),
|
||||
lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Camera Entity", camera_entity.id))
|
||||
|
||||
# Decal Component
|
||||
material_asset_path = os.path.join("AutomatedTesting", "Materials", "basic_grey.material")
|
||||
material_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", material_asset_path, math.Uuid(), False)
|
||||
ComponentTests(
|
||||
"Decal", lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Material", material_asset))
|
||||
|
||||
# Directional Light Component
|
||||
ComponentTests(
|
||||
"Directional Light",
|
||||
lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Shadow|Camera", camera_entity.id))
|
||||
|
||||
# Exposure Control Component
|
||||
ComponentTests(
|
||||
"Exposure Control", lambda entity_obj: verify_required_component_addition(
|
||||
entity_obj, ["PostFX Layer"], "Exposure Control"))
|
||||
|
||||
# Global Skylight (IBL) Component
|
||||
diffuse_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage")
|
||||
diffuse_image_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", diffuse_image_path, math.Uuid(), False)
|
||||
specular_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage")
|
||||
specular_image_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", specular_image_path, math.Uuid(), False)
|
||||
ComponentTests(
|
||||
"Global Skylight (IBL)",
|
||||
lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Diffuse Image", diffuse_image_asset),
|
||||
lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Specular Image", specular_image_asset))
|
||||
|
||||
# Physical Sky Component
|
||||
ComponentTests("Physical Sky")
|
||||
|
||||
# PostFX Layer Component
|
||||
ComponentTests("PostFX Layer")
|
||||
|
||||
# PostFX Radius Weight Modifier Component
|
||||
ComponentTests("PostFX Radius Weight Modifier")
|
||||
|
||||
# Light Component
|
||||
ComponentTests("Light")
|
||||
|
||||
# Display Mapper Component
|
||||
ComponentTests("Display Mapper")
|
||||
|
||||
# Reflection Probe Component
|
||||
reflection_probe = "Reflection Probe"
|
||||
ComponentTests(
|
||||
reflection_probe,
|
||||
lambda entity_obj: verify_required_component_addition(entity_obj, ["Box Shape"], reflection_probe),
|
||||
lambda entity_obj: verify_cubemap_generation(reflection_probe, entity_obj),)
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
@@ -1,191 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
|
||||
class Tests:
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"REDO Entity creation failed")
|
||||
bloom_creation = (
|
||||
"Bloom Entity successfully created",
|
||||
"Bloom Entity failed to be created")
|
||||
bloom_component = (
|
||||
"Entity has a Bloom component",
|
||||
"Entity failed to find Bloom component")
|
||||
bloom_disabled = (
|
||||
"Bloom component disabled",
|
||||
"Bloom component was not disabled")
|
||||
postfx_layer_component = (
|
||||
"Entity has a PostFX Layer component",
|
||||
"Entity did not have an PostFX Layer component")
|
||||
bloom_enabled = (
|
||||
"Bloom component enabled",
|
||||
"Bloom component was not enabled")
|
||||
enable_bloom_parameter_enabled = (
|
||||
"Enable Bloom parameter enabled",
|
||||
"Enable Bloom parameter was not enabled")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"REDO deletion failed")
|
||||
|
||||
|
||||
def AtomEditorComponents_Bloom_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Bloom component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create an Bloom entity with no components.
|
||||
2) Add Bloom component to Bloom entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Verify Bloom component not enabled.
|
||||
6) Add PostFX Layer component since it is required by the Bloom component.
|
||||
7) Verify Bloom component is enabled.
|
||||
8) Enable the "Enable Bloom" parameter.
|
||||
9) Enter/Exit game mode.
|
||||
10) Test IsHidden.
|
||||
11) Test IsVisible.
|
||||
12) Delete Bloom entity.
|
||||
13) UNDO deletion.
|
||||
14) REDO deletion.
|
||||
15) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create an Bloom entity with no components.
|
||||
bloom_entity = EditorEntity.create_editor_entity(AtomComponentProperties.bloom())
|
||||
Report.critical_result(Tests.bloom_creation, bloom_entity.exists())
|
||||
|
||||
# 2. Add Bloom component to Bloom entity.
|
||||
bloom_component = bloom_entity.add_component(AtomComponentProperties.bloom())
|
||||
Report.critical_result(Tests.bloom_component, bloom_entity.has_component(AtomComponentProperties.bloom()))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not bloom_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, bloom_entity.exists())
|
||||
|
||||
# 5. Verify Bloom component not enabled.
|
||||
Report.result(Tests.bloom_disabled, not bloom_component.is_enabled())
|
||||
|
||||
# 6. Add PostFX Layer component since it is required by the Bloom component.
|
||||
bloom_entity.add_component(AtomComponentProperties.postfx_layer())
|
||||
Report.result(
|
||||
Tests.postfx_layer_component,
|
||||
bloom_entity.has_component(AtomComponentProperties.postfx_layer()))
|
||||
|
||||
# 7. Verify Bloom component is enabled.
|
||||
Report.result(Tests.bloom_enabled, bloom_component.is_enabled())
|
||||
|
||||
# 8. Enable the "Enable Bloom" parameter.
|
||||
bloom_component.set_component_property_value(AtomComponentProperties.bloom('Enable Bloom'), True)
|
||||
Report.result(
|
||||
Tests.enable_bloom_parameter_enabled,
|
||||
bloom_component.get_component_property_value(AtomComponentProperties.bloom('Enable Bloom')) is True)
|
||||
|
||||
# 9. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 10. Test IsHidden.
|
||||
bloom_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, bloom_entity.is_hidden() is True)
|
||||
|
||||
# 11. Test IsVisible.
|
||||
bloom_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, bloom_entity.is_visible() is True)
|
||||
|
||||
# 12. Delete Bloom entity.
|
||||
bloom_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not bloom_entity.exists())
|
||||
|
||||
# 13. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, bloom_entity.exists())
|
||||
|
||||
# 14. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not bloom_entity.exists())
|
||||
|
||||
# 15. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_Bloom_AddedToEntity)
|
||||
+56
-126
@@ -5,64 +5,25 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = (
|
||||
"Camera Entity successfully created",
|
||||
"P0: Camera Entity failed to be created")
|
||||
camera_component_added = (
|
||||
"Camera component was added to entity",
|
||||
"P0: Camera component failed to be added to entity")
|
||||
camera_component_check = (
|
||||
"Entity has a Camera component",
|
||||
"P0: Entity failed to find Camera component")
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"P0: UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"P0: REDO Entity creation failed")
|
||||
decal_creation = (
|
||||
"Decal Entity successfully created",
|
||||
"P0: Decal Entity failed to be created")
|
||||
decal_component = (
|
||||
"Entity has a Decal component",
|
||||
"P0: Entity failed to find Decal component")
|
||||
decal_component_removed = (
|
||||
"Decal component removed",
|
||||
"P0: Decal component failed to be removed")
|
||||
material_property_set = (
|
||||
"Material property set on Decal component",
|
||||
"P0: Couldn't set Material property on Decal component")
|
||||
attenuation_property_set = (
|
||||
"Attenuation Angle property set on Decal component",
|
||||
"P1: Couldn't set Attenuation Angle property on Decal component")
|
||||
opacity_property_set = (
|
||||
"Opacity property set on Decal component",
|
||||
"P1: Coudn't set Opacity property on Decal component")
|
||||
sort_key_property_set = (
|
||||
"Sort Key property set on Decal component",
|
||||
"P1: Couldn't set Sort Key property on Decal component")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"P0: Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"P0: Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"P0: Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"P0: Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"P0: Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"P0: UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"P0: REDO deletion failed")
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
decal_creation = ("Decal Entity successfully created", "Decal Entity failed to be created")
|
||||
decal_component = ("Entity has a Decal component", "Entity failed to find Decal component")
|
||||
material_property_set = ("Material property set on Decal component", "Couldn't set Material property on Decal component")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_Decal_AddedToEntity():
|
||||
@@ -83,44 +44,42 @@ def AtomEditorComponents_Decal_AddedToEntity():
|
||||
2) Add Decal component to Decal entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Set Material property on Decal component.
|
||||
6) Set Attenuation Angle property on Decal component.
|
||||
7) Set Opacity property on Decal component
|
||||
8) Set Sort Key property on Decal Component
|
||||
9) Remove Decal component then UNDO the remove
|
||||
10) Enter/Exit game mode.
|
||||
11) Test IsHidden.
|
||||
12) Test IsVisible.
|
||||
13) Delete Decal entity.
|
||||
14) UNDO deletion.
|
||||
15) REDO deletion.
|
||||
16) Look for errors and asserts.
|
||||
5) Enter/Exit game mode.
|
||||
6) Test IsHidden.
|
||||
7) Test IsVisible.
|
||||
8) Set Material property on Decal component.
|
||||
9) Delete Decal entity.
|
||||
10) UNDO deletion.
|
||||
11) REDO deletion.
|
||||
12) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.asset_utils import Asset
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Decal entity with no components.
|
||||
decal_entity = EditorEntity.create_editor_entity(AtomComponentProperties.decal())
|
||||
decal_name = "Decal"
|
||||
decal_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), decal_name)
|
||||
Report.critical_result(Tests.decal_creation, decal_entity.exists())
|
||||
|
||||
# 2. Add Decal component to Decal entity.
|
||||
decal_component = decal_entity.add_component(AtomComponentProperties.decal())
|
||||
Report.critical_result(Tests.decal_component, decal_entity.has_component(AtomComponentProperties.decal()))
|
||||
decal_component = decal_entity.add_component(decal_name)
|
||||
Report.critical_result(Tests.decal_component, decal_entity.has_component(decal_name))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
@@ -146,74 +105,45 @@ def AtomEditorComponents_Decal_AddedToEntity():
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, decal_entity.exists())
|
||||
|
||||
# 5. Set Material property on Decal component.
|
||||
decal_material_asset_path = os.path.join("materials", "decal", "airship_symbol_decal.azmaterial")
|
||||
decal_material_asset = Asset.find_asset_by_path(decal_material_asset_path, False)
|
||||
decal_component.set_component_property_value(AtomComponentProperties.decal('Material'), decal_material_asset.id)
|
||||
get_material_property = decal_component.get_component_property_value(AtomComponentProperties.decal('Material'))
|
||||
Report.result(Tests.material_property_set, get_material_property == decal_material_asset.id)
|
||||
|
||||
# 6. Set Attenuation Angle property on Decal component
|
||||
decal_component.set_component_property_value(AtomComponentProperties.decal('Attenuation Angle'), value=0.75)
|
||||
get_attenuation_property = decal_component.get_component_property_value(
|
||||
AtomComponentProperties.decal('Attenuation Angle'))
|
||||
Report.result(Tests.attenuation_property_set, get_attenuation_property == 0.75)
|
||||
|
||||
# 7. Set Opacity property on Decal component
|
||||
decal_component.set_component_property_value(AtomComponentProperties.decal('Opacity'), value=0.5)
|
||||
get_opacity_property = decal_component.get_component_property_value(AtomComponentProperties.decal('Opacity'))
|
||||
Report.result(Tests.opacity_property_set, get_opacity_property == 0.5)
|
||||
|
||||
# 8. Set Sort Key property on Decal component
|
||||
decal_component.set_component_property_value(AtomComponentProperties.decal('Sort Key'), value=255.0)
|
||||
get_sort_key_property = decal_component.get_component_property_value(AtomComponentProperties.decal('Sort Key'))
|
||||
Report.result(Tests.sort_key_property_set, get_sort_key_property == 255.0)
|
||||
decal_component.set_component_property_value(AtomComponentProperties.decal('Sort Key'), value=0)
|
||||
get_sort_key_property = decal_component.get_component_property_value(AtomComponentProperties.decal('Sort Key'))
|
||||
Report.result(Tests.sort_key_property_set, get_sort_key_property == 0)
|
||||
|
||||
# 9. Remove Decal component then UNDO the remove
|
||||
decal_component.remove()
|
||||
# 5. Enter/Exit game mode.
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.decal_component_removed, not decal_entity.has_component(AtomComponentProperties.decal()))
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.decal_component, decal_entity.has_component(AtomComponentProperties.decal()))
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 10. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 11. Test IsHidden.
|
||||
# 6. Test IsHidden.
|
||||
decal_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, decal_entity.is_hidden() is True)
|
||||
|
||||
# 12. Test IsVisible.
|
||||
# 7. Test IsVisible.
|
||||
decal_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, decal_entity.is_visible() is True)
|
||||
|
||||
# 13. Delete Decal entity.
|
||||
# 8. Set Material property on Decal component.
|
||||
decal_material_property_path = "Controller|Configuration|Material"
|
||||
decal_material_asset_path = os.path.join("AutomatedTesting", "Materials", "basic_grey.material")
|
||||
decal_material_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", decal_material_asset_path, math.Uuid(), False)
|
||||
decal_component.set_component_property_value(decal_material_property_path, decal_material_asset)
|
||||
get_material_property = decal_component.get_component_property_value(decal_material_property_path)
|
||||
Report.result(Tests.material_property_set, get_material_property == decal_material_asset)
|
||||
|
||||
# 9. Delete Decal entity.
|
||||
decal_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not decal_entity.exists())
|
||||
|
||||
# 14. UNDO deletion.
|
||||
# 10. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, decal_entity.exists())
|
||||
|
||||
# 15. REDO deletion.
|
||||
# 11. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not decal_entity.exists())
|
||||
|
||||
# 16. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
# 12. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
-195
@@ -1,195 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
|
||||
class Tests:
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"REDO Entity creation failed")
|
||||
deferred_fog_creation = (
|
||||
"Deferred Fog Entity successfully created",
|
||||
"Deferred Fog Entity failed to be created")
|
||||
deferred_fog_component = (
|
||||
"Entity has a Deferred Fog component",
|
||||
"Entity failed to find Deferred Fog component")
|
||||
deferred_fog_disabled = (
|
||||
"Deferred Fog component disabled",
|
||||
"Deferred Fog component was not disabled")
|
||||
postfx_layer_component = (
|
||||
"Entity has a PostFX Layer component",
|
||||
"Entity did not have an PostFX Layer component")
|
||||
deferred_fog_enabled = (
|
||||
"Deferred Fog component enabled",
|
||||
"Deferred Fog component was not enabled")
|
||||
enable_deferred_fog_parameter_enabled = (
|
||||
"Enable Deferred Fog parameter enabled",
|
||||
"Enable Deferred Fog parameter was not enabled")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"REDO deletion failed")
|
||||
|
||||
|
||||
def AtomEditorComponents_DeferredFog_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Deferred Fog component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create an Deferred Fog entity with no components.
|
||||
2) Add Deferred Fog component to Deferred Fog entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Verify Deferred Fog component not enabled.
|
||||
6) Add PostFX Layer component since it is required by the Deferred Fog component.
|
||||
7) Verify Deferred Fog component is enabled.
|
||||
8) Enable the "Enable Deferred Fog" parameter.
|
||||
9) Enter/Exit game mode.
|
||||
10) Test IsHidden.
|
||||
11) Test IsVisible.
|
||||
12) Delete Deferred Fog entity.
|
||||
13) UNDO deletion.
|
||||
14) REDO deletion.
|
||||
15) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create an Deferred Fog entity with no components.
|
||||
deferred_fog_entity = EditorEntity.create_editor_entity(AtomComponentProperties.deferred_fog())
|
||||
Report.critical_result(Tests.deferred_fog_creation, deferred_fog_entity.exists())
|
||||
|
||||
# 2. Add Deferred Fog component to Deferred Fog entity.
|
||||
deferred_fog_component = deferred_fog_entity.add_component(
|
||||
AtomComponentProperties.deferred_fog())
|
||||
Report.critical_result(
|
||||
Tests.deferred_fog_component,
|
||||
deferred_fog_entity.has_component(AtomComponentProperties.deferred_fog()))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not deferred_fog_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, deferred_fog_entity.exists())
|
||||
|
||||
# 5. Verify Deferred Fog component not enabled.
|
||||
Report.result(Tests.deferred_fog_disabled, not deferred_fog_component.is_enabled())
|
||||
|
||||
# 6. Add PostFX Layer component since it is required by the Deferred Fog component.
|
||||
deferred_fog_entity.add_component(AtomComponentProperties.postfx_layer())
|
||||
Report.result(
|
||||
Tests.postfx_layer_component,
|
||||
deferred_fog_entity.has_component(AtomComponentProperties.postfx_layer()))
|
||||
|
||||
# 7. Verify Deferred Fog component is enabled.
|
||||
Report.result(Tests.deferred_fog_enabled, deferred_fog_component.is_enabled())
|
||||
|
||||
# 8. Enable the "Enable Deferred Fog" parameter.
|
||||
deferred_fog_component.set_component_property_value(
|
||||
AtomComponentProperties.deferred_fog('Enable Deferred Fog'), True)
|
||||
Report.result(Tests.enable_deferred_fog_parameter_enabled,
|
||||
deferred_fog_component.get_component_property_value(
|
||||
AtomComponentProperties.deferred_fog('Enable Deferred Fog')) is True)
|
||||
|
||||
# 9. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 10. Test IsHidden.
|
||||
deferred_fog_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, deferred_fog_entity.is_hidden() is True)
|
||||
|
||||
# 11. Test IsVisible.
|
||||
deferred_fog_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, deferred_fog_entity.is_visible() is True)
|
||||
|
||||
# 12. Delete Deferred Fog entity.
|
||||
deferred_fog_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not deferred_fog_entity.exists())
|
||||
|
||||
# 13. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, deferred_fog_entity.exists())
|
||||
|
||||
# 14. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not deferred_fog_entity.exists())
|
||||
|
||||
# 15. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_DeferredFog_AddedToEntity)
|
||||
+47
-84
@@ -5,61 +5,28 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = (
|
||||
"Camera Entity successfully created",
|
||||
"Camera Entity failed to be created")
|
||||
camera_component_added = (
|
||||
"Camera component was added to Camera entity",
|
||||
"Camera component failed to be added to entity")
|
||||
camera_component_check = (
|
||||
"Entity has a Camera component",
|
||||
"Entity failed to find Camera component")
|
||||
camera_property_set = (
|
||||
"DepthOfField Entity set Camera Entity",
|
||||
"DepthOfField Entity could not set Camera Entity")
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"REDO Entity creation failed")
|
||||
depth_of_field_creation = (
|
||||
"DepthOfField Entity successfully created",
|
||||
"DepthOfField Entity failed to be created")
|
||||
depth_of_field_component = (
|
||||
"Entity has a DepthOfField component",
|
||||
"Entity failed to find DepthOfField component")
|
||||
depth_of_field_disabled = (
|
||||
"DepthOfField component disabled",
|
||||
"DepthOfField component was not disabled.")
|
||||
post_fx_component = (
|
||||
"Entity has a Post FX Layer component",
|
||||
"Entity did not have a Post FX Layer component")
|
||||
depth_of_field_enabled = (
|
||||
"DepthOfField component enabled",
|
||||
"DepthOfField component was not enabled.")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"REDO deletion failed")
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to Camera entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
camera_property_set = ("DepthOfField Entity set Camera Entity", "DepthOfField Entity could not set Camera Entity")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
depth_of_field_creation = ("DepthOfField Entity successfully created", "DepthOfField Entity failed to be created")
|
||||
depth_of_field_component = ("Entity has a DepthOfField component", "Entity failed to find DepthOfField component")
|
||||
depth_of_field_disabled = ("DepthOfField component disabled", "DepthOfField component was not disabled.")
|
||||
post_fx_component = ("Entity has a Post FX Layer component", "Entity did not have a Post FX Layer component")
|
||||
depth_of_field_enabled = ("DepthOfField component enabled", "DepthOfField component was not enabled.")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_DepthOfField_AddedToEntity():
|
||||
@@ -92,32 +59,33 @@ def AtomEditorComponents_DepthOfField_AddedToEntity():
|
||||
14) Delete DepthOfField entity.
|
||||
15) UNDO deletion.
|
||||
16) REDO deletion.
|
||||
17) Look for errors and asserts.
|
||||
17) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a DepthOfField entity with no components.
|
||||
depth_of_field_entity = EditorEntity.create_editor_entity(AtomComponentProperties.depth_of_field())
|
||||
depth_of_field_name = "DepthOfField"
|
||||
depth_of_field_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(512.0, 512.0, 34.0), depth_of_field_name)
|
||||
Report.critical_result(Tests.depth_of_field_creation, depth_of_field_entity.exists())
|
||||
|
||||
# 2. Add a DepthOfField component to DepthOfField entity.
|
||||
depth_of_field_component = depth_of_field_entity.add_component(AtomComponentProperties.depth_of_field())
|
||||
Report.critical_result(Tests.depth_of_field_component,
|
||||
depth_of_field_entity.has_component(AtomComponentProperties.depth_of_field()))
|
||||
depth_of_field_component = depth_of_field_entity.add_component(depth_of_field_name)
|
||||
Report.critical_result(Tests.depth_of_field_component, depth_of_field_entity.has_component(depth_of_field_name))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
@@ -147,16 +115,17 @@ def AtomEditorComponents_DepthOfField_AddedToEntity():
|
||||
Report.result(Tests.depth_of_field_disabled, not depth_of_field_component.is_enabled())
|
||||
|
||||
# 6. Add Post FX Layer component since it is required by the DepthOfField component.
|
||||
depth_of_field_entity.add_component(AtomComponentProperties.postfx_layer())
|
||||
Report.result(Tests.post_fx_component, depth_of_field_entity.has_component(AtomComponentProperties.postfx_layer()))
|
||||
post_fx_layer = "PostFX Layer"
|
||||
depth_of_field_entity.add_component(post_fx_layer)
|
||||
Report.result(Tests.post_fx_component, depth_of_field_entity.has_component(post_fx_layer))
|
||||
|
||||
# 7. Verify DepthOfField component is enabled.
|
||||
Report.result(Tests.depth_of_field_enabled, depth_of_field_component.is_enabled())
|
||||
|
||||
# 8. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 9. Test IsHidden.
|
||||
depth_of_field_entity.set_visibility_state(False)
|
||||
@@ -168,20 +137,19 @@ def AtomEditorComponents_DepthOfField_AddedToEntity():
|
||||
Report.result(Tests.is_visible, depth_of_field_entity.is_visible() is True)
|
||||
|
||||
# 11. Add Camera entity.
|
||||
camera_entity = EditorEntity.create_editor_entity(AtomComponentProperties.camera())
|
||||
camera_name = "Camera"
|
||||
camera_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), camera_name)
|
||||
Report.result(Tests.camera_creation, camera_entity.exists())
|
||||
|
||||
# 12. Add Camera component to Camera entity.
|
||||
camera_entity.add_component(AtomComponentProperties.camera())
|
||||
Report.result(Tests.camera_component_added, camera_entity.has_component(AtomComponentProperties.camera()))
|
||||
camera_entity.add_component(camera_name)
|
||||
Report.result(Tests.camera_component_added, camera_entity.has_component(camera_name))
|
||||
|
||||
# 13. Set the DepthOfField components's Camera Entity to the newly created Camera entity.
|
||||
depth_of_field_component.set_component_property_value(
|
||||
AtomComponentProperties.depth_of_field('Camera Entity'), camera_entity.id)
|
||||
Report.result(
|
||||
Tests.camera_property_set,
|
||||
camera_entity.id == depth_of_field_component.get_component_property_value(
|
||||
AtomComponentProperties.depth_of_field('Camera Entity')))
|
||||
depth_of_field_camera_property_path = "Controller|Configuration|Camera Entity"
|
||||
depth_of_field_component.set_component_property_value(depth_of_field_camera_property_path, camera_entity.id)
|
||||
camera_entity_set = depth_of_field_component.get_component_property_value(depth_of_field_camera_property_path)
|
||||
Report.result(Tests.camera_property_set, camera_entity.id == camera_entity_set)
|
||||
|
||||
# 14. Delete DepthOfField entity.
|
||||
depth_of_field_entity.delete()
|
||||
@@ -189,20 +157,15 @@ def AtomEditorComponents_DepthOfField_AddedToEntity():
|
||||
|
||||
# 15. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, depth_of_field_entity.exists())
|
||||
|
||||
# 16. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not depth_of_field_entity.exists())
|
||||
|
||||
# 17. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
# 17. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
-189
@@ -1,189 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
|
||||
class Tests:
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"REDO Entity creation failed")
|
||||
diffuse_probe_grid_creation = (
|
||||
"Diffuse Probe Grid Entity successfully created",
|
||||
"Diffuse Probe Grid Entity failed to be created")
|
||||
diffuse_probe_grid_component = (
|
||||
"Entity has a Diffuse Probe Grid component",
|
||||
"Entity failed to find Diffuse Probe Grid component")
|
||||
diffuse_probe_grid_disabled = (
|
||||
"Diffuse Probe Grid component disabled",
|
||||
"Diffuse Probe Grid component was not disabled")
|
||||
diffuse_probe_grid_enabled = (
|
||||
"Diffuse Probe Grid component enabled",
|
||||
"Diffuse Probe Grid component was not enabled")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"REDO deletion failed")
|
||||
|
||||
|
||||
def AtomEditorComponents_DiffuseProbeGrid_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Diffuse Probe Grid component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create a Diffuse Probe Grid entity with no components.
|
||||
2) Add a Diffuse Probe Grid component to Diffuse Probe Grid entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Verify Diffuse Probe Grid component not enabled.
|
||||
6) Add Shape component since it is required by the Diffuse Probe Grid component.
|
||||
7) Verify Diffuse Probe Grid component is enabled.
|
||||
8) Enter/Exit game mode.
|
||||
9) Test IsHidden.
|
||||
10) Test IsVisible.
|
||||
11) Delete Diffuse Probe Grid entity.
|
||||
12) UNDO deletion.
|
||||
13) REDO deletion.
|
||||
14) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Diffuse Probe Grid entity with no components.
|
||||
diffuse_probe_grid_entity = EditorEntity.create_editor_entity(AtomComponentProperties.diffuse_probe_grid())
|
||||
Report.critical_result(Tests.diffuse_probe_grid_creation, diffuse_probe_grid_entity.exists())
|
||||
|
||||
# 2. Add a Diffuse Probe Grid component to Diffuse Probe Grid entity.
|
||||
diffuse_probe_grid_component = diffuse_probe_grid_entity.add_component(
|
||||
AtomComponentProperties.diffuse_probe_grid())
|
||||
Report.critical_result(
|
||||
Tests.diffuse_probe_grid_component,
|
||||
diffuse_probe_grid_entity.has_component(AtomComponentProperties.diffuse_probe_grid()))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not diffuse_probe_grid_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, diffuse_probe_grid_entity.exists())
|
||||
|
||||
# 5. Verify Diffuse Probe Grid component not enabled.
|
||||
Report.result(Tests.diffuse_probe_grid_disabled, not diffuse_probe_grid_component.is_enabled())
|
||||
|
||||
# 6. Add Shape component since it is required by the Diffuse Probe Grid component.
|
||||
for shape in AtomComponentProperties.diffuse_probe_grid('shapes'):
|
||||
diffuse_probe_grid_entity.add_component(shape)
|
||||
test_shape = (
|
||||
f"Entity has a {shape} component",
|
||||
f"Entity did not have a {shape} component")
|
||||
Report.result(test_shape, diffuse_probe_grid_entity.has_component(shape))
|
||||
|
||||
# 7. Check if required shape allows Diffuse Probe Grid to be enabled
|
||||
Report.result(Tests.diffuse_probe_grid_enabled, diffuse_probe_grid_component.is_enabled())
|
||||
|
||||
# Undo to remove each added shape except the last one and verify Diffuse Probe Grid is not enabled.
|
||||
if not (shape == AtomComponentProperties.diffuse_probe_grid('shapes')[-1]):
|
||||
general.undo()
|
||||
TestHelper.wait_for_condition(lambda: not diffuse_probe_grid_entity.has_component(shape), 1.0)
|
||||
Report.result(Tests.diffuse_probe_grid_disabled, not diffuse_probe_grid_component.is_enabled())
|
||||
|
||||
# 8. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 9. Test IsHidden.
|
||||
diffuse_probe_grid_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, diffuse_probe_grid_entity.is_hidden() is True)
|
||||
|
||||
# 10. Test IsVisible.
|
||||
diffuse_probe_grid_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, diffuse_probe_grid_entity.is_visible() is True)
|
||||
|
||||
# 11. Delete Diffuse Probe Grid entity.
|
||||
diffuse_probe_grid_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not diffuse_probe_grid_entity.exists())
|
||||
|
||||
# 12. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, diffuse_probe_grid_entity.exists())
|
||||
|
||||
# 13. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not diffuse_probe_grid_entity.exists())
|
||||
|
||||
# 14. Look for errors or asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_DiffuseProbeGrid_AddedToEntity)
|
||||
+41
-73
@@ -5,52 +5,25 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = (
|
||||
"Camera Entity successfully created",
|
||||
"Camera Entity failed to be created")
|
||||
camera_component_added = (
|
||||
"Camera component was added to entity",
|
||||
"Camera component failed to be added to entity")
|
||||
camera_component_check = (
|
||||
"Entity has a Camera component",
|
||||
"Entity failed to find Camera component")
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"REDO Entity creation failed")
|
||||
directional_light_creation = (
|
||||
"Directional Light Entity successfully created",
|
||||
"Directional Light Entity failed to be created")
|
||||
directional_light_component = (
|
||||
"Entity has a Directional Light component",
|
||||
"Entity failed to find Directional Light component")
|
||||
shadow_camera_check = (
|
||||
"Directional Light component Shadow camera set",
|
||||
"Directional Light component Shadow camera was not set")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"REDO deletion failed")
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
directional_light_creation = ("Directional Light Entity successfully created", "Directional Light Entity failed to be created")
|
||||
directional_light_component = ("Entity has a Directional Light component", "Entity failed to find Directional Light component")
|
||||
shadow_camera_check = ("Directional Light component Shadow camera set", "Directional Light component Shadow camera was not set")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_DirectionalLight_AddedToEntity():
|
||||
@@ -80,33 +53,34 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity():
|
||||
11) Delete Directional Light entity.
|
||||
12) UNDO deletion.
|
||||
13) REDO deletion.
|
||||
14) Look for errors and asserts.
|
||||
14) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Directional Light entity with no components.
|
||||
directional_light_entity = EditorEntity.create_editor_entity(AtomComponentProperties.directional_light())
|
||||
directional_light_name = "Directional Light"
|
||||
directional_light_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(512.0, 512.0, 34.0), directional_light_name)
|
||||
Report.critical_result(Tests.directional_light_creation, directional_light_entity.exists())
|
||||
|
||||
# 2. Add Directional Light component to Directional Light entity.
|
||||
directional_light_component = directional_light_entity.add_component(AtomComponentProperties.directional_light())
|
||||
directional_light_component = directional_light_entity.add_component(directional_light_name)
|
||||
Report.critical_result(
|
||||
Tests.directional_light_component,
|
||||
directional_light_entity.has_component(AtomComponentProperties.directional_light()))
|
||||
Tests.directional_light_component, directional_light_entity.has_component(directional_light_name))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
@@ -133,9 +107,9 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity():
|
||||
Report.result(Tests.creation_redo, directional_light_entity.exists())
|
||||
|
||||
# 5. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 6. Test IsHidden.
|
||||
directional_light_entity.set_visibility_state(False)
|
||||
@@ -147,20 +121,19 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity():
|
||||
Report.result(Tests.is_visible, directional_light_entity.is_visible() is True)
|
||||
|
||||
# 8. Add Camera entity.
|
||||
camera_entity = EditorEntity.create_editor_entity(AtomComponentProperties.camera())
|
||||
camera_name = "Camera"
|
||||
camera_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), camera_name)
|
||||
Report.result(Tests.camera_creation, camera_entity.exists())
|
||||
|
||||
# 9. Add Camera component to Camera entity.
|
||||
camera_entity.add_component(AtomComponentProperties.camera())
|
||||
Report.result(Tests.camera_component_added, camera_entity.has_component(AtomComponentProperties.camera()))
|
||||
camera_entity.add_component(camera_name)
|
||||
Report.result(Tests.camera_component_added, camera_entity.has_component(camera_name))
|
||||
|
||||
# 10. Set the Directional Light component property Shadow|Camera to the Camera entity.
|
||||
directional_light_component.set_component_property_value(
|
||||
AtomComponentProperties.directional_light('Camera'), camera_entity.id)
|
||||
Report.result(
|
||||
Tests.shadow_camera_check,
|
||||
camera_entity.id == directional_light_component.get_component_property_value(
|
||||
AtomComponentProperties.directional_light('Camera')))
|
||||
shadow_camera_property_path = "Controller|Configuration|Shadow|Camera"
|
||||
directional_light_component.set_component_property_value(shadow_camera_property_path, camera_entity.id)
|
||||
shadow_camera_set = directional_light_component.get_component_property_value(shadow_camera_property_path)
|
||||
Report.result(Tests.shadow_camera_check, camera_entity.id == shadow_camera_set)
|
||||
|
||||
# 11. Delete DirectionalLight entity.
|
||||
directional_light_entity.delete()
|
||||
@@ -168,20 +141,15 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity():
|
||||
|
||||
# 12. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, directional_light_entity.exists())
|
||||
|
||||
# 13. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not directional_light_entity.exists())
|
||||
|
||||
# 14. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
# 14. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+44
-94
@@ -5,47 +5,24 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"REDO Entity creation failed")
|
||||
display_mapper_creation = (
|
||||
"Display Mapper Entity successfully created",
|
||||
"Display Mapper Entity failed to be created")
|
||||
display_mapper_component = (
|
||||
"Entity has a Display Mapper component",
|
||||
"Entity failed to find Display Mapper component")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"Entity was not hidden")
|
||||
ldr_color_grading_lut = (
|
||||
"LDR color Grading LUT asset set",
|
||||
"LDR color Grading LUT asset could not be set")
|
||||
enable_ldr_color_grading_lut = (
|
||||
"Enable LDR color grading LUT set",
|
||||
"Enable LDR color grading LUT could not be set")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"REDO deletion failed")
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
display_mapper_creation = ("Display Mapper Entity successfully created", "Display Mapper Entity failed to be created")
|
||||
display_mapper_component = ("Entity has a Display Mapper component", "Entity failed to find Display Mapper component")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_DisplayMapper_AddedToEntity():
|
||||
@@ -66,43 +43,39 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity():
|
||||
2) Add Display Mapper component to Display Mapper entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Set LDR color Grading LUT asset.
|
||||
6) Set Enable LDR color grading LUT property True
|
||||
7) Enter/Exit game mode.
|
||||
8) Test IsHidden.
|
||||
9) Test IsVisible.
|
||||
10) Delete Display Mapper entity.
|
||||
11) UNDO deletion.
|
||||
12) REDO deletion.
|
||||
13) Look for errors and asserts.
|
||||
5) Enter/Exit game mode.
|
||||
6) Test IsHidden.
|
||||
7) Test IsVisible.
|
||||
8) Delete Display Mapper entity.
|
||||
9) UNDO deletion.
|
||||
10) REDO deletion.
|
||||
11) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.asset_utils import Asset
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Display Mapper entity with no components.
|
||||
display_mapper_entity = EditorEntity.create_editor_entity(AtomComponentProperties.display_mapper())
|
||||
display_mapper = "Display Mapper"
|
||||
display_mapper_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(512.0, 512.0, 34.0), f"{display_mapper}")
|
||||
Report.critical_result(Tests.display_mapper_creation, display_mapper_entity.exists())
|
||||
|
||||
# 2. Add Display Mapper component to Display Mapper entity.
|
||||
display_mapper_component = display_mapper_entity.add_component(AtomComponentProperties.display_mapper())
|
||||
Report.critical_result(
|
||||
Tests.display_mapper_component,
|
||||
display_mapper_entity.has_component(AtomComponentProperties.display_mapper()))
|
||||
display_mapper_entity.add_component(display_mapper)
|
||||
Report.critical_result(Tests.display_mapper_component, display_mapper_entity.has_component(display_mapper))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
@@ -128,58 +101,35 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity():
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, display_mapper_entity.exists())
|
||||
|
||||
# 5. Set LDR color Grading LUT asset.
|
||||
display_mapper_asset_path = os.path.join("TestData", "test.lightingpreset.azasset")
|
||||
display_mapper_asset = Asset.find_asset_by_path(display_mapper_asset_path, False)
|
||||
display_mapper_component.set_component_property_value(
|
||||
AtomComponentProperties.display_mapper("LDR color Grading LUT"), display_mapper_asset.id)
|
||||
Report.result(
|
||||
Tests.ldr_color_grading_lut,
|
||||
display_mapper_component.get_component_property_value(
|
||||
AtomComponentProperties.display_mapper("LDR color Grading LUT")) == display_mapper_asset.id)
|
||||
|
||||
# 6. Set Enable LDR color grading LUT property True
|
||||
display_mapper_component.set_component_property_value(
|
||||
AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True)
|
||||
Report.result(
|
||||
Tests.enable_ldr_color_grading_lut,
|
||||
display_mapper_component.get_component_property_value(
|
||||
AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True)
|
||||
|
||||
# 7. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
# 5. Enter/Exit game mode.
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 8. Test IsHidden.
|
||||
# 6. Test IsHidden.
|
||||
display_mapper_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, display_mapper_entity.is_hidden() is True)
|
||||
|
||||
# 9. Test IsVisible.
|
||||
# 7. Test IsVisible.
|
||||
display_mapper_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, display_mapper_entity.is_visible() is True)
|
||||
|
||||
# 10. Delete Display Mapper entity.
|
||||
# 8. Delete Display Mapper entity.
|
||||
display_mapper_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not display_mapper_entity.exists())
|
||||
|
||||
# 11. UNDO deletion.
|
||||
# 9. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, display_mapper_entity.exists())
|
||||
|
||||
# 12. REDO deletion.
|
||||
# 10. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not display_mapper_entity.exists())
|
||||
|
||||
# 13. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
# 11. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
-261
@@ -1,261 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
|
||||
class Tests:
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"P0: UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"P0: REDO Entity creation failed")
|
||||
entity_reference_creation = (
|
||||
"Entity Reference Entity successfully created",
|
||||
"P0: Entity Reference Entity failed to be created")
|
||||
entity_reference_component = (
|
||||
"Entity has an Entity Reference component",
|
||||
"P0: Entity failed to find Entity Reference component")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"P0: Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"P0: Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"P0: Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"P0: Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"P0: Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"P0: UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"P0: REDO deletion failed")
|
||||
entity_id_references_is_container = (
|
||||
"EntityIdReferences is a container property",
|
||||
"P1: EntityIdReferences is NOT a container property")
|
||||
container_append = (
|
||||
"EntityIdReferences append succeeded",
|
||||
"P1: EntityIdReferences append did not succeed")
|
||||
container_add = (
|
||||
"EntityIdReferences add succeeded",
|
||||
"P1: EntityIdReferences add did not succeed")
|
||||
container_update = (
|
||||
"EntityIdReferences update succeeded",
|
||||
"P1: EntityIdReferences update did not succeed")
|
||||
container_remove = (
|
||||
"EntityIdReferences remove succeeded",
|
||||
"P1: EntityIdReferences remove did not succeed")
|
||||
container_reset = (
|
||||
"EntityIdReferences reset succeeded",
|
||||
"P1: EntityIdReferences reset did not succeed")
|
||||
entity_reference_component_removed = (
|
||||
"Entity Reference component removed from entity",
|
||||
"P1: Entity Reference component NOT removed from entity")
|
||||
|
||||
|
||||
def AtomEditorComponents_EntityReference_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Entity Reference component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create an Entity Reference entity with no components.
|
||||
2) Add Entity Reference component to Entity Reference entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) 'EntityIdReferences' is a container property
|
||||
6) Append item to 'EntityIdReferences'
|
||||
7) Add item to 'EntityIdReferences'
|
||||
8) Update item in 'EntityIdReferences'
|
||||
9) Remove item from 'EntityIdReferences'
|
||||
10) Reset the container property then put one entity reference back for further tests
|
||||
11) Remove component
|
||||
12) UNDO component remove
|
||||
13) Enter/Exit game mode.
|
||||
14) Test IsHidden.
|
||||
15) Test IsVisible.
|
||||
16) Delete Entity Reference entity.
|
||||
17) UNDO deletion.
|
||||
18) REDO deletion.
|
||||
19) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create an Entity Reference entity with no components.
|
||||
entity_reference_entity = EditorEntity.create_editor_entity(AtomComponentProperties.entity_reference())
|
||||
Report.critical_result(Tests.entity_reference_creation, entity_reference_entity.exists())
|
||||
|
||||
# 2. Add Entity Reference component to Entity Reference entity.
|
||||
entity_reference_component = entity_reference_entity.add_component(
|
||||
AtomComponentProperties.entity_reference())
|
||||
Report.critical_result(
|
||||
Tests.entity_reference_component,
|
||||
entity_reference_entity.has_component(AtomComponentProperties.entity_reference()))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not entity_reference_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, entity_reference_entity.exists())
|
||||
|
||||
# Entities for EntityIdReferences tests
|
||||
test_1 = EditorEntity.create_editor_entity('test_1')
|
||||
test_2 = EditorEntity.create_editor_entity('test_2')
|
||||
test_3 = EditorEntity.create_editor_entity('test_3')
|
||||
|
||||
# 5. 'EntityIdReferences' is a container property
|
||||
Report.result(
|
||||
Tests.entity_id_references_is_container,
|
||||
entity_reference_component.is_property_container(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences')))
|
||||
|
||||
# 6. Append item to 'EntityIdReferences'
|
||||
entity_reference_component.append_container_item(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences'), test_1.id)
|
||||
Report.result(
|
||||
Tests.container_append,
|
||||
entity_reference_component.get_container_item(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences'), 0) == test_1.id)
|
||||
|
||||
# 7. Add item to 'EntityIdReferences'
|
||||
entity_reference_component.add_container_item(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences'), 1, test_1.id)
|
||||
Report.result(
|
||||
Tests.container_add,
|
||||
entity_reference_component.get_container_count(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences')) == 2)
|
||||
|
||||
# 8. Update item in 'EntityIdReferences'
|
||||
entity_reference_component.update_container_item(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences'), 1, test_2.id)
|
||||
Report.result(
|
||||
Tests.container_update,
|
||||
entity_reference_component.get_container_item(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_2.id)
|
||||
|
||||
# 9. Remove item from 'EntityIdReferences'
|
||||
entity_reference_component.append_container_item(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences'), test_3.id)
|
||||
count_before = entity_reference_component.get_container_count(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences'))
|
||||
entity_reference_component.remove_container_item(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences'), 1)
|
||||
count_after = entity_reference_component.get_container_count(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences'))
|
||||
Report.result(
|
||||
Tests.container_remove,
|
||||
((count_before == 3) and (count_after == 2) and
|
||||
(entity_reference_component.get_container_item(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_3.id)))
|
||||
|
||||
# 10. Reset the container property then put one entity reference back for further tests
|
||||
entity_reference_component.reset_container(AtomComponentProperties.entity_reference('EntityIdReferences'))
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(
|
||||
Tests.container_reset,
|
||||
entity_reference_component.get_container_count(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences')) == 0)
|
||||
entity_reference_component.append_container_item(
|
||||
AtomComponentProperties.entity_reference('EntityIdReferences'), test_1.id)
|
||||
|
||||
# 11. Remove component
|
||||
entity_reference_entity.remove_component(AtomComponentProperties.entity_reference())
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.entity_reference_component_removed, not entity_reference_entity.has_component(
|
||||
AtomComponentProperties.entity_reference()))
|
||||
|
||||
# 12. UNDO component remove
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.entity_reference_component, entity_reference_entity.has_component(
|
||||
AtomComponentProperties.entity_reference()))
|
||||
|
||||
# 13. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 14. Test IsHidden.
|
||||
entity_reference_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, entity_reference_entity.is_hidden() is True)
|
||||
|
||||
# 15. Test IsVisible.
|
||||
entity_reference_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, entity_reference_entity.is_visible() is True)
|
||||
|
||||
# 16. Delete Entity Reference entity.
|
||||
entity_reference_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not entity_reference_entity.exists())
|
||||
|
||||
# 17. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, entity_reference_entity.exists())
|
||||
|
||||
# 18. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not entity_reference_entity.exists())
|
||||
|
||||
# 19. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_EntityReference_AddedToEntity)
|
||||
+51
-96
@@ -5,58 +5,25 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = (
|
||||
"Camera Entity successfully created",
|
||||
"Camera Entity failed to be created")
|
||||
camera_component_added = (
|
||||
"Camera component was added to entity",
|
||||
"Camera component failed to be added to entity")
|
||||
camera_component_check = (
|
||||
"Entity has a Camera component",
|
||||
"Entity failed to find Camera component")
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"REDO Entity creation failed")
|
||||
exposure_control_creation = (
|
||||
"ExposureControl Entity successfully created",
|
||||
"ExposureControl Entity failed to be created")
|
||||
exposure_control_component = (
|
||||
"Entity has a Exposure Control component",
|
||||
"Entity failed to find Exposure Control component")
|
||||
exposure_control_disabled = (
|
||||
"DepthOfField component disabled",
|
||||
"DepthOfField component was not disabled.")
|
||||
post_fx_component = (
|
||||
"Entity has a Post FX Layer component",
|
||||
"Entity did not have a Post FX Layer component")
|
||||
exposure_control_enabled = (
|
||||
"DepthOfField component enabled",
|
||||
"DepthOfField component was not enabled.")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"REDO deletion failed")
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
exposure_control_creation = ("ExposureControl Entity successfully created", "ExposureControl Entity failed to be created")
|
||||
exposure_control_component = ("Entity has a Exposure Control component", "Entity failed to find Exposure Control component")
|
||||
post_fx_component = ("Entity has a Post FX Layer component", "Entity did not have a Post FX Layer component")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_ExposureControl_AddedToEntity():
|
||||
@@ -77,42 +44,41 @@ def AtomEditorComponents_ExposureControl_AddedToEntity():
|
||||
2) Add Exposure Control component to Exposure Control entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Verify Exposure Control component not enabled.
|
||||
6) Add Post FX Layer component since it is required by the Exposure Control component.
|
||||
7) Verify Exposure Control component is enabled.
|
||||
8) Enter/Exit game mode.
|
||||
9) Test IsHidden.
|
||||
10) Test IsVisible.
|
||||
11) Delete Exposure Control entity.
|
||||
12) UNDO deletion.
|
||||
13) REDO deletion.
|
||||
14) Look for errors and asserts.
|
||||
5) Enter/Exit game mode.
|
||||
6) Test IsHidden.
|
||||
7) Test IsVisible.
|
||||
8) Add Post FX Layer component.
|
||||
9) Delete Exposure Control entity.
|
||||
10) UNDO deletion.
|
||||
11) REDO deletion.
|
||||
12) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Creation of Exposure Control entity with no components.
|
||||
exposure_control_entity = EditorEntity.create_editor_entity(AtomComponentProperties.exposure_control())
|
||||
exposure_control_name = "Exposure Control"
|
||||
exposure_control_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(512.0, 512.0, 34.0), f"{exposure_control_name}")
|
||||
Report.critical_result(Tests.exposure_control_creation, exposure_control_entity.exists())
|
||||
|
||||
# 2. Add Exposure Control component to Exposure Control entity.
|
||||
exposure_control_component = exposure_control_entity.add_component(AtomComponentProperties.exposure_control())
|
||||
exposure_control_entity.add_component(exposure_control_name)
|
||||
Report.critical_result(
|
||||
Tests.exposure_control_component,
|
||||
exposure_control_entity.has_component(AtomComponentProperties.exposure_control()))
|
||||
Tests.exposure_control_component, exposure_control_entity.has_component(exposure_control_name))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
@@ -138,51 +104,40 @@ def AtomEditorComponents_ExposureControl_AddedToEntity():
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, exposure_control_entity.exists())
|
||||
|
||||
# 5. Verify Exposure Control component not enabled.
|
||||
Report.result(Tests.exposure_control_disabled, not exposure_control_component.is_enabled())
|
||||
|
||||
# 6. Add Post FX Layer component since it is required by the Exposure Control component.
|
||||
exposure_control_entity.add_component(AtomComponentProperties.postfx_layer())
|
||||
Report.result(Tests.post_fx_component,
|
||||
exposure_control_entity.has_component(AtomComponentProperties.postfx_layer()))
|
||||
|
||||
# 7. Verify Exposure Control component is enabled.
|
||||
Report.result(Tests.exposure_control_enabled, exposure_control_component.is_enabled())
|
||||
|
||||
# 8. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
# 5. Enter/Exit game mode.
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 9. Test IsHidden.
|
||||
# 6. Test IsHidden.
|
||||
exposure_control_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, exposure_control_entity.is_hidden() is True)
|
||||
|
||||
# 10. Test IsVisible.
|
||||
# 7. Test IsVisible.
|
||||
exposure_control_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, exposure_control_entity.is_visible() is True)
|
||||
|
||||
# 11. Delete ExposureControl entity.
|
||||
# 8. Add Post FX Layer component.
|
||||
post_fx_layer_name = "PostFX Layer"
|
||||
exposure_control_entity.add_component(post_fx_layer_name)
|
||||
Report.result(Tests.post_fx_component, exposure_control_entity.has_component(post_fx_layer_name))
|
||||
|
||||
# 9. Delete ExposureControl entity.
|
||||
exposure_control_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not exposure_control_entity.exists())
|
||||
|
||||
# 12. UNDO deletion.
|
||||
# 10. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, exposure_control_entity.exists())
|
||||
|
||||
# 13. REDO deletion.
|
||||
# 11. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not exposure_control_entity.exists())
|
||||
|
||||
# 14. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
# 12. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+41
-76
@@ -5,55 +5,26 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
# fmt: off
|
||||
class Tests:
|
||||
camera_creation = (
|
||||
"Camera Entity successfully created",
|
||||
"Camera Entity failed to be created")
|
||||
camera_component_added = (
|
||||
"Camera component was added to entity",
|
||||
"Camera component failed to be added to entity")
|
||||
camera_component_check = (
|
||||
"Entity has a Camera component",
|
||||
"Entity failed to find Camera component")
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"REDO Entity creation failed")
|
||||
global_skylight_creation = (
|
||||
"Global Skylight (IBL) Entity successfully created",
|
||||
"Global Skylight (IBL) Entity failed to be created")
|
||||
global_skylight_component = (
|
||||
"Entity has a Global Skylight (IBL) component",
|
||||
"Entity failed to find Global Skylight (IBL) component")
|
||||
diffuse_image_set = (
|
||||
"Entity has the Diffuse Image set",
|
||||
"Entity did not the Diffuse Image set")
|
||||
specular_image_set = (
|
||||
"Entity has the Specular Image set",
|
||||
"Entity did not the Specular Image set")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"REDO deletion failed")
|
||||
camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
|
||||
camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
|
||||
camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
|
||||
creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
|
||||
creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
|
||||
global_skylight_creation = ("Global Skylight (IBL) Entity successfully created", "Global Skylight (IBL) Entity failed to be created")
|
||||
global_skylight_component = ("Entity has a Global Skylight (IBL) component", "Entity failed to find Global Skylight (IBL) component")
|
||||
diffuse_image_set = ("Entity has the Diffuse Image set", "Entity did not the Diffuse Image set")
|
||||
specular_image_set = ("Entity has the Specular Image set", "Entity did not the Specular Image set")
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
is_visible = ("Entity is visible", "Entity was not visible")
|
||||
is_hidden = ("Entity is hidden", "Entity was not hidden")
|
||||
entity_deleted = ("Entity deleted", "Entity was not deleted")
|
||||
deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
|
||||
deletion_redo = ("REDO deletion success", "REDO deletion failed")
|
||||
no_error_occurred = ("No errors detected", "Errors were detected")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity():
|
||||
@@ -89,28 +60,29 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity():
|
||||
import os
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
from editor_python_test_tools.asset_utils import Asset
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
helper.init_idle()
|
||||
helper.open_level("", "Base")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Global Skylight (IBL) entity with no components.
|
||||
global_skylight_entity = EditorEntity.create_editor_entity(AtomComponentProperties.global_skylight())
|
||||
global_skylight_name = "Global Skylight (IBL)"
|
||||
global_skylight_entity = EditorEntity.create_editor_entity_at(
|
||||
math.Vector3(512.0, 512.0, 34.0), global_skylight_name)
|
||||
Report.critical_result(Tests.global_skylight_creation, global_skylight_entity.exists())
|
||||
|
||||
# 2. Add Global Skylight (IBL) component to Global Skylight (IBL) entity.
|
||||
global_skylight_component = global_skylight_entity.add_component(AtomComponentProperties.global_skylight())
|
||||
global_skylight_component = global_skylight_entity.add_component(global_skylight_name)
|
||||
Report.critical_result(
|
||||
Tests.global_skylight_component,
|
||||
global_skylight_entity.has_component(AtomComponentProperties.global_skylight()))
|
||||
Tests.global_skylight_component, global_skylight_entity.has_component(global_skylight_name))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
@@ -137,9 +109,9 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity():
|
||||
Report.result(Tests.creation_redo, global_skylight_entity.exists())
|
||||
|
||||
# 5. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 6. Test IsHidden.
|
||||
global_skylight_entity.set_visibility_state(False)
|
||||
@@ -154,21 +126,19 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity():
|
||||
diffuse_image_path = os.path.join("LightingPresets", "default_iblskyboxcm.exr.streamingimage")
|
||||
diffuse_image_asset = Asset.find_asset_by_path(diffuse_image_path, False)
|
||||
global_skylight_component.set_component_property_value(
|
||||
AtomComponentProperties.global_skylight('Diffuse Image'), diffuse_image_asset.id)
|
||||
Report.result(
|
||||
Tests.diffuse_image_set,
|
||||
diffuse_image_asset.id == global_skylight_component.get_component_property_value(
|
||||
AtomComponentProperties.global_skylight('Diffuse Image')))
|
||||
global_skylight_diffuse_image_property, diffuse_image_asset.id)
|
||||
diffuse_image_set = global_skylight_component.get_component_property_value(
|
||||
global_skylight_diffuse_image_property)
|
||||
Report.result(Tests.diffuse_image_set, diffuse_image_set == diffuse_image_asset.id)
|
||||
|
||||
# 9. Set the Specular Image asset on the Global Light (IBL) entity.
|
||||
specular_image_path = os.path.join("LightingPresets", "default_iblskyboxcm.exr.streamingimage")
|
||||
specular_image_asset = Asset.find_asset_by_path(specular_image_path, False)
|
||||
global_skylight_component.set_component_property_value(
|
||||
AtomComponentProperties.global_skylight('Specular Image'), specular_image_asset.id)
|
||||
Report.result(
|
||||
Tests.specular_image_set,
|
||||
specular_image_asset.id == global_skylight_component.get_component_property_value(
|
||||
AtomComponentProperties.global_skylight('Specular Image')))
|
||||
global_skylight_specular_image_property, specular_image_asset.id)
|
||||
specular_image_added = global_skylight_component.get_component_property_value(
|
||||
global_skylight_specular_image_property)
|
||||
Report.result(Tests.specular_image_set, specular_image_added == specular_image_asset.id)
|
||||
|
||||
# 10. Delete Global Skylight (IBL) entity.
|
||||
global_skylight_entity.delete()
|
||||
@@ -176,20 +146,15 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity():
|
||||
|
||||
# 11. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, global_skylight_entity.exists())
|
||||
|
||||
# 12. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not global_skylight_entity.exists())
|
||||
|
||||
# 13. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
# 13. Look for errors.
|
||||
helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
|
||||
Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
class Tests:
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"REDO Entity creation failed")
|
||||
grid_entity_creation = (
|
||||
"Grid Entity successfully created",
|
||||
"Grid Entity failed to be created")
|
||||
grid_component_added = (
|
||||
"Entity has a Grid component",
|
||||
"Entity failed to find Grid component")
|
||||
grid_size = (
|
||||
"Grid Size value set successfully",
|
||||
"Grid Size value could not be set")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"REDO deletion failed")
|
||||
|
||||
|
||||
def AtomEditorComponents_Grid_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the Grid component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create a Grid entity with no components.
|
||||
2) Add a Grid component to Grid entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Grid Size changed.
|
||||
6) Enter/Exit game mode.
|
||||
7) Test IsHidden.
|
||||
8) Test IsVisible.
|
||||
9) Delete Grid entity.
|
||||
10) UNDO deletion.
|
||||
11) REDO deletion.
|
||||
12) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Grid entity with no components.
|
||||
grid_entity = EditorEntity.create_editor_entity(AtomComponentProperties.grid())
|
||||
Report.critical_result(Tests.grid_entity_creation, grid_entity.exists())
|
||||
|
||||
# 2. Add a Grid component to Grid entity.
|
||||
grid_component = grid_entity.add_component(AtomComponentProperties.grid())
|
||||
Report.critical_result(
|
||||
Tests.grid_component_added,
|
||||
grid_entity.has_component(AtomComponentProperties.grid()))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not grid_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, grid_entity.exists())
|
||||
|
||||
# 5. Grid Size changed
|
||||
grid_component.set_component_property_value(
|
||||
AtomComponentProperties.grid('Grid Size'), value=64)
|
||||
current_grid_size = grid_component.get_component_property_value(
|
||||
AtomComponentProperties.grid('Grid Size'))
|
||||
Report.result(Tests.grid_size, current_grid_size == 64)
|
||||
|
||||
# 6. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 7. Test IsHidden.
|
||||
grid_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, grid_entity.is_hidden() is True)
|
||||
|
||||
# 8. Test IsVisible.
|
||||
grid_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, grid_entity.is_visible() is True)
|
||||
|
||||
# 9. Delete Grid entity.
|
||||
grid_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not grid_entity.exists())
|
||||
|
||||
# 10. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, grid_entity.exists())
|
||||
|
||||
# 11. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not grid_entity.exists())
|
||||
|
||||
# 12. Look for errors or asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_Grid_AddedToEntity)
|
||||
-194
@@ -1,194 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
class Tests:
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"REDO Entity creation failed")
|
||||
hdr_color_grading_creation = (
|
||||
"HDR Color Grading Entity successfully created",
|
||||
"HDR Color Grading Entity failed to be created")
|
||||
hdr_color_grading_component = (
|
||||
"Entity has an HDR Color Grading component",
|
||||
"Entity failed to find HDR Color Grading component")
|
||||
hdr_color_grading_disabled = (
|
||||
"HDR Color Grading component disabled",
|
||||
"HDR Color Grading component was not disabled")
|
||||
postfx_layer_component = (
|
||||
"Entity has a PostFX Layer component",
|
||||
"Entity did not have an PostFX Layer component")
|
||||
hdr_color_grading_enabled = (
|
||||
"HDR Color Grading component enabled",
|
||||
"HDR Color Grading component was not enabled")
|
||||
enable_hdr_color_grading_parameter_enabled = (
|
||||
"Enable HDR Color Grading parameter enabled",
|
||||
"Enable HDR Color Grading parameter was not enabled")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"REDO deletion failed")
|
||||
|
||||
|
||||
def AtomEditorComponents_HDRColorGrading_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the HDR Color Grading component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create an HDR Color Grading entity with no components.
|
||||
2) Add HDR Color Grading component to HDR Color Grading entity.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Verify HDR Color Grading component not enabled.
|
||||
6) Add PostFX Layer component since it is required by the HDR Color Grading component.
|
||||
7) Verify HDR Color Grading component is enabled.
|
||||
8) Enable the "Enable HDR Color Grading" parameter.
|
||||
9) Enter/Exit game mode.
|
||||
10) Test IsHidden.
|
||||
11) Test IsVisible.
|
||||
12) Delete HDR Color Grading entity.
|
||||
13) UNDO deletion.
|
||||
14) REDO deletion.
|
||||
15) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create an HDR Color Grading entity with no components.
|
||||
hdr_color_grading_entity = EditorEntity.create_editor_entity(AtomComponentProperties.hdr_color_grading())
|
||||
Report.critical_result(Tests.hdr_color_grading_creation, hdr_color_grading_entity.exists())
|
||||
|
||||
# 2. Add HDR Color Grading component to HDR Color Grading entity.
|
||||
hdr_color_grading_component = hdr_color_grading_entity.add_component(
|
||||
AtomComponentProperties.hdr_color_grading())
|
||||
Report.critical_result(
|
||||
Tests.hdr_color_grading_component,
|
||||
hdr_color_grading_entity.has_component(AtomComponentProperties.hdr_color_grading()))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not hdr_color_grading_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, hdr_color_grading_entity.exists())
|
||||
|
||||
# 5. Verify HDR Color Grading component not enabled.
|
||||
Report.result(Tests.hdr_color_grading_disabled, not hdr_color_grading_component.is_enabled())
|
||||
|
||||
# 6. Add PostFX Layer component since it is required by the HDR Color Grading component.
|
||||
hdr_color_grading_entity.add_component(AtomComponentProperties.postfx_layer())
|
||||
Report.result(
|
||||
Tests.postfx_layer_component,
|
||||
hdr_color_grading_entity.has_component(AtomComponentProperties.postfx_layer()))
|
||||
|
||||
# 7. Verify HDR Color Grading component is enabled.
|
||||
Report.result(Tests.hdr_color_grading_enabled, hdr_color_grading_component.is_enabled())
|
||||
|
||||
# 8. Enable the "Enable HDR Color Grading" parameter.
|
||||
hdr_color_grading_component.set_component_property_value(
|
||||
AtomComponentProperties.hdr_color_grading('Enable HDR color grading'), True)
|
||||
Report.result(Tests.enable_hdr_color_grading_parameter_enabled,
|
||||
hdr_color_grading_component.get_component_property_value(
|
||||
AtomComponentProperties.hdr_color_grading('Enable HDR color grading')) is True)
|
||||
|
||||
# 9. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 10. Test IsHidden.
|
||||
hdr_color_grading_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, hdr_color_grading_entity.is_hidden() is True)
|
||||
|
||||
# 11. Test IsVisible.
|
||||
hdr_color_grading_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, hdr_color_grading_entity.is_visible() is True)
|
||||
|
||||
# 12. Delete HDR Color Grading entity.
|
||||
hdr_color_grading_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not hdr_color_grading_entity.exists())
|
||||
|
||||
# 13. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, hdr_color_grading_entity.exists())
|
||||
|
||||
# 14. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not hdr_color_grading_entity.exists())
|
||||
|
||||
# 15. Look for errors and asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_HDRColorGrading_AddedToEntity)
|
||||
-179
@@ -1,179 +0,0 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
|
||||
class Tests:
|
||||
creation_undo = (
|
||||
"UNDO Entity creation success",
|
||||
"UNDO Entity creation failed")
|
||||
creation_redo = (
|
||||
"REDO Entity creation success",
|
||||
"REDO Entity creation failed")
|
||||
hdri_skybox_entity_creation = (
|
||||
"HDRi Skybox successfully created",
|
||||
"HDRi Skybox failed to be created")
|
||||
hdri_skybox_component = (
|
||||
"Entity has an HDRi Skybox component",
|
||||
"Entity failed to find HDRi Skybox component")
|
||||
cubemap_property_set = (
|
||||
"Cubemap property set on HDRi Skybox component",
|
||||
"Couldn't set Cubemap property on HDRi Skybox component")
|
||||
enter_game_mode = (
|
||||
"Entered game mode",
|
||||
"Failed to enter game mode")
|
||||
exit_game_mode = (
|
||||
"Exited game mode",
|
||||
"Couldn't exit game mode")
|
||||
is_visible = (
|
||||
"Entity is visible",
|
||||
"Entity was not visible")
|
||||
is_hidden = (
|
||||
"Entity is hidden",
|
||||
"Entity was not hidden")
|
||||
entity_deleted = (
|
||||
"Entity deleted",
|
||||
"Entity was not deleted")
|
||||
deletion_undo = (
|
||||
"UNDO deletion success",
|
||||
"UNDO deletion failed")
|
||||
deletion_redo = (
|
||||
"REDO deletion success",
|
||||
"REDO deletion failed")
|
||||
|
||||
|
||||
def AtomEditorComponents_HDRiSkybox_AddedToEntity():
|
||||
"""
|
||||
Summary:
|
||||
Tests the HDRi Skybox component can be added to an entity and has the expected functionality.
|
||||
|
||||
Test setup:
|
||||
- Wait for Editor idle loop.
|
||||
- Open the "Base" level.
|
||||
|
||||
Expected Behavior:
|
||||
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
|
||||
Creation and deletion undo/redo should also work.
|
||||
|
||||
Test Steps:
|
||||
1) Create an HDRi Skybox with no components.
|
||||
2) Add an HDRi Skybox component to HDRi Skybox.
|
||||
3) UNDO the entity creation and component addition.
|
||||
4) REDO the entity creation and component addition.
|
||||
5) Enter/Exit game mode.
|
||||
6) Test IsHidden.
|
||||
7) Test IsVisible.
|
||||
8) Delete HDRi Skybox.
|
||||
9) UNDO deletion.
|
||||
10) REDO deletion.
|
||||
11) Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from editor_python_test_tools.asset_utils import Asset
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
from editor_python_test_tools.utils import Report, Tracer, TestHelper
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
|
||||
with Tracer() as error_tracer:
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create an HDRi Skybox with no components.
|
||||
hdri_skybox_entity = EditorEntity.create_editor_entity(
|
||||
AtomComponentProperties.hdri_skybox())
|
||||
Report.critical_result(Tests.hdri_skybox_entity_creation,
|
||||
hdri_skybox_entity.exists())
|
||||
|
||||
# 2. Add an HDRi Skybox component to HDRi Skybox.
|
||||
hdri_skybox_component = hdri_skybox_entity.add_component(
|
||||
AtomComponentProperties.hdri_skybox())
|
||||
Report.critical_result(
|
||||
Tests.hdri_skybox_component,
|
||||
hdri_skybox_entity.has_component(AtomComponentProperties.hdri_skybox()))
|
||||
|
||||
# 3. UNDO the entity creation and component addition.
|
||||
# -> UNDO component addition.
|
||||
general.undo()
|
||||
# -> UNDO naming entity.
|
||||
general.undo()
|
||||
# -> UNDO selecting entity.
|
||||
general.undo()
|
||||
# -> UNDO entity creation.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_undo, not hdri_skybox_entity.exists())
|
||||
|
||||
# 4. REDO the entity creation and component addition.
|
||||
# -> REDO entity creation.
|
||||
general.redo()
|
||||
# -> REDO selecting entity.
|
||||
general.redo()
|
||||
# -> REDO naming entity.
|
||||
general.redo()
|
||||
# -> REDO component addition.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.creation_redo, hdri_skybox_entity.exists())
|
||||
|
||||
|
||||
# 5. Set Cubemap Texture on HDRi Skybox component.
|
||||
skybox_cubemap_asset_path = os.path.join("LightingPresets", "default_iblskyboxcm.exr.streamingimage")
|
||||
skybox_cubemap_material_asset = Asset.find_asset_by_path(skybox_cubemap_asset_path, False)
|
||||
hdri_skybox_component.set_component_property_value(
|
||||
AtomComponentProperties.hdri_skybox('Cubemap Texture'), skybox_cubemap_material_asset.id)
|
||||
get_cubemap_property = hdri_skybox_component.get_component_property_value(
|
||||
AtomComponentProperties.hdri_skybox('Cubemap Texture'))
|
||||
Report.result(Tests.cubemap_property_set, get_cubemap_property == skybox_cubemap_material_asset.id)
|
||||
|
||||
|
||||
# 6. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
general.idle_wait_frames(1)
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
# 7. Test IsHidden.
|
||||
hdri_skybox_entity.set_visibility_state(False)
|
||||
Report.result(Tests.is_hidden, hdri_skybox_entity.is_hidden() is True)
|
||||
|
||||
# 8. Test IsVisible.
|
||||
hdri_skybox_entity.set_visibility_state(True)
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.is_visible, hdri_skybox_entity.is_visible() is True)
|
||||
|
||||
# 9. Delete hdri_skybox entity.
|
||||
hdri_skybox_entity.delete()
|
||||
Report.result(Tests.entity_deleted, not hdri_skybox_entity.exists())
|
||||
|
||||
# 10. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, hdri_skybox_entity.exists())
|
||||
|
||||
# 11. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not hdri_skybox_entity.exists())
|
||||
|
||||
# 12. Look for errors or asserts.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
for assert_info in error_tracer.asserts:
|
||||
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(AtomEditorComponents_HDRiSkybox_AddedToEntity)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user