Merge branch 'main' into LYN-3969
commit
60da667e8b
File diff suppressed because it is too large
Load Diff
@ -1 +1 @@
|
||||
/autooptimizefile=0 /preset=AlbedoWithGenericAlpha /reduce="es3:2,ios:2,osx_gl:0,pc:0,provo:0"
|
||||
/autooptimizefile=0 /preset=AlbedoWithGenericAlpha /reduce="android:2,ios:2,mac:0,pc:0,provo:0"
|
||||
@ -1 +1 @@
|
||||
/autooptimizefile=0 /preset=Albedo /reduce="es3:3,ios:3,osx_gl:0,pc:0,provo:0"
|
||||
/autooptimizefile=0 /preset=Albedo /reduce="android:3,ios:3,mac:0,pc:0,provo:0"
|
||||
@ -0,0 +1,58 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
set(ENABLED_GEMS
|
||||
ImGui
|
||||
ScriptEvents
|
||||
ExpressionEvaluation
|
||||
Gestures
|
||||
CertificateManager
|
||||
DebugDraw
|
||||
SceneProcessing
|
||||
GraphCanvas
|
||||
InAppPurchases
|
||||
AutomatedTesting
|
||||
EditorPythonBindings
|
||||
QtForPython
|
||||
PythonAssetBuilder
|
||||
Metastream
|
||||
AudioSystem
|
||||
Camera
|
||||
EMotionFX
|
||||
PhysX
|
||||
CameraFramework
|
||||
StartingPointMovement
|
||||
StartingPointCamera
|
||||
ScriptCanvas
|
||||
ScriptCanvasPhysics
|
||||
ScriptCanvasTesting
|
||||
LyShineExamples
|
||||
StartingPointInput
|
||||
PhysXDebug
|
||||
WhiteBox
|
||||
FastNoise
|
||||
SurfaceData
|
||||
GradientSignal
|
||||
Vegetation
|
||||
GraphModel
|
||||
LandscapeCanvas
|
||||
NvCloth
|
||||
Blast
|
||||
Maestro
|
||||
TextureAtlas
|
||||
LmbrCentral
|
||||
LyShine
|
||||
HttpRequestor
|
||||
Atom_AtomBridge
|
||||
AWSCore
|
||||
AWSClientAuth
|
||||
AWSMetrics
|
||||
)
|
||||
@ -1,48 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the License). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an AS IS BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
# Extracted from Game
|
||||
set(GEM_DEPENDENCIES
|
||||
Gem::Maestro
|
||||
Gem::TextureAtlas
|
||||
Gem::LmbrCentral
|
||||
Gem::LyShine
|
||||
Gem::HttpRequestor
|
||||
Gem::ScriptEvents
|
||||
Gem::ExpressionEvaluation
|
||||
Gem::Gestures
|
||||
Gem::CertificateManager
|
||||
Gem::DebugDraw
|
||||
Gem::AudioSystem
|
||||
Gem::InAppPurchases
|
||||
Gem::AutomatedTesting
|
||||
Gem::Metastream
|
||||
Gem::Camera
|
||||
Gem::EMotionFX
|
||||
Gem::PhysX
|
||||
Gem::CameraFramework
|
||||
Gem::StartingPointMovement
|
||||
Gem::StartingPointCamera
|
||||
Gem::ScriptCanvas
|
||||
Gem::ImGui
|
||||
Gem::LyShineExamples
|
||||
Gem::StartingPointInput
|
||||
Gem::ScriptCanvasPhysics
|
||||
Gem::PhysXDebug
|
||||
Gem::WhiteBox
|
||||
Gem::FastNoise
|
||||
Gem::SurfaceData
|
||||
Gem::GradientSignal
|
||||
Gem::Vegetation
|
||||
Gem::Atom_AtomBridge
|
||||
Gem::NvCloth
|
||||
Gem::Blast
|
||||
)
|
||||
@ -1,60 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the License). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an AS IS BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
# Extracted from Editor.xml
|
||||
set(GEM_DEPENDENCIES
|
||||
Gem::Maestro.Editor
|
||||
Gem::TextureAtlas.Editor
|
||||
Gem::LmbrCentral.Editor
|
||||
Gem::LyShine.Editor
|
||||
Gem::HttpRequestor
|
||||
Gem::ScriptEvents.Editor
|
||||
Gem::ExpressionEvaluation
|
||||
Gem::Gestures
|
||||
Gem::CertificateManager
|
||||
Gem::DebugDraw.Editor
|
||||
Gem::SceneProcessing.Editor
|
||||
Gem::GraphCanvas.Editor
|
||||
Gem::InAppPurchases
|
||||
Gem::AutomatedTesting
|
||||
Gem::EditorPythonBindings.Editor
|
||||
Gem::PythonAssetBuilder.Editor
|
||||
Gem::Metastream
|
||||
Gem::AudioSystem.Editor
|
||||
Gem::Camera.Editor
|
||||
Gem::EMotionFX.Editor
|
||||
Gem::PhysX.Editor
|
||||
Gem::CameraFramework
|
||||
Gem::StartingPointMovement
|
||||
Gem::StartingPointCamera
|
||||
Gem::ScriptCanvas.Editor
|
||||
Gem::ScriptEvents.Editor
|
||||
Gem::ImGui.Editor
|
||||
Gem::LyShineExamples
|
||||
Gem::StartingPointInput.Editor
|
||||
Gem::ScriptCanvasPhysics
|
||||
Gem::ScriptCanvasTesting.Editor
|
||||
Gem::PhysXDebug.Editor
|
||||
Gem::WhiteBox.Editor
|
||||
Gem::FastNoise.Editor
|
||||
Gem::SurfaceData.Editor
|
||||
Gem::GradientSignal.Editor
|
||||
Gem::Vegetation.Editor
|
||||
Gem::GraphModel.Editor
|
||||
Gem::LandscapeCanvas.Editor
|
||||
Gem::EMotionFX.Editor
|
||||
Gem::ImGui.Editor
|
||||
Gem::Atom_RHI.Private
|
||||
Gem::Atom_Feature_Common.Editor
|
||||
Gem::Atom_AtomBridge.Editor
|
||||
Gem::NvCloth.Editor
|
||||
Gem::Blast.Editor
|
||||
)
|
||||
@ -0,0 +1,10 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
@ -0,0 +1,237 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import pytest
|
||||
import time
|
||||
import typing
|
||||
|
||||
from datetime import datetime
|
||||
import ly_test_tools.log.log_monitor
|
||||
|
||||
from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor as asset_processor
|
||||
from AWS.common.aws_utils import aws_utils
|
||||
from AWS.common.aws_credentials import aws_credentials
|
||||
from AWS.Windows.resource_mappings.resource_mappings import resource_mappings
|
||||
from AWS.Windows.cdk.cdk import cdk
|
||||
from .aws_metrics_utils import aws_metrics_utils
|
||||
|
||||
AWS_METRICS_FEATURE_NAME = 'AWSMetrics'
|
||||
GAME_LOG_NAME = 'Game.log'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup(launcher: ly_test_tools.launchers.Launcher,
|
||||
cdk: cdk,
|
||||
asset_processor: asset_processor,
|
||||
resource_mappings: resource_mappings,
|
||||
context_variable: str = '') -> typing.Tuple[ly_test_tools.log.log_monitor.LogMonitor, str, str]:
|
||||
"""
|
||||
Set up the CDK application and start the log monitor.
|
||||
:param launcher: Client launcher for running the test level.
|
||||
:param cdk: CDK application for deploying the AWS resources.
|
||||
:param asset_processor: asset_processor fixture.
|
||||
:param resource_mappings: resource_mappings fixture.
|
||||
:param context_variable: context_variable for enable optional CDK feature.
|
||||
:return log monitor object, metrics file path and the metrics stack name.
|
||||
"""
|
||||
logger.info(f'Cdk stack names:\n{cdk.list()}')
|
||||
stacks = cdk.deploy(context_variable=context_variable)
|
||||
resource_mappings.populate_output_keys(stacks)
|
||||
|
||||
asset_processor.start()
|
||||
asset_processor.wait_for_idle()
|
||||
|
||||
metrics_file_path = os.path.join(launcher.workspace.paths.project(), 'user',
|
||||
AWS_METRICS_FEATURE_NAME, 'metrics.json')
|
||||
remove_file(metrics_file_path)
|
||||
|
||||
file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), GAME_LOG_NAME)
|
||||
remove_file(file_to_monitor)
|
||||
|
||||
# Initialize the log monitor.
|
||||
log_monitor = ly_test_tools.log.log_monitor.LogMonitor(launcher=launcher, log_file_path=file_to_monitor)
|
||||
|
||||
return log_monitor, metrics_file_path, stacks[0]
|
||||
|
||||
|
||||
def monitor_metrics_submission(log_monitor: ly_test_tools.log.log_monitor.LogMonitor) -> 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) - 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 remove_file(file_path: str) -> None:
|
||||
"""
|
||||
Remove a local file and its directory.
|
||||
:param file_path: Path to the local file.
|
||||
"""
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
|
||||
file_dir = os.path.dirname(file_path)
|
||||
if os.path.exists(file_dir) and len(os.listdir(file_dir)) == 0:
|
||||
os.rmdir(file_dir)
|
||||
|
||||
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.usefixtures('automatic_process_killer')
|
||||
@pytest.mark.parametrize('project', ['AutomatedTesting'])
|
||||
@pytest.mark.parametrize('level', ['AWS/Metrics'])
|
||||
@pytest.mark.parametrize('feature_name', [AWS_METRICS_FEATURE_NAME])
|
||||
@pytest.mark.parametrize('resource_mappings_filename', ['aws_resource_mappings.json'])
|
||||
@pytest.mark.parametrize('profile_name', ['AWSAutomationTest'])
|
||||
@pytest.mark.parametrize('region_name', ['us-west-2'])
|
||||
@pytest.mark.parametrize('assume_role_arn', ['arn:aws:iam::645075835648:role/o3de-automation-tests'])
|
||||
@pytest.mark.parametrize('session_name', ['o3de-Automation-session'])
|
||||
class TestAWSMetrics_Windows(object):
|
||||
def test_AWSMetrics_RealTimeAnalytics_MetricsSentToCloudWatch(self,
|
||||
level: str,
|
||||
launcher: ly_test_tools.launchers.Launcher,
|
||||
asset_processor: pytest.fixture,
|
||||
workspace: pytest.fixture,
|
||||
aws_utils: aws_utils,
|
||||
aws_credentials: aws_credentials,
|
||||
resource_mappings: resource_mappings,
|
||||
cdk: cdk,
|
||||
aws_metrics_utils: aws_metrics_utils,
|
||||
):
|
||||
"""
|
||||
Tests that the submitted metrics are sent to CloudWatch for real-time analytics.
|
||||
"""
|
||||
log_monitor, metrics_file_path, stack_name = setup(launcher, cdk, asset_processor, resource_mappings)
|
||||
|
||||
# Start the Kinesis Data Analytics application for real-time analytics.
|
||||
analytics_application_name = f'{stack_name}-AnalyticsApplication'
|
||||
aws_metrics_utils.start_kinesis_data_analytics_application(analytics_application_name)
|
||||
|
||||
launcher.args = ['+LoadLevel', level]
|
||||
launcher.args.extend(['-rhi=null'])
|
||||
|
||||
with launcher.start(launch_ap=False):
|
||||
start_time = datetime.utcnow()
|
||||
monitor_metrics_submission(log_monitor)
|
||||
# Verify that operational health metrics are delivered to CloudWatch.
|
||||
aws_metrics_utils.verify_cloud_watch_delivery(
|
||||
'AWS/Lambda',
|
||||
'Invocations',
|
||||
[{'Name': 'FunctionName',
|
||||
'Value': f'{stack_name}-AnalyticsProcessingLambda'}],
|
||||
start_time)
|
||||
logger.info('Operational health metrics sent to CloudWatch.')
|
||||
|
||||
aws_metrics_utils.verify_cloud_watch_delivery(
|
||||
AWS_METRICS_FEATURE_NAME,
|
||||
'TotalLogins',
|
||||
[],
|
||||
start_time)
|
||||
logger.info('Real-time metrics sent to CloudWatch.')
|
||||
|
||||
# Stop the Kinesis Data Analytics application.
|
||||
aws_metrics_utils.stop_kinesis_data_analytics_application(analytics_application_name)
|
||||
|
||||
def test_AWSMetrics_UnauthorizedUser_RequestRejected(self,
|
||||
level: str,
|
||||
launcher: ly_test_tools.launchers.Launcher,
|
||||
cdk: cdk,
|
||||
aws_credentials: aws_credentials,
|
||||
asset_processor: pytest.fixture,
|
||||
resource_mappings: resource_mappings,
|
||||
workspace: pytest.fixture):
|
||||
"""
|
||||
Tests that unauthorized users cannot send metrics events to the AWS backed backend.
|
||||
"""
|
||||
log_monitor, metrics_file_path, stack_name = setup(launcher, cdk, asset_processor, resource_mappings)
|
||||
# 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_AWSMetrics_BatchAnalytics_MetricsDeliveredToS3(self,
|
||||
level: str,
|
||||
launcher: ly_test_tools.launchers.Launcher,
|
||||
cdk: cdk,
|
||||
aws_credentials: aws_credentials,
|
||||
asset_processor: pytest.fixture,
|
||||
resource_mappings: resource_mappings,
|
||||
aws_utils: aws_utils,
|
||||
aws_metrics_utils: aws_metrics_utils,
|
||||
workspace: pytest.fixture):
|
||||
"""
|
||||
Tests that the submitted metrics are sent to the data lake for batch analytics.
|
||||
"""
|
||||
log_monitor, metrics_file_path, stack_name = setup(launcher, cdk, asset_processor, resource_mappings,
|
||||
context_variable='batch_processing=true')
|
||||
|
||||
analytics_bucket_name = aws_metrics_utils.get_analytics_bucket_name(stack_name)
|
||||
|
||||
launcher.args = ['+LoadLevel', level]
|
||||
launcher.args.extend(['-rhi=null'])
|
||||
|
||||
with launcher.start(launch_ap=False):
|
||||
start_time = datetime.utcnow()
|
||||
monitor_metrics_submission(log_monitor)
|
||||
# Verify that operational health metrics are delivered to CloudWatch.
|
||||
aws_metrics_utils.verify_cloud_watch_delivery(
|
||||
'AWS/Lambda',
|
||||
'Invocations',
|
||||
[{'Name': 'FunctionName',
|
||||
'Value': f'{stack_name}-EventsProcessingLambda'}],
|
||||
start_time)
|
||||
logger.info('Operational health metrics sent to CloudWatch.')
|
||||
|
||||
aws_metrics_utils.verify_s3_delivery(analytics_bucket_name)
|
||||
logger.info('Metrics sent to S3.')
|
||||
|
||||
# Run the glue crawler to populate the AWS Glue Data Catalog with tables.
|
||||
aws_metrics_utils.run_glue_crawler(f'{stack_name}-EventsCrawler')
|
||||
# Run named queries on the table to verify the batch analytics.
|
||||
aws_metrics_utils.run_named_queries(f'{stack_name}-AthenaWorkGroup')
|
||||
logger.info('Query metrics from S3 successfully.')
|
||||
|
||||
# Kinesis Data Firehose buffers incoming data before it delivers it to Amazon S3. Sleep for the
|
||||
# default interval (60s) to make sure that all the metrics are sent to the bucket before cleanup.
|
||||
time.sleep(60)
|
||||
# Empty the S3 bucket. S3 buckets can only be deleted successfully when it doesn't contain any object.
|
||||
aws_metrics_utils.empty_s3_bucket(analytics_bucket_name)
|
||||
|
||||
@ -0,0 +1,252 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import pathlib
|
||||
import pytest
|
||||
import typing
|
||||
|
||||
from datetime import datetime
|
||||
from botocore.exceptions import WaiterError
|
||||
|
||||
from AWS.common.aws_utils import AwsUtils
|
||||
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: AwsUtils):
|
||||
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_s3_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 get_analytics_bucket_name(self, stack_name: str) -> str:
|
||||
"""
|
||||
Get the name of the deployed S3 bucket.
|
||||
:param stack_name: Name of the CloudFormation stack.
|
||||
:return: Name of the deployed S3 bucket.
|
||||
"""
|
||||
|
||||
client = self._aws_util.client('cloudformation')
|
||||
|
||||
response = client.describe_stack_resources(
|
||||
StackName=stack_name
|
||||
)
|
||||
resources = response.get('StackResources', [])
|
||||
|
||||
for resource in resources:
|
||||
if resource.get('ResourceType') == 'AWS::S3::Bucket':
|
||||
return resource.get('PhysicalResourceId', '')
|
||||
|
||||
return ''
|
||||
|
||||
|
||||
@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
|
||||
@ -0,0 +1,142 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
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.
|
||||
"""
|
||||
def __init__(self, client: botocore.client):
|
||||
"""
|
||||
Initialize the waiter.
|
||||
|
||||
:param client: Boto3 client to use.
|
||||
"""
|
||||
super().__init__(
|
||||
'GlueCrawlerReady',
|
||||
'GetCrawler',
|
||||
'Crawler.State',
|
||||
{'READY': 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,134 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
import boto3
|
||||
import configparser
|
||||
import logging
|
||||
import os
|
||||
import pytest
|
||||
import typing
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.getLogger('boto').setLevel(logging.CRITICAL)
|
||||
|
||||
|
||||
class AwsCredentials:
|
||||
def __init__(self, profile_name: str):
|
||||
self._profile_name = profile_name
|
||||
|
||||
self._credentials_path = os.environ.get('AWS_SHARED_CREDENTIALS_FILE')
|
||||
if not self._credentials_path:
|
||||
# Home directory location varies based on the operating system, but is referred to using the environment
|
||||
# variables %UserProfile% in Windows and $HOME or ~ (tilde) in Unix-based systems.
|
||||
self._credentials_path = os.path.join(os.environ.get('UserProfile', os.path.expanduser('~')),
|
||||
'.aws', 'credentials')
|
||||
self._credentials_file_exists = os.path.exists(self._credentials_path)
|
||||
|
||||
self._credentials = configparser.ConfigParser()
|
||||
self._credentials.read(self._credentials_path)
|
||||
|
||||
def get_aws_credentials(self) -> typing.Tuple[str, str, str]:
|
||||
"""
|
||||
Get aws credentials stored in the specific named profile.
|
||||
|
||||
:return AWS credentials.
|
||||
"""
|
||||
access_key_id = self._get_aws_credential_attribute_value('aws_access_key_id')
|
||||
secret_access_key = self._get_aws_credential_attribute_value('aws_secret_access_key')
|
||||
session_token = self._get_aws_credential_attribute_value('aws_session_token')
|
||||
|
||||
return access_key_id, secret_access_key, session_token
|
||||
|
||||
def set_aws_credentials_by_session(self, session: boto3.Session) -> None:
|
||||
"""
|
||||
Set AWS credentials stored in the specific named profile using an assumed role session.
|
||||
|
||||
:param session: assumed role session.
|
||||
"""
|
||||
credentials = session.get_credentials().get_frozen_credentials()
|
||||
self.set_aws_credentials(credentials.access_key, credentials.secret_key, credentials.token)
|
||||
|
||||
def set_aws_credentials(self, aws_access_key_id: str, aws_secret_access_key: str,
|
||||
aws_session_token: str) -> None:
|
||||
"""
|
||||
Set AWS credentials stored in the specific named profile.
|
||||
|
||||
:param aws_access_key_id: AWS access key id.
|
||||
:param aws_secret_access_key: AWS secrete access key.
|
||||
:param aws_session_token: AWS assumed role session.
|
||||
"""
|
||||
self._set_aws_credential_attribute_value('aws_access_key_id', aws_access_key_id)
|
||||
self._set_aws_credential_attribute_value('aws_secret_access_key', aws_secret_access_key)
|
||||
self._set_aws_credential_attribute_value('aws_session_token', aws_session_token)
|
||||
|
||||
if (len(self._credentials.sections()) == 0) and (not self._credentials_file_exists):
|
||||
os.remove(self._credentials_path)
|
||||
return
|
||||
|
||||
with open(self._credentials_path, 'w+') as credential_file:
|
||||
self._credentials.write(credential_file)
|
||||
|
||||
def _get_aws_credential_attribute_value(self, attribute_name: str) -> str:
|
||||
"""
|
||||
Get the value of an AWS credential attribute stored in the specific named profile.
|
||||
|
||||
:param attribute_name: Name of the AWS credential attribute.
|
||||
:return Value of the AWS credential attribute.
|
||||
"""
|
||||
try:
|
||||
value = self._credentials.get(self._profile_name, attribute_name)
|
||||
except configparser.NoSectionError:
|
||||
# Named profile or key doesn't exist
|
||||
value = None
|
||||
except configparser.NoOptionError:
|
||||
# Named profile doesn't have the specified attribute
|
||||
value = None
|
||||
|
||||
return value
|
||||
|
||||
def _set_aws_credential_attribute_value(self, attribute_name: str, attribute_value: str) -> None:
|
||||
"""
|
||||
Set the value of an AWS credential attribute stored in the specific named profile.
|
||||
|
||||
:param attribute_name: Name of the AWS credential attribute.
|
||||
:param attribute_value: Value of the AWS credential attribute.
|
||||
"""
|
||||
if self._profile_name not in self._credentials:
|
||||
self._credentials[self._profile_name] = {}
|
||||
|
||||
if attribute_value is None:
|
||||
self._credentials.remove_option(self._profile_name, attribute_name)
|
||||
# Remove the named profile if it doesn't have any AWS credential attribute.
|
||||
if len(self._credentials[self._profile_name]) == 0:
|
||||
self._credentials.remove_section(self._profile_name)
|
||||
else:
|
||||
self._credentials[self._profile_name][attribute_name] = attribute_value
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def aws_credentials(request: pytest.fixture, aws_utils: pytest.fixture, profile_name: str):
|
||||
"""
|
||||
Fixture for setting up temporary AWS credentials from assume role.
|
||||
|
||||
:param request: _pytest.fixtures.SubRequest class that handles getting
|
||||
a pytest fixture from a pytest function/fixture.
|
||||
:param aws_utils: aws_utils fixture.
|
||||
:param profile_name: Named AWS profile to store temporary credentials.
|
||||
"""
|
||||
aws_credentials_obj = AwsCredentials(profile_name)
|
||||
original_access_key, original_secret_access_key, original_token = aws_credentials_obj.get_aws_credentials()
|
||||
aws_credentials_obj.set_aws_credentials_by_session(aws_utils.assume_session())
|
||||
|
||||
def teardown():
|
||||
# Reset to the named profile using the original AWS credentials
|
||||
aws_credentials_obj.set_aws_credentials(original_access_key, original_secret_access_key, original_token)
|
||||
request.addfinalizer(teardown)
|
||||
|
||||
return aws_credentials_obj
|
||||
@ -1,82 +1,90 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
import boto3
|
||||
import pytest
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AwsUtils:
|
||||
|
||||
def __init__(self, arn: str, session_name: str, region_name: str):
|
||||
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}')
|
||||
|
||||
response = local_sts_client.assume_role(RoleArn=arn, RoleSessionName=session_name)
|
||||
|
||||
self._assume_session = boto3.Session(aws_access_key_id=response['Credentials']['AccessKeyId'],
|
||||
aws_secret_access_key=response['Credentials']['SecretAccessKey'],
|
||||
aws_session_token=response['Credentials']['SessionToken'],
|
||||
region_name=region_name)
|
||||
|
||||
assume_sts_client = self._assume_session.client('sts')
|
||||
assume_account_id = assume_sts_client.get_caller_identity()["Account"]
|
||||
logger.info(f'Assume Account Id: {assume_account_id}')
|
||||
self._assume_account_id = assume_account_id
|
||||
|
||||
def client(self, service: str):
|
||||
"""
|
||||
Get the client for a specific AWS service from configured session
|
||||
:return: Client for the AWS service.
|
||||
"""
|
||||
return self._assume_session.client(service)
|
||||
|
||||
def assume_session(self):
|
||||
return self._assume_session
|
||||
|
||||
def local_account_id(self):
|
||||
return self._local_account_id
|
||||
|
||||
def assume_account_id(self):
|
||||
return self._assume_account_id
|
||||
|
||||
def destroy(self) -> None:
|
||||
"""
|
||||
clears stored session
|
||||
"""
|
||||
self._assume_session = None
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def aws_utils(
|
||||
request: pytest.fixture,
|
||||
assume_role_arn: str,
|
||||
session_name: str,
|
||||
region_name: str):
|
||||
"""
|
||||
Fixture for setting up a Cdk
|
||||
:param request: _pytest.fixtures.SubRequest class that handles getting
|
||||
a pytest fixture from a pytest function/fixture.
|
||||
:param assume_role_arn: Role used to fetch temporary aws credentials, configure service clients with obtained credentials.
|
||||
:param session_name: Session name to set.
|
||||
:param region_name: AWS account region to set for session.
|
||||
:return AWSUtils class object.
|
||||
"""
|
||||
aws_utils_obj = AwsUtils(assume_role_arn, session_name, region_name)
|
||||
|
||||
def teardown():
|
||||
aws_utils_obj.destroy()
|
||||
|
||||
request.addfinalizer(teardown)
|
||||
|
||||
return aws_utils_obj
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
import boto3
|
||||
import pytest
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.getLogger('boto').setLevel(logging.CRITICAL)
|
||||
|
||||
|
||||
class AwsUtils:
|
||||
|
||||
def __init__(self, arn: str, session_name: str, region_name: str):
|
||||
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}')
|
||||
|
||||
response = local_sts_client.assume_role(RoleArn=arn, RoleSessionName=session_name)
|
||||
|
||||
self._assume_session = boto3.Session(aws_access_key_id=response['Credentials']['AccessKeyId'],
|
||||
aws_secret_access_key=response['Credentials']['SecretAccessKey'],
|
||||
aws_session_token=response['Credentials']['SessionToken'],
|
||||
region_name=region_name)
|
||||
|
||||
assume_sts_client = self._assume_session.client('sts')
|
||||
assume_account_id = assume_sts_client.get_caller_identity()["Account"]
|
||||
logger.info(f'Assume Account Id: {assume_account_id}')
|
||||
self._assume_account_id = assume_account_id
|
||||
|
||||
def client(self, service: str):
|
||||
"""
|
||||
Get the client for a specific AWS service from configured session
|
||||
:return: Client for the AWS service.
|
||||
"""
|
||||
return self._assume_session.client(service)
|
||||
|
||||
def resource(self, service: str):
|
||||
"""
|
||||
Get the resource for a specific AWS service from configured session
|
||||
:return: Client for the AWS service.
|
||||
"""
|
||||
return self._assume_session.resource(service)
|
||||
|
||||
def assume_session(self):
|
||||
return self._assume_session
|
||||
|
||||
def local_account_id(self):
|
||||
return self._local_account_id
|
||||
|
||||
def assume_account_id(self):
|
||||
return self._assume_account_id
|
||||
|
||||
def destroy(self) -> None:
|
||||
"""
|
||||
clears stored session
|
||||
"""
|
||||
self._assume_session = None
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def aws_utils(
|
||||
request: pytest.fixture,
|
||||
assume_role_arn: str,
|
||||
session_name: str,
|
||||
region_name: str):
|
||||
"""
|
||||
Fixture for AWS util functions
|
||||
:param request: _pytest.fixtures.SubRequest class that handles getting
|
||||
a pytest fixture from a pytest function/fixture.
|
||||
:param assume_role_arn: Role used to fetch temporary aws credentials, configure service clients with obtained credentials.
|
||||
:param session_name: Session name to set.
|
||||
:param region_name: AWS account region to set for session.
|
||||
:return AWSUtils class object.
|
||||
"""
|
||||
aws_utils_obj = AwsUtils(assume_role_arn, session_name, region_name)
|
||||
|
||||
def teardown():
|
||||
aws_utils_obj.destroy()
|
||||
|
||||
request.addfinalizer(teardown)
|
||||
|
||||
return aws_utils_obj
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
from enum import Enum
|
||||
import botocore.client
|
||||
import botocore.waiter
|
||||
import logging
|
||||
|
||||
logging.getLogger('boto').setLevel(logging.CRITICAL)
|
||||
|
||||
|
||||
class WaitState(Enum):
|
||||
SUCCESS = 'success'
|
||||
FAILURE = 'failure'
|
||||
|
||||
|
||||
class CustomWaiter:
|
||||
"""
|
||||
Base class for a custom waiter.
|
||||
|
||||
Modified from:
|
||||
https://docs.aws.amazon.com/code-samples/latest/catalog/python-demo_tools-custom_waiter.py.html
|
||||
"""
|
||||
def __init__(
|
||||
self, name: str, operation: str, argument: str,
|
||||
acceptors: dict, client: botocore.client, delay: int = 30, max_tries: int = 10,
|
||||
matcher='path'):
|
||||
"""
|
||||
Subclasses should pass specific operations, arguments, and acceptors to
|
||||
their superclass.
|
||||
|
||||
:param name: The name of the waiter. This can be any descriptive string.
|
||||
:param operation: The operation to wait for. This must match the casing of
|
||||
the underlying operation model, which is typically in
|
||||
CamelCase.
|
||||
:param argument: The dict keys used to access the result of the operation, in
|
||||
dot notation. For example, 'Job.Status' will access
|
||||
result['Job']['Status'].
|
||||
:param acceptors: The list of acceptors that indicate the wait is over. These
|
||||
can indicate either success or failure. The acceptor values
|
||||
are compared to the result of the operation after the
|
||||
argument keys are applied.
|
||||
:param client: The Boto3 client.
|
||||
:param delay: The number of seconds to wait between each call to the operation. Default to 30 seconds.
|
||||
:param max_tries: The maximum number of tries before exiting. Default to 10.
|
||||
:param matcher: The kind of matcher to use. Default to 'path'.
|
||||
"""
|
||||
self.name = name
|
||||
self.operation = operation
|
||||
self.argument = argument
|
||||
self.client = client
|
||||
self.waiter_model = botocore.waiter.WaiterModel({
|
||||
'version': 2,
|
||||
'waiters': {
|
||||
name: {
|
||||
"delay": delay,
|
||||
"operation": operation,
|
||||
"maxAttempts": max_tries,
|
||||
"acceptors": [{
|
||||
"state": state.value,
|
||||
"matcher": matcher,
|
||||
"argument": argument,
|
||||
"expected": expected
|
||||
} for expected, state in acceptors.items()]
|
||||
}}})
|
||||
self.waiter = botocore.waiter.create_waiter_with_client(
|
||||
self.name, self.waiter_model, self.client)
|
||||
|
||||
self._timeout = delay * max_tries
|
||||
|
||||
def _wait(self, **kwargs):
|
||||
"""
|
||||
Starts the botocore wait loop.
|
||||
|
||||
:param kwargs: Keyword arguments that are passed to the operation being polled.
|
||||
"""
|
||||
self.waiter.wait(**kwargs)
|
||||
|
||||
@property
|
||||
def timeout(self):
|
||||
return self._timeout
|
||||
|
||||
|
||||
@ -0,0 +1,131 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
|
||||
# fmt: off
|
||||
class Tests():
|
||||
new_event_created = ("Successfully created a new event", "Failed to create a new event")
|
||||
child_event_created = ("Successfully created Child Event", "Failed to create Child Event")
|
||||
file_saved = ("Successfully saved event asset", "Failed to save event asset")
|
||||
parameter_created = ("Successfully added parameter", "Failed to add parameter")
|
||||
parameter_removed = ("Successfully removed parameter", "Failed to remove parameter")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def ScriptEvent_AddRemoveParameter_ActionsSuccessful():
|
||||
"""
|
||||
Summary:
|
||||
Parameter can be removed from a Script Event method
|
||||
|
||||
Expected Behavior:
|
||||
Upon saving the updated .scriptevents asset the removed paramenter should no longer be present on the Script Event
|
||||
|
||||
Test Steps:
|
||||
1) Open Asset Editor
|
||||
2) Get Asset Editor Qt object
|
||||
3) Create new Script Event Asset
|
||||
4) Add Parameter to Event
|
||||
5) Remove Parameter from Event
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Open 3D Engine Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
from PySide2 import QtWidgets
|
||||
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
import editor_python_test_tools.pyside_utils as pyside_utils
|
||||
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
GENERAL_WAIT = 1.0 # seconds
|
||||
FILE_PATH = os.path.join("AutomatedTesting", "ScriptCanvas", "test_file.scriptevent")
|
||||
QtObject = object
|
||||
|
||||
def create_script_event(asset_editor: QtObject, file_path: str) -> None:
|
||||
action = pyside_utils.find_child_by_pattern(menu_bar, {"type": QtWidgets.QAction, "text": "Script Events"})
|
||||
action.trigger()
|
||||
result = helper.wait_for_condition(
|
||||
lambda: container.findChild(QtWidgets.QFrame, "Events") is not None, 3 * GENERAL_WAIT
|
||||
)
|
||||
Report.result(Tests.new_event_created, result)
|
||||
|
||||
# Add new child event
|
||||
add_event = container.findChild(QtWidgets.QFrame, "Events").findChild(QtWidgets.QToolButton, "")
|
||||
add_event.click()
|
||||
result = helper.wait_for_condition(
|
||||
lambda: asset_editor.findChild(QtWidgets.QFrame, "EventName") is not None, GENERAL_WAIT
|
||||
)
|
||||
Report.result(Tests.child_event_created, result)
|
||||
# Save the Script Event file
|
||||
editor.AssetEditorWidgetRequestsBus(bus.Broadcast, "SaveAssetAs", file_path)
|
||||
|
||||
# Verify if file is created
|
||||
result = helper.wait_for_condition(lambda: os.path.exists(file_path), 3 * GENERAL_WAIT)
|
||||
Report.result(Tests.file_saved, result)
|
||||
|
||||
def create_parameter(file_path: str) -> None:
|
||||
add_param = container.findChild(QtWidgets.QFrame, "Parameters").findChild(QtWidgets.QToolButton, "")
|
||||
add_param.click()
|
||||
result = helper.wait_for_condition(
|
||||
lambda: asset_editor_widget.findChild(QtWidgets.QFrame, "[0]") is not None, GENERAL_WAIT
|
||||
)
|
||||
Report.result(Tests.parameter_created, result)
|
||||
editor.AssetEditorWidgetRequestsBus(bus.Broadcast, "SaveAssetAs", file_path)
|
||||
|
||||
def remove_parameter(file_path: str) -> None:
|
||||
remove_param = container.findChild(QtWidgets.QFrame, "[0]").findChild(QtWidgets.QToolButton, "")
|
||||
remove_param.click()
|
||||
result = helper.wait_for_condition(
|
||||
lambda: asset_editor_widget.findChild(QtWidgets.QFrame, "[0]") is None, GENERAL_WAIT
|
||||
)
|
||||
Report.result(Tests.parameter_removed, result)
|
||||
editor.AssetEditorWidgetRequestsBus(bus.Broadcast, "SaveAssetAs", file_path)
|
||||
|
||||
# 1) Open Asset Editor
|
||||
general.idle_enable(True)
|
||||
# Initially close the Asset Editor and then reopen to ensure we don't have any existing assets open
|
||||
general.close_pane("Asset Editor")
|
||||
general.open_pane("Asset Editor")
|
||||
helper.wait_for_condition(lambda: general.is_pane_visible("Asset Editor"), 5.0)
|
||||
|
||||
# 2) Get Asset Editor Qt object
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
asset_editor_widget = editor_window.findChild(QtWidgets.QDockWidget, "Asset Editor").findChild(
|
||||
QtWidgets.QWidget, "AssetEditorWindowClass"
|
||||
)
|
||||
container = asset_editor_widget.findChild(QtWidgets.QWidget, "ContainerForRows")
|
||||
menu_bar = asset_editor_widget.findChild(QtWidgets.QMenuBar)
|
||||
|
||||
# 3) Create new Script Event Asset
|
||||
create_script_event(asset_editor_widget, FILE_PATH)
|
||||
|
||||
# 4) Add Parameter to Event
|
||||
create_parameter(FILE_PATH)
|
||||
|
||||
# 5) Remove Parameter from Event
|
||||
remove_parameter(FILE_PATH)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import ImportPathHelper as imports
|
||||
|
||||
imports.init()
|
||||
from editor_python_test_tools.utils import Report
|
||||
|
||||
Report.start_test(ScriptEvent_AddRemoveParameter_ActionsSuccessful)
|
||||
@ -0,0 +1,210 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
|
||||
# fmt: off
|
||||
class Tests():
|
||||
new_event_created = ("New Script Event created", "New Script Event not created")
|
||||
child_event_created = ("Child Event created", "Child Event not created")
|
||||
params_added = ("New parameters added", "New parameters are not added")
|
||||
file_saved = ("Script event file saved", "Script event file did not save")
|
||||
node_found = ("Node found in Script Canvas", "Node not found in Script Canvas")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def ScriptEvents_AllParamDatatypes_CreationSuccess():
|
||||
"""
|
||||
Summary:
|
||||
Parameters of all types can be created.
|
||||
|
||||
Expected Behavior:
|
||||
The Method handles the large number of Parameters gracefully.
|
||||
Parameters of all data types can be successfully created.
|
||||
Updated ScriptEvent toast appears in Script Canvas.
|
||||
|
||||
Test Steps:
|
||||
1) Open Asset Editor
|
||||
2) Initially create new Script Event file with one method
|
||||
3) Add new method and set name to it
|
||||
4) Add new parameters of each type
|
||||
5) Verify if parameters are added
|
||||
6) Expand the parameter rows
|
||||
7) Set different names and datatypes for each parameter
|
||||
8) Save file and verify node in SC Node Palette
|
||||
9) Close Asset Editor
|
||||
|
||||
Note:
|
||||
- This test file must be called from the Open 3D Engine Editor command terminal
|
||||
- Any passed and failed tests are written to the Editor.log file.
|
||||
Parsing the file or running a log_monitor are required to observe the test results.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
import os
|
||||
from utils import TestHelper as helper
|
||||
import pyside_utils
|
||||
|
||||
# Open 3D Engine imports
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.bus as bus
|
||||
|
||||
# Pyside imports
|
||||
from PySide2 import QtWidgets, QtTest, QtCore
|
||||
|
||||
GENERAL_WAIT = 1.0 # seconds
|
||||
|
||||
FILE_PATH = os.path.join("AutomatedTesting", "TestAssets", "test_file.scriptevents")
|
||||
N_VAR_TYPES = 10 # Top 10 variable types
|
||||
TEST_METHOD_NAME = "test_method_name"
|
||||
|
||||
editor_window = pyside_utils.get_editor_main_window()
|
||||
asset_editor = asset_editor_widget = container = menu_bar = None
|
||||
sc = node_palette = tree = search_frame = search_box = None
|
||||
|
||||
def initialize_asset_editor_qt_objects():
|
||||
nonlocal asset_editor, asset_editor_widget, container, menu_bar
|
||||
asset_editor = editor_window.findChild(QtWidgets.QDockWidget, "Asset Editor")
|
||||
asset_editor_widget = asset_editor.findChild(QtWidgets.QWidget, "AssetEditorWindowClass")
|
||||
container = asset_editor_widget.findChild(QtWidgets.QWidget, "ContainerForRows")
|
||||
menu_bar = asset_editor_widget.findChild(QtWidgets.QMenuBar)
|
||||
|
||||
def initialize_sc_qt_objects():
|
||||
nonlocal sc, node_palette, tree, search_frame, search_box
|
||||
sc = editor_window.findChild(QtWidgets.QDockWidget, "Script Canvas")
|
||||
if sc.findChild(QtWidgets.QDockWidget, "NodePalette") is None:
|
||||
action = pyside_utils.find_child_by_pattern(sc, {"text": "Node Palette", "type": QtWidgets.QAction})
|
||||
action.trigger()
|
||||
node_palette = sc.findChild(QtWidgets.QDockWidget, "NodePalette")
|
||||
tree = node_palette.findChild(QtWidgets.QTreeView, "treeView")
|
||||
search_frame = node_palette.findChild(QtWidgets.QFrame, "searchFrame")
|
||||
search_box = search_frame.findChild(QtWidgets.QLineEdit, "searchFilter")
|
||||
|
||||
def save_file():
|
||||
editor.AssetEditorWidgetRequestsBus(bus.Broadcast, "SaveAssetAs", FILE_PATH)
|
||||
action = pyside_utils.find_child_by_pattern(menu_bar, {"type": QtWidgets.QAction, "iconText": "Save"})
|
||||
action.trigger()
|
||||
# wait till file is saved, to validate that check the text of QLabel at the bottom of the AssetEditor,
|
||||
# if there are no unsaved changes we will not have any * in the text
|
||||
label = asset_editor.findChild(QtWidgets.QLabel, "textEdit")
|
||||
return helper.wait_for_condition(lambda: "*" not in label.text(), 3.0)
|
||||
|
||||
def expand_container_rows(object_name):
|
||||
children = container.findChildren(QtWidgets.QFrame, object_name)
|
||||
for child in children:
|
||||
check_box = child.findChild(QtWidgets.QCheckBox)
|
||||
if check_box and not check_box.isChecked():
|
||||
QtTest.QTest.mouseClick(check_box, QtCore.Qt.LeftButton, QtCore.Qt.NoModifier)
|
||||
|
||||
def node_palette_search(node_name):
|
||||
search_box.setText(node_name)
|
||||
helper.wait_for_condition(lambda: search_box.text() == node_name, 1.0)
|
||||
# Try clicking ENTER in search box multiple times
|
||||
for _ in range(20):
|
||||
QtTest.QTest.keyClick(search_box, QtCore.Qt.Key_Enter, QtCore.Qt.NoModifier)
|
||||
if pyside_utils.find_child_by_pattern(tree, {"text": node_name}) is not None:
|
||||
break
|
||||
|
||||
def verify_added_params():
|
||||
for index in range(N_VAR_TYPES):
|
||||
if container.findChild(QtWidgets.QFrame, f"[{index}]") is None:
|
||||
return False
|
||||
return True
|
||||
|
||||
# 1) Open Asset Editor
|
||||
general.idle_enable(True)
|
||||
# Initially close the Asset Editor and then reopen to ensure we don't have any existing assets open
|
||||
general.close_pane("Asset Editor")
|
||||
general.open_pane("Asset Editor")
|
||||
helper.wait_for_condition(lambda: general.is_pane_visible("Asset Editor"), 5.0)
|
||||
|
||||
# 2) Initially create new Script Event file with one method
|
||||
initialize_asset_editor_qt_objects()
|
||||
action = pyside_utils.find_child_by_pattern(menu_bar, {"type": QtWidgets.QAction, "text": "Script Events"})
|
||||
action.trigger()
|
||||
result = helper.wait_for_condition(
|
||||
lambda: container.findChild(QtWidgets.QFrame, "Events") is not None
|
||||
and container.findChild(QtWidgets.QFrame, "Events").findChild(QtWidgets.QToolButton, "") is not None,
|
||||
3 * GENERAL_WAIT,
|
||||
)
|
||||
Report.result(Tests.new_event_created, result)
|
||||
|
||||
# 3) Add new method and set name to it
|
||||
add_event = container.findChild(QtWidgets.QFrame, "Events").findChild(QtWidgets.QToolButton, "")
|
||||
add_event.click()
|
||||
result = helper.wait_for_condition(
|
||||
lambda: asset_editor_widget.findChild(QtWidgets.QFrame, "EventName") is not None, GENERAL_WAIT
|
||||
)
|
||||
Report.result(Tests.child_event_created, result)
|
||||
expand_container_rows("EventName")
|
||||
expand_container_rows("Name")
|
||||
initialize_asset_editor_qt_objects()
|
||||
children = container.findChildren(QtWidgets.QFrame, "Name")
|
||||
for child in children:
|
||||
line_edit = child.findChild(QtWidgets.QLineEdit)
|
||||
if line_edit is not None and line_edit.text() == "MethodName":
|
||||
line_edit.setText(TEST_METHOD_NAME)
|
||||
|
||||
# 4) Add new parameters of each type
|
||||
helper.wait_for_condition(lambda: container.findChild(QtWidgets.QFrame, "Parameters") is not None, 2.0)
|
||||
parameters = container.findChild(QtWidgets.QFrame, "Parameters")
|
||||
add_param = parameters.findChild(QtWidgets.QToolButton, "")
|
||||
for _ in range(N_VAR_TYPES):
|
||||
add_param.click()
|
||||
|
||||
# 5) Verify if parameters are added
|
||||
result = helper.wait_for_condition(verify_added_params, 3.0)
|
||||
Report.result(Tests.params_added, result)
|
||||
|
||||
# 6) Expand the parameter rows (to render QFrame 'Type' for each param)
|
||||
for index in range(N_VAR_TYPES):
|
||||
expand_container_rows(f"[{index}]")
|
||||
|
||||
# 7) Set different names and datatypes for each parameter
|
||||
expand_container_rows("Name")
|
||||
children = container.findChildren(QtWidgets.QFrame, "Name")
|
||||
index = 0
|
||||
for child in children:
|
||||
line_edit = child.findChild(QtWidgets.QLineEdit)
|
||||
if line_edit is not None and line_edit.text() == "ParameterName":
|
||||
line_edit.setText(f"param_{index}")
|
||||
index += 1
|
||||
|
||||
children = container.findChildren(QtWidgets.QFrame, "Type")
|
||||
index = 0
|
||||
for child in children:
|
||||
combo_box = child.findChild(QtWidgets.QComboBox)
|
||||
if combo_box is not None and index < N_VAR_TYPES:
|
||||
combo_box.setCurrentIndex(index)
|
||||
index += 1
|
||||
|
||||
# 8) Save file and verify node in SC Node Palette
|
||||
Report.result(Tests.file_saved, save_file())
|
||||
general.open_pane("Script Canvas")
|
||||
helper.wait_for_condition(lambda: general.is_pane_visible("Script Canvas"), 5.0)
|
||||
initialize_sc_qt_objects()
|
||||
node_palette_search(TEST_METHOD_NAME)
|
||||
get_node_index = lambda: pyside_utils.find_child_by_pattern(tree, {"text": TEST_METHOD_NAME}) is not None
|
||||
result = helper.wait_for_condition(get_node_index, 2.0)
|
||||
Report.result(Tests.node_found, result)
|
||||
|
||||
# 9) Close Asset Editor
|
||||
general.close_pane("Asset Editor")
|
||||
general.close_pane("Script Canvas")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import ImportPathHelper as imports
|
||||
|
||||
imports.init()
|
||||
from utils import Report
|
||||
|
||||
Report.start_test(ScriptEvents_AllParamDatatypes_CreationSuccess)
|
||||
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:804193a2afd68cd1e6bec8155ea11400566f2941fbd6eb0c324839ebcd10192d
|
||||
size 8492
|
||||
oid sha256:302d6172156e8ed665e44e206d81f54f1b0f1008d73327300ea92f8c1159780b
|
||||
size 11820
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d49aceca5ad4e0b9f46c8127afb5c53b68aa30272950b1abd66fba310977ff0c
|
||||
size 15032
|
||||
@ -1,6 +0,0 @@
|
||||
<download name="blank2" type="Map">
|
||||
<index src="filelist.xml" dest="filelist.xml"/>
|
||||
<files>
|
||||
<file src="level.pak" dest="level.pak" size="39815" md5="3874c8411da272b96974e24a9fff06e8"/>
|
||||
</files>
|
||||
</download>
|
||||
@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5f221acd847ec8a15e1333a5163d6d0fd886b8eda46fa7b133f76ddbf1d11216
|
||||
size 41472
|
||||
@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c8e5dcfbe65fd2fd8ea29a38a96e703683c544fd42b9424857b1df3718c7775a
|
||||
size 41472
|
||||
@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0378911c27933302042550d5a031a5f9104296162edc2b21e44893f1b8cff969
|
||||
size 44124
|
||||
@ -1,14 +0,0 @@
|
||||
<Environment>
|
||||
<Fog ViewDistance="8000" ViewDistanceLowSpec="1000" LDRGlobalDensMult="1.0"/>
|
||||
<Terrain DetailLayersViewDistRatio="1.0" HeightMapAO="0"/>
|
||||
<EnvState WindVector="1,0,0" BreezeGeneration="0" BreezeStrength="1.f" BreezeMovementSpeed="8.f" BreezeVariation="1.f" BreezeLifeTime="15.f" BreezeCount="4" BreezeSpawnRadius="25.f" BreezeSpread="0.f" BreezeRadius="5.f" ConsoleMergedMeshesPool="2750" ShowTerrainSurface="1" SunShadowsMinSpec="1" SunShadowsAdditionalCascadeMinSpec="0" SunShadowsClipPlaneRange="256.0f" SunShadowsClipPlaneRangeShift="0.0f" UseLayersActivation="0" SunLinkedToTOD="1"/>
|
||||
<VolFogShadows Enable="0" EnableForClouds="0"/>
|
||||
<CloudShadows CloudShadowTexture="" CloudShadowSpeed="0,0,0" CloudShadowTiling="1.0" CloudShadowBrightness="1.0" CloudShadowInvert="0"/>
|
||||
<ParticleLighting AmbientMul="1.0" LightsMul="1.0"/>
|
||||
<SkyBox Material="EngineAssets/Materials/Sky/Sky" MaterialLowSpec="EngineAssets/Materials/Sky/Sky" Angle="0" Stretching="0.5"/>
|
||||
<Ocean Material="EngineAssets/Materials/Water/Ocean_default" CausticsDistanceAtten="100.0" CausticDepth="8.0" CausticIntensity="1.0" CausticsTilling="1.0"/>
|
||||
<OceanAnimation WindDirection="1.0" WindSpeed="4.0" WavesAmount="1.5" WavesSize="0.4" WavesSpeed="1.0"/>
|
||||
<Moon Latitude="240.0" Longitude="45.0" Size="0.5" Texture="Textures/Skys/Night/half_moon.dds"/>
|
||||
<DynTexSource Width="256" Height="256"/>
|
||||
<Total_Illumination_v2 Active="0" IntegrationMode="0" InjectionMultiplier="1.0" SkyColorMultiplier="1.0" UseTODSkyColor="0.5" PortalsDeform="0" PortalsInject="0" DiffuseAmplifier="1.0" SpecularAmplifier="0" NumberOfBounces="1" Saturation="0.8" PropagationBooster="1.5" DiffuseBias="0.05" DiffuseConeWidth="24" ConeMaxLength="12.0" UpdateLighting="0" UpdateGeometry="0" MinNodeSize="8.0" SkipNonGILights="0" LowSpecMode="0" HalfresKernel="0" UseLightProbes="0" VoxelizaionLODRatio="1.8" VoxelPoolResolution="128" SSAOAmount="0.7" ObjectsMaxViewDistance="64" SunRSMInject="0" SSDepthTrace="0"/>
|
||||
</Environment>
|
||||
@ -1,7 +0,0 @@
|
||||
<TerrainTexture TileCountX="1" TileCountY="1" TileResolution="512">
|
||||
<RGBLayer>
|
||||
<Tiles>
|
||||
<tile />
|
||||
</Tiles>
|
||||
</RGBLayer>
|
||||
</TerrainTexture>
|
||||
@ -1,356 +0,0 @@
|
||||
<TimeOfDay Time="12" TimeStart="12" TimeEnd="12" TimeAnimSpeed="0">
|
||||
<Variable Name="Sun color" Color="0.94730699,0.74540401,0.57758099">
|
||||
<Spline Keys="-0.000628322:(0.783538:0.89627:0.930341):36,0:(0.783538:0.887923:0.921582):36,0.229167:(0.783538:0.879623:0.921582):36,0.25:(0.947307:0.745404:0.577581):36,0.5:(0.947307:0.745404:0.577581):262180,0.75:(0.947307:0.745404:0.577581):36,0.770833:(0.783538:0.879623:0.921582):36,1:(0.783538:0.89627:0.930556):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sun intensity" Value="120000">
|
||||
<Spline Keys="0:1000:36,0.229167:1000:36,0.5:120000:36,0.770833:1000:65572,0.999306:1000:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sun specular multiplier" Value="1">
|
||||
<Spline Keys="0:1:36,0.25:1:36,0.5:1:36,0.75:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Fog color" Color="0.27049801,0.47353199,0.83077002">
|
||||
<Spline Keys="0:(0.00651209:0.00972122:0.0137021):36,0.229167:(0.00604883:0.00972122:0.0137021):36,0.25:(0.270498:0.473532:0.83077):36,0.5:(0.270498:0.473532:0.83077):458788,0.75:(0.270498:0.473532:0.83077):36,0.770833:(0.00604883:0.00972122:0.0137021):36,1:(0.00651209:0.00972122:0.0137021):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Fog color multiplier" Value="1">
|
||||
<Spline Keys="0:0.5:36,0.229167:0.5:36,0.25:1:36,0.5:1:36,0.75:1:36,0.770833:0.5:36,1:0.5:65572,"/>
|
||||
</Variable>
|
||||
<Variable Name="Fog height (bottom)" Value="0">
|
||||
<Spline Keys="0:0:36,0.25:0:36,0.5:0:36,0.75:0:36,1:0:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Fog layer density (bottom)" Value="1">
|
||||
<Spline Keys="0:1:36,0.25:1:36,0.5:1:36,0.75:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Fog color (top)" Color="0.597202,0.72305501,0.91309899">
|
||||
<Spline Keys="0:(0.00699541:0.00972122:0.0122865):36,0.229167:(0.00699541:0.00972122:0.0122865):36,0.25:(0.597202:0.723055:0.913099):36,0.5:(0.597202:0.723055:0.913099):458788,0.75:(0.597202:0.723055:0.913099):36,0.770833:(0.00699541:0.00972122:0.0122865):36,1:(0.00699541:0.00972122:0.0122865):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Fog color (top) multiplier" Value="1">
|
||||
<Spline Keys="-4.40702e-06:0.5:36,0.0297507:0.499195:36,0.229167:0.5:36,0.5:1:36,0.770833:0.5:36,1:0.5:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Fog height (top)" Value="100">
|
||||
<Spline Keys="0:100:36,0.25:100:36,0.5:100:36,0.75:100:65572,1:100:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Fog layer density (top)" Value="9.9999997e-05">
|
||||
<Spline Keys="0:0.0001:36,0.25:0.0001:36,0.5:0.0001:65572,0.75:0.0001:36,1:0.0001:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Fog color height offset" Value="0">
|
||||
<Spline Keys="0:0:36,0.25:0:36,0.5:0:36,0.75:0:36,1:0:65572,"/>
|
||||
</Variable>
|
||||
<Variable Name="Fog color (radial)" Color="0.76815099,0.51491803,0.16826899">
|
||||
<Spline Keys="0:(0:0:0):36,0.229167:(0.00439144:0.00367651:0.00334654):36,0.25:(0.838799:0.564712:0.184475):36,0.5:(0.768151:0.514918:0.168269):458788,0.75:(0.838799:0.564712:0.184475):36,0.770833:(0.00402472:0.00334654:0.00303527):36,1:(0:0:0):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Fog color (radial) multiplier" Value="6">
|
||||
<Spline Keys="0:0:36,0.25:6:36,0.5:6:36,0.75:6:36,1:0:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Fog radial size" Value="0.85000002">
|
||||
<Spline Keys="0:0:36,0.25:0.85:65572,0.5:0.85:36,0.75:0.85:36,1:0:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Fog radial lobe" Value="0.75">
|
||||
<Spline Keys="0:0:36,0.25:0.75:36,0.5:0.75:36,0.75:0.75:65572,1:0:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog: Final density clamp" Value="1">
|
||||
<Spline Keys="0:1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog: Global density" Value="1.5">
|
||||
<Spline Keys="0:1.5:36,0.25:1.5:36,0.5:1.5:65572,0.75:1.5:36,1:1.5:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog: Ramp start" Value="25">
|
||||
<Spline Keys="0:25:36,0.25:25:36,0.5:25:65572,0.75:25:36,1:25:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog: Ramp end" Value="1000">
|
||||
<Spline Keys="0:1000:36,0.25:1000:36,0.5:1000:65572,0.75:1000:36,1:1000:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog: Ramp influence" Value="0.69999999">
|
||||
<Spline Keys="0:0.7:36,0.25:0.7:36,0.5:0.7:65572,0.75:0.7:36,1:0.7:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog: Shadow darkening" Value="0.2">
|
||||
<Spline Keys="0:0.2:36,0.25:0.2:36,0.5:0.2:65572,0.75:0.2:36,1:0.2:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog: Shadow darkening sun" Value="0.5">
|
||||
<Spline Keys="0:0.5:36,0.25:0.5:36,0.5:0.5:65572,0.75:0.5:36,1:0.5:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog: Shadow darkening ambient" Value="1">
|
||||
<Spline Keys="0:1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog: Shadow range" Value="0.1">
|
||||
<Spline Keys="0:0.1:36,0.25:0.1:36,0.5:0.1:65572,0.75:0.1:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Fog height (bottom)" Value="0">
|
||||
<Spline Keys="0:0:0,1:0:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Fog layer density (bottom)" Value="1">
|
||||
<Spline Keys="0:1:0,1:1:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Fog height (top)" Value="4000">
|
||||
<Spline Keys="0:4000:0,1:4000:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Fog layer density (top)" Value="9.9999997e-05">
|
||||
<Spline Keys="0:0.0001:0,1:0.0001:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Global fog density" Value="0.10000001">
|
||||
<Spline Keys="0:0.1:0,1:0.1:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Ramp start" Value="0">
|
||||
<Spline Keys="0:0:0,1:0:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Ramp end" Value="0">
|
||||
<Spline Keys="0:0:0,1:0:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Fog albedo color (atmosphere)" Color="1,1,1">
|
||||
<Spline Keys="0:(1:1:1):0,1:(1:1:1):0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Anisotropy factor (atmosphere)" Value="0.60000002">
|
||||
<Spline Keys="0:0.6:0,1:0.6:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Fog albedo color (sun radial)" Color="1,1,1">
|
||||
<Spline Keys="0:(1:1:1):0,1:(1:1:1):0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Anisotropy factor (sun radial)" Value="0.94999993">
|
||||
<Spline Keys="0:0.95:0,1:0.95:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Blend factor for sun scattering" Value="1">
|
||||
<Spline Keys="0:1:0,1:1:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Blend mode for sun scattering" Value="0">
|
||||
<Spline Keys="0:0:0,1:0:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Fog albedo color (entities)" Color="1,1,1">
|
||||
<Spline Keys="0:(1:1:1):0,1:(1:1:1):0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Anisotropy factor (entities)" Value="0.60000002">
|
||||
<Spline Keys="0:0.6:0,1:0.6:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Maximum range of ray-marching" Value="64">
|
||||
<Spline Keys="0:64:0,1:64:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: In-scattering factor" Value="1">
|
||||
<Spline Keys="0:1:0,1:1:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Extinction factor" Value="0.30000001">
|
||||
<Spline Keys="0:0.3:0,1:0.3:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Analytical volumetric fog visibility" Value="0.5">
|
||||
<Spline Keys="0:0.5:0,1:0.5:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Volumetric fog 2: Final density clamp" Value="1">
|
||||
<Spline Keys="0:1:0,0.5:1:36,1:1:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sky light: Sun intensity" Color="1,1,1">
|
||||
<Spline Keys="0:(1:1:1):36,0.25:(1:1:1):36,0.494381:(1:1:1):65572,0.5:(1:1:1):36,0.75:(1:1:1):36,1:(1:1:1):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sky light: Sun intensity multiplier" Value="200">
|
||||
<Spline Keys="0:200:36,0.25:200:36,0.5:200:36,0.75:200:36,1:200:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sky light: Mie scattering" Value="2">
|
||||
<Spline Keys="0:40:36,0.5:2:36,1:40:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sky light: Rayleigh scattering" Value="0.2">
|
||||
<Spline Keys="0:0.2:36,0.229167:0.2:36,0.25:1:36,0.291667:0.2:36,0.5:0.2:36,0.729167:0.2:36,0.75:1:36,0.770833:0.2:36,1:0.2:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sky light: Sun anisotropy factor" Value="-0.99989998">
|
||||
<Spline Keys="0:-0.9999:36,0.25:-0.9999:36,0.5:-0.9999:65572,0.75:-0.9999:36,1:-0.9999:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sky light: Wavelength (R)" Value="694">
|
||||
<Spline Keys="0:694:36,0.25:694:36,0.5:694:65572,0.75:694:36,1:694:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sky light: Wavelength (G)" Value="597">
|
||||
<Spline Keys="0:597:36,0.25:597:36,0.5:597:36,0.75:597:36,1:597:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sky light: Wavelength (B)" Value="488">
|
||||
<Spline Keys="0:488:36,0.25:488:36,0.5:488:65572,0.75:488:36,1:488:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Horizon color" Color="0.27049801,0.39157301,0.52711499">
|
||||
<Spline Keys="0:(0.270498:0.391573:0.520996):36,0.25:(0.270498:0.391573:0.527115):36,0.5:(0.270498:0.391573:0.527115):262180,0.75:(0.270498:0.391573:0.527115):36,1:(0.270498:0.391573:0.520996):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Horizon color multiplier" Value="0">
|
||||
<Spline Keys="0:0.1:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Zenith color" Color="0.361307,0.434154,0.46778399">
|
||||
<Spline Keys="0:(0.361307:0.434154:0.467784):36,0.25:(0.361307:0.434154:0.467784):36,0.5:(0.361307:0.434154:0.467784):262180,0.75:(0.361307:0.434154:0.467784):36,1:(0.361307:0.434154:0.467784):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Zenith color multiplier" Value="0">
|
||||
<Spline Keys="0:0.02:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0.02:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Zenith shift" Value="0.5">
|
||||
<Spline Keys="0:0.5:36,0.25:0.5:36,0.5:0.5:65572,0.75:0.5:36,1:0.5:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Star intensity" Value="0">
|
||||
<Spline Keys="0:3:36,0.25:0:36,0.5:0:65572,0.75:0:36,0.836647:1.03977:36,1:3:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Moon color" Color="1,1,1">
|
||||
<Spline Keys="0:(1:1:1):36,0.25:(1:1:1):36,0.5:(1:1:1):458788,0.75:(1:1:1):36,1:(1:1:1):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Moon color multiplier" Value="0">
|
||||
<Spline Keys="0:0.4:36,0.25:0:36,0.5:0:36,0.75:0:65572,1:0.4:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Moon inner corona color" Color="0.904661,1,1">
|
||||
<Spline Keys="0:(0.89627:1:1):36,0.25:(0.904661:1:1):36,0.5:(0.904661:1:1):393252,0.75:(0.904661:1:1):36,0.836647:(0.89627:1:1):36,1:(0.89627:1:1):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Moon inner corona color multiplier" Value="0">
|
||||
<Spline Keys="0:0.1:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Moon inner corona scale" Value="0">
|
||||
<Spline Keys="0:2:36,0.25:0:36,0.5:0:65572,0.75:0:36,0.836647:0.693178:36,1:2:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Moon outer corona color" Color="0.201556,0.22696599,0.254152">
|
||||
<Spline Keys="0:(0.198069:0.226966:0.250158):36,0.25:(0.201556:0.226966:0.254152):36,0.5:(0.201556:0.226966:0.254152):36,0.75:(0.201556:0.226966:0.254152):36,1:(0.198069:0.226966:0.250158):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Moon outer corona color multiplier" Value="0">
|
||||
<Spline Keys="0:0.1:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Night sky: Moon outer corona scale" Value="0">
|
||||
<Spline Keys="0:0.01:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0.01:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cloud shading: Sun light multiplier" Value="1">
|
||||
<Spline Keys="0:1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cloud shading: Sun custom color" Color="0.83077002,0.76815099,0.65837502">
|
||||
<Spline Keys="0:(0.737911:0.737911:0.737911):36,0.25:(0.83077:0.768151:0.658375):36,0.5:(0.83077:0.768151:0.658375):458788,0.75:(0.83077:0.768151:0.658375):36,1:(0.737911:0.737911:0.737911):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cloud shading: Sun custom color multiplier" Value="1">
|
||||
<Spline Keys="0:0.1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cloud shading: Sun custom color influence" Value="0">
|
||||
<Spline Keys="0:0.5:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0.5:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sun shafts visibility" Value="0">
|
||||
<Spline Keys="0:0:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sun rays visibility" Value="1.5">
|
||||
<Spline Keys="0:1:36,0.25:1.5:36,0.5:1.5:65572,0.75:1.5:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sun rays attenuation" Value="1.5">
|
||||
<Spline Keys="0:0.1:36,0.25:1.5:36,0.5:1.5:65572,0.75:1.5:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sun rays suncolor influence" Value="0.5">
|
||||
<Spline Keys="0:0.5:36,0.25:0.5:36,0.5:0.5:65572,0.75:0.5:36,1:0.5:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sun rays custom color" Color="0.66538697,0.838799,0.94730699">
|
||||
<Spline Keys="0:(0.665387:0.838799:0.947307):36,0.25:(0.665387:0.838799:0.947307):36,0.5:(0.665387:0.838799:0.947307):458788,0.75:(0.665387:0.838799:0.947307):36,1:(0.665387:0.838799:0.947307):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Ocean fog color" Color="0.0012141099,0.0091340598,0.017642001">
|
||||
<Spline Keys="0:(0.00121411:0.00913406:0.017642):36,0.25:(0.00121411:0.00913406:0.017642):36,0.5:(0.00121411:0.00913406:0.017642):458788,0.75:(0.00121411:0.00913406:0.017642):36,1:(0.00121411:0.00913406:0.017642):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Ocean fog color multiplier" Value="0.5">
|
||||
<Spline Keys="0:0.5:36,0.25:0.5:36,0.5:0.5:65572,0.75:0.5:36,1:0.5:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Ocean fog density" Value="0.5">
|
||||
<Spline Keys="0:0.5:36,0.25:0.5:36,0.5:0.5:65572,0.75:0.5:36,1:0.5:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Skybox multiplier" Value="1">
|
||||
<Spline Keys="0:1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Film curve shoulder scale" Value="2">
|
||||
<Spline Keys="0:3:36,0.229167:3:36,0.5:2:36,0.770833:3:36,1:3:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Film curve midtones scale" Value="1">
|
||||
<Spline Keys="0:0.5:36,0.229167:0.5:36,0.5:1:36,0.770833:0.5:36,1:0.5:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Film curve toe scale" Value="1">
|
||||
<Spline Keys="0:1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Film curve whitepoint" Value="4">
|
||||
<Spline Keys="0:4:36,0.25:4:36,0.5:4:65572,0.75:4:36,1:4:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Saturation" Value="1">
|
||||
<Spline Keys="0:0.8:36,0.229167:0.8:36,0.5:1:36,0.751391:1:65572,0.770833:0.8:36,1:0.8:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Color balance" Color="1,1,1">
|
||||
<Spline Keys="0:(1:1:1):36,0.25:(1:1:1):36,0.5:(1:1:1):36,0.75:(1:1:1):36,1:(1:1:1):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Scene key" Value="0.18000001">
|
||||
<Spline Keys="0:0.18:36,0.25:0.18:36,0.5:0.18:65572,0.75:0.18:36,1:0.18:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Min exposure" Value="1">
|
||||
<Spline Keys="0:1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Max exposure" Value="2.8">
|
||||
<Spline Keys="0:2:36,0.229167:2:36,0.5:2.8:36,0.770833:2:36,1:2:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="EV Min" Value="4.5">
|
||||
<Spline Keys="0:4.5:0,1:4.5:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="EV Max" Value="17">
|
||||
<Spline Keys="0:17:0,1:17:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="EV Auto compensation" Value="1.5">
|
||||
<Spline Keys="0:1.5:0,1:1.5:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="Bloom amount" Value="0.1">
|
||||
<Spline Keys="0:1:36,0.229167:1:36,0.5:0.1:36,0.770833:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Filters: grain" Value="0">
|
||||
<Spline Keys="0:0.3:65572,0.229167:0.3:36,0.25:0:36,0.5:0:36,0.75:0:36,1:0.3:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Filters: photofilter color" Color="0,0,0">
|
||||
<Spline Keys="0:(0:0:0):36,0.25:(0:0:0):36,0.5:(0:0:0):458788,0.75:(0:0:0):36,1:(0:0:0):36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Filters: photofilter density" Value="0">
|
||||
<Spline Keys="0:0:36,0.25:0:36,0.5:0:36,0.75:0:36,1:0:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Dof: focus range" Value="500">
|
||||
<Spline Keys="0:500:36,0.25:500:36,0.5:500:65572,0.75:500:36,1:500:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Dof: blur amount" Value="0.1">
|
||||
<Spline Keys="0:0.1:36,0.25:0.1:36,0.5:0.1:65572,0.75:0.1:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 0: Bias" Value="0.1">
|
||||
<Spline Keys="0:0.1:36,0.25:0.1:36,0.5:0.1:65572,0.75:0.1:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 0: Slope Bias" Value="64">
|
||||
<Spline Keys="0:64:36,0.25:64:36,0.5:64:65572,0.75:64:36,1:64:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 1: Bias" Value="0.1">
|
||||
<Spline Keys="0:0.1:36,0.25:0.1:36,0.5:0.1:65572,0.75:0.1:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 1: Slope Bias" Value="8">
|
||||
<Spline Keys="0:8:36,0.25:8:36,0.5:8:65572,0.75:8:36,1:8:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 2: Bias" Value="0.1">
|
||||
<Spline Keys="0:0.1:36,0.25:0.1:36,0.5:0.1:65572,0.75:0.1:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 2: Slope Bias" Value="4">
|
||||
<Spline Keys="0:4:36,0.25:4:36,0.5:4:65572,0.75:4:36,1:4:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 3: Bias" Value="0.1">
|
||||
<Spline Keys="0:0.1:36,0.25:0.1:36,0.5:0.1:36,0.75:0.1:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 3: Slope Bias" Value="1">
|
||||
<Spline Keys="0:1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 4: Bias" Value="0.1">
|
||||
<Spline Keys="0:0.1:0,0.25:0.1:36,0.5:0.1:65572,0.75:0.1:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 4: Slope Bias" Value="1">
|
||||
<Spline Keys="0:1:0,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 5: Bias" Value="0.0099999998">
|
||||
<Spline Keys="0:0.01:0,0.25:0.01:36,0.5:0.01:65572,0.75:0.01:36,1:0.01:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 5: Slope Bias" Value="1">
|
||||
<Spline Keys="0:1:0,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 6: Bias" Value="0.1">
|
||||
<Spline Keys="0:0.1:0,0.25:0.1:36,0.5:0.1:36,0.75:0.1:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 6: Slope Bias" Value="1">
|
||||
<Spline Keys="0:1:0,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 7: Bias" Value="0.1">
|
||||
<Spline Keys="0:0.1:0,0.25:0.1:36,0.5:0.1:36,0.75:0.1:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Cascade 7: Slope Bias" Value="1">
|
||||
<Spline Keys="0:1:0,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Shadow jittering" Value="2.5">
|
||||
<Spline Keys="0:5:36,0.25:2.5:36,0.5:2.5:65572,0.75:2.5:36,1:5:0,"/>
|
||||
</Variable>
|
||||
<Variable Name="HDR dynamic power factor" Value="0">
|
||||
<Spline Keys="0:0:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sky brightening (terrain occlusion)" Value="0">
|
||||
<Spline Keys="0:0:36,0.25:0:36,0.5:0:36,0.75:0:36,1:0:36,"/>
|
||||
</Variable>
|
||||
<Variable Name="Sun color multiplier" Value="10">
|
||||
<Spline Keys="0:0.1:36,0.25:10:36,0.5:10:36,0.75:10:36,1:0.1:36,"/>
|
||||
</Variable>
|
||||
</TimeOfDay>
|
||||
@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0e6a5435c928079b27796f6b202bbc2623e7e454244ddc099a3cadf33b7cb9e9
|
||||
size 63
|
||||
@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:12ca8f1942331abde4d58724aea22609c8d7951cc415afa6e5f1c550a14e67b0
|
||||
size 363624
|
||||
@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f5b525a410730d84c0b3e97396d392e1e72f4b894742ddef3de4ede5542b0f8e
|
||||
size 86148
|
||||
@ -1,12 +0,0 @@
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8739c76e681f900923b900c9df0ef75cf421d39cabb54650c4b9ad19b6a76d85
|
||||
size 22
|
||||
@ -1,7 +0,0 @@
|
||||
<Material MtlFlags="2623488" Shader="Watervolume" GenMask="80000013" StringGenMask="" SurfaceType="mat_water" Diffuse="1,1,1,1" Specular="0.27583286,0.27583286,0.27583286,1" Opacity="1" Shininess="255" vertModifType="0" LayerAct="1">
|
||||
<Textures>
|
||||
<Texture Map="Specular" File="engineassets/textures/water_gloss.dds" Filter="7"/>
|
||||
<Texture Map="Environment" File="nearest_cubemap" TexType="7"/>
|
||||
</Textures>
|
||||
<PublicParams NormalsScale="0.5" GlossMapTilling="1" SoftIntersectionFactor="1" Tilling="0.1" DetailNormalsScale="0.5" GlossMapBias="0" EnvCubeReflMul="16" VertexWaveScale="0.125" DetailTilling="2.5" EnvCubeScale="16" GlossMapScale="1.5" RealtimeReflMul="1" RainTilling="1" WaterFlowSpeed="0.5"/>
|
||||
</Material>
|
||||
@ -1 +1 @@
|
||||
/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce="es3:1,ios:1,osx_gl:0,pc:0,provo:0"
|
||||
/autooptimizefile=0 /M=50,50,0,50,50,50 /preset=NormalsWithSmoothness /reduce="android:1,ios:1,mac:0,pc:0,provo:0"
|
||||
@ -0,0 +1,118 @@
|
||||
{
|
||||
"Amazon": {
|
||||
"Gems": {
|
||||
"PhysX": {
|
||||
"PhysXSystemConfiguration": {
|
||||
"CollisionConfig": {
|
||||
"Layers": {
|
||||
"LayerNames": [
|
||||
"Default",
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
"TouchBend"
|
||||
]
|
||||
},
|
||||
"Groups": {
|
||||
"GroupPresets": [
|
||||
{
|
||||
"Name": "All",
|
||||
"ReadOnly": true
|
||||
},
|
||||
{
|
||||
"Id": {
|
||||
"GroupId": "{CDB6B8D8-5CD0-40A8-874D-839B00A92EBB}"
|
||||
},
|
||||
"Name": "None",
|
||||
"Group": {
|
||||
"Mask": 0
|
||||
},
|
||||
"ReadOnly": true
|
||||
},
|
||||
{
|
||||
"Id": {
|
||||
"GroupId": "{22769429-5D46-429B-829A-0115239D9AAA}"
|
||||
},
|
||||
"Name": "All_NoTouchBend",
|
||||
"Group": {
|
||||
"Mask": 9223372036854775807
|
||||
},
|
||||
"ReadOnly": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"DefaultMaterial": {
|
||||
"SurfaceType": "Default_1"
|
||||
},
|
||||
"MaterialLibrary": {
|
||||
"assetId": {
|
||||
"guid": "{6AA79EE4-7EC3-5717-87AE-EDD7D886FD7F}"
|
||||
},
|
||||
"loadBehavior": "QueueLoad",
|
||||
"assetHint": "levels/physics/c4044459_material_dynamicfriction/dynamic_friction.physmaterial"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue