Merge branch 'main' into Atom/dmcdiar/ATOM-15517
This commit is contained in:
@@ -97,16 +97,19 @@ class Cdk:
|
||||
env=self._cdk_env,
|
||||
shell=True)
|
||||
|
||||
def deploy(self, context_variable: str = '') -> List[str]:
|
||||
def deploy(self, context_variable: str = '', additonal_params: List[str] = None) -> List[str]:
|
||||
"""
|
||||
Deploys all the CDK stacks.
|
||||
:param context_variable: Context variable for enabling optional features.
|
||||
:param additonal_params: Additonal parameters like --all can be passed in this way.
|
||||
:return List of deployed stack arns.
|
||||
"""
|
||||
if not self._cdk_path:
|
||||
return []
|
||||
|
||||
deploy_cdk_application_cmd = ['cdk', 'deploy', '--require-approval', 'never']
|
||||
if additonal_params:
|
||||
deploy_cdk_application_cmd.extend(additonal_params)
|
||||
if context_variable:
|
||||
deploy_cdk_application_cmd.extend(['-c', f'{context_variable}'])
|
||||
|
||||
|
||||
@@ -137,5 +137,6 @@ enum class AnimParamType
|
||||
Invalid = static_cast<int>(0xFFFFFFFF)
|
||||
};
|
||||
|
||||
static const int OLD_APARAM_USER = 100;
|
||||
|
||||
#endif // CRYINCLUDE_CRYCOMMON_MAESTRO_TYPES_ANIMPARAMTYPE_H
|
||||
|
||||
@@ -561,7 +561,7 @@ void DebugCallStack::LogExceptionInfo(EXCEPTION_POINTERS* pex)
|
||||
|
||||
if (pex)
|
||||
{
|
||||
MINIDUMP_TYPE mdumpValue;
|
||||
MINIDUMP_TYPE mdumpValue = MiniDumpNormal;
|
||||
bool bDump = true;
|
||||
switch (g_cvars.sys_dump_type)
|
||||
{
|
||||
|
||||
@@ -66,7 +66,7 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
if (pSystem && !pSystem->IsQuitting())
|
||||
{
|
||||
LRESULT result;
|
||||
LRESULT result = 0;
|
||||
bool bAny = false;
|
||||
for (std::vector<IWindowMessageHandler*>::const_iterator it = pSystem->m_windowMessageHandlers.begin(); it != pSystem->m_windowMessageHandlers.end(); ++it)
|
||||
{
|
||||
|
||||
@@ -634,7 +634,7 @@ ICVar* CSystem::attachVariable (const char* szVarName, int* pContainer, const ch
|
||||
IConsole* pConsole = GetIConsole();
|
||||
|
||||
ICVar* pOldVar = pConsole->GetCVar (szVarName);
|
||||
int nDefault;
|
||||
int nDefault = 0;
|
||||
if (pOldVar)
|
||||
{
|
||||
nDefault = pOldVar->GetIVal();
|
||||
|
||||
@@ -1914,7 +1914,7 @@ namespace UnitTest
|
||||
TEST_F(String, StringView_CompareIsConstexpr)
|
||||
{
|
||||
using TypeParam = char;
|
||||
auto MakeCompileTimeString1 = []() constexpr -> const TypeParam*
|
||||
auto ThisTestMakeCompileTimeString1 = []() constexpr -> const TypeParam*
|
||||
{
|
||||
return "HelloWorld";
|
||||
};
|
||||
@@ -1922,7 +1922,7 @@ namespace UnitTest
|
||||
{
|
||||
return "HelloPearl";
|
||||
};
|
||||
constexpr const TypeParam* compileTimeString1 = MakeCompileTimeString1();
|
||||
constexpr const TypeParam* compileTimeString1 = ThisTestMakeCompileTimeString1();
|
||||
constexpr const TypeParam* compileTimeString2 = MakeCompileTimeString2();
|
||||
constexpr basic_string_view<TypeParam> lhsView(compileTimeString1);
|
||||
constexpr basic_string_view<TypeParam> rhsView(compileTimeString2);
|
||||
@@ -1937,11 +1937,11 @@ namespace UnitTest
|
||||
TEST_F(String, StringView_CompareOperatorsAreConstexpr)
|
||||
{
|
||||
using TypeParam = char;
|
||||
auto MakeCompileTimeString1 = []() constexpr -> const TypeParam*
|
||||
auto TestMakeCompileTimeString1 = []() constexpr -> const TypeParam*
|
||||
{
|
||||
return "HelloWorld";
|
||||
};
|
||||
constexpr const TypeParam* compileTimeString1 = MakeCompileTimeString1();
|
||||
constexpr const TypeParam* compileTimeString1 = TestMakeCompileTimeString1();
|
||||
constexpr basic_string_view<TypeParam> compareView(compileTimeString1);
|
||||
static_assert(compareView == "HelloWorld", "string_view operator== comparison has failed");
|
||||
static_assert(compareView != "MadWorld", "string_view operator!= comparison has failed");
|
||||
@@ -1955,7 +1955,7 @@ namespace UnitTest
|
||||
{
|
||||
auto swap_test_func = []() constexpr -> basic_string_view<TypeParam>
|
||||
{
|
||||
constexpr auto MakeCompileTimeString1 = []() constexpr -> const TypeParam*
|
||||
constexpr auto ThisTestMakeCompileTimeString1 = []() constexpr -> const TypeParam*
|
||||
{
|
||||
if constexpr (AZStd::is_same_v<TypeParam, char>)
|
||||
{
|
||||
@@ -1977,7 +1977,7 @@ namespace UnitTest
|
||||
return L"InuWorld";
|
||||
}
|
||||
};
|
||||
constexpr const TypeParam* compileTimeString1 = MakeCompileTimeString1();
|
||||
constexpr const TypeParam* compileTimeString1 = ThisTestMakeCompileTimeString1();
|
||||
constexpr const TypeParam* compileTimeString2 = MakeCompileTimeString2();
|
||||
basic_string_view<TypeParam> lhsView(compileTimeString1);
|
||||
basic_string_view<TypeParam> rhsView(compileTimeString2);
|
||||
@@ -2001,7 +2001,7 @@ namespace UnitTest
|
||||
|
||||
TYPED_TEST(BasicStringViewConstexprFixture, HashString_FunctionIsConstexpr)
|
||||
{
|
||||
auto MakeCompileTimeString1 = []() constexpr -> const TypeParam*
|
||||
auto ThisTestMakeCompileTimeString1 = []() constexpr -> const TypeParam*
|
||||
{
|
||||
if constexpr (AZStd::is_same_v<TypeParam, char>)
|
||||
{
|
||||
@@ -2012,7 +2012,7 @@ namespace UnitTest
|
||||
return L"HelloWorld";
|
||||
}
|
||||
};
|
||||
constexpr const TypeParam* compileTimeString1 = MakeCompileTimeString1();
|
||||
constexpr const TypeParam* compileTimeString1 = ThisTestMakeCompileTimeString1();
|
||||
constexpr basic_string_view<TypeParam> hashView(compileTimeString1);
|
||||
constexpr size_t compileHash = AZStd::hash<basic_string_view<TypeParam>>{}(hashView);
|
||||
static_assert(compileHash != 0, "Hash of \"HelloWorld\" should not be 0");
|
||||
|
||||
@@ -395,7 +395,8 @@ namespace UnitTest
|
||||
}
|
||||
else
|
||||
{
|
||||
int result1, result2;
|
||||
int result1 = 0;
|
||||
int result2 = 0;
|
||||
Job* job1 = aznew FibonacciJob2(m_n - 1, &result1, m_context);
|
||||
Job* job2 = aznew FibonacciJob2(m_n - 2, &result2, m_context);
|
||||
StartAsChild(job1);
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace UnitTest
|
||||
|
||||
TEST(MATH_Matrix4x4, TestCreateFrom)
|
||||
{
|
||||
float testFloats[] =
|
||||
float thisTestFloats[] =
|
||||
{
|
||||
1.0f, 2.0f, 3.0f, 4.0f,
|
||||
5.0f, 6.0f, 7.0f, 8.0f,
|
||||
@@ -67,20 +67,20 @@ namespace UnitTest
|
||||
13.0f, 14.0f, 15.0f, 16.0f
|
||||
};
|
||||
float testFloatMtx[16];
|
||||
Matrix4x4 m1 = Matrix4x4::CreateFromRowMajorFloat16(testFloats);
|
||||
Matrix4x4 m1 = Matrix4x4::CreateFromRowMajorFloat16(thisTestFloats);
|
||||
AZ_TEST_ASSERT(m1.GetRow(0) == Vector4(1.0f, 2.0f, 3.0f, 4.0f));
|
||||
AZ_TEST_ASSERT(m1.GetRow(1) == Vector4(5.0f, 6.0f, 7.0f, 8.0f));
|
||||
AZ_TEST_ASSERT(m1.GetRow(2) == Vector4(9.0f, 10.0f, 11.0f, 12.0f));
|
||||
AZ_TEST_ASSERT(m1.GetRow(3) == Vector4(13.0f, 14.0f, 15.0f, 16.0f));
|
||||
m1.StoreToRowMajorFloat16(testFloatMtx);
|
||||
AZ_TEST_ASSERT(memcmp(testFloatMtx, testFloats, sizeof(testFloatMtx)) == 0);
|
||||
m1 = Matrix4x4::CreateFromColumnMajorFloat16(testFloats);
|
||||
AZ_TEST_ASSERT(memcmp(testFloatMtx, thisTestFloats, sizeof(testFloatMtx)) == 0);
|
||||
m1 = Matrix4x4::CreateFromColumnMajorFloat16(thisTestFloats);
|
||||
AZ_TEST_ASSERT(m1.GetRow(0) == Vector4(1.0f, 5.0f, 9.0f, 13.0f));
|
||||
AZ_TEST_ASSERT(m1.GetRow(1) == Vector4(2.0f, 6.0f, 10.0f, 14.0f));
|
||||
AZ_TEST_ASSERT(m1.GetRow(2) == Vector4(3.0f, 7.0f, 11.0f, 15.0f));
|
||||
AZ_TEST_ASSERT(m1.GetRow(3) == Vector4(4.0f, 8.0f, 12.0f, 16.0f));
|
||||
m1.StoreToColumnMajorFloat16(testFloatMtx);
|
||||
AZ_TEST_ASSERT(memcmp(testFloatMtx, testFloats, sizeof(testFloatMtx)) == 0);
|
||||
AZ_TEST_ASSERT(memcmp(testFloatMtx, thisTestFloats, sizeof(testFloatMtx)) == 0);
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestCreateFromMatrix3x4)
|
||||
|
||||
@@ -119,10 +119,10 @@ namespace UnitTest
|
||||
|
||||
TEST(MATH_Obb, Contains)
|
||||
{
|
||||
const Vector3 position(1.0f, 2.0f, 3.0f);
|
||||
const Quaternion rotation = Quaternion::CreateRotationZ(DegToRad(30.0f));
|
||||
const Vector3 halfLengths(2.0f, 1.0f, 2.5f);
|
||||
const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(position, rotation, halfLengths);
|
||||
const Vector3 testPosition(1.0f, 2.0f, 3.0f);
|
||||
const Quaternion testRotation = Quaternion::CreateRotationZ(DegToRad(30.0f));
|
||||
const Vector3 testHalfLengths(2.0f, 1.0f, 2.5f);
|
||||
const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(testPosition, testRotation, testHalfLengths);
|
||||
// test some pairs of points which should be just either side of the Obb boundary
|
||||
EXPECT_TRUE(obb.Contains(Vector3(1.35f, 3.35f, 3.5f)));
|
||||
EXPECT_FALSE(obb.Contains(Vector3(1.35f, 3.4f, 3.5f)));
|
||||
@@ -134,10 +134,10 @@ namespace UnitTest
|
||||
|
||||
TEST(MATH_Obb, GetDistance)
|
||||
{
|
||||
const Vector3 position(5.0f, 3.0f, 2.0f);
|
||||
const Quaternion rotation = Quaternion::CreateRotationX(DegToRad(60.0f));
|
||||
const Vector3 halfLengths(0.5f, 2.0f, 1.5f);
|
||||
const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(position, rotation, halfLengths);
|
||||
const Vector3 testPosition(5.0f, 3.0f, 2.0f);
|
||||
const Quaternion testRotation = Quaternion::CreateRotationX(DegToRad(60.0f));
|
||||
const Vector3 testHalfLengths(0.5f, 2.0f, 1.5f);
|
||||
const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(testPosition, testRotation, testHalfLengths);
|
||||
EXPECT_NEAR(obb.GetDistance(Vector3(5.3f, 3.2f, 1.8f)), 0.0f, 1e-3f);
|
||||
EXPECT_NEAR(obb.GetDistance(Vector3(5.1f, 1.1f, 3.7f)), 0.9955f, 1e-3f);
|
||||
EXPECT_NEAR(obb.GetDistance(Vector3(4.7f, 4.5f, 4.2f)), 0.6553f, 1e-3f);
|
||||
@@ -146,10 +146,10 @@ namespace UnitTest
|
||||
|
||||
TEST(MATH_Obb, GetDistanceSq)
|
||||
{
|
||||
const Vector3 position(1.0f, 4.0f, 3.0f);
|
||||
const Quaternion rotation = Quaternion::CreateRotationY(DegToRad(45.0f));
|
||||
const Vector3 halfLengths(1.5f, 3.0f, 1.0f);
|
||||
const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(position, rotation, halfLengths);
|
||||
const Vector3 testPosition(1.0f, 4.0f, 3.0f);
|
||||
const Quaternion testRotation = Quaternion::CreateRotationY(DegToRad(45.0f));
|
||||
const Vector3 testHalfLengths(1.5f, 3.0f, 1.0f);
|
||||
const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(testPosition, testRotation, testHalfLengths);
|
||||
EXPECT_NEAR(obb.GetDistanceSq(Vector3(1.1f, 4.3f, 2.7f)), 0.0f, 1e-3f);
|
||||
EXPECT_NEAR(obb.GetDistanceSq(Vector3(-0.7f, 3.5f, 2.0f)), 0.8266f, 1e-3f);
|
||||
EXPECT_NEAR(obb.GetDistanceSq(Vector3(2.4f, 0.5f, 1.5f)), 0.5532f, 1e-3f);
|
||||
|
||||
+1
@@ -353,6 +353,7 @@ namespace AzFramework
|
||||
|
||||
// Get the dimensions of the display device on which the window is currently displayed.
|
||||
MONITORINFO monitorInfo;
|
||||
memset(&monitorInfo, 0, sizeof(MONITORINFO)); // C4701 potentially uninitialized local variable 'monitorInfo' used
|
||||
monitorInfo.cbSize = sizeof(MONITORINFO);
|
||||
const BOOL success = monitor ? GetMonitorInfo(monitor, &monitorInfo) : FALSE;
|
||||
if (!success)
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace AzNetworking
|
||||
}
|
||||
else if (m_updateRate < updateTimeMs)
|
||||
{
|
||||
AZLOG_INFO("TimedThread bled %d ms", aznumeric_cast<int32_t>(updateTimeMs - m_updateRate));
|
||||
AZLOG(NET_TimedThread, "TimedThread bled %d ms", aznumeric_cast<int32_t>(updateTimeMs - m_updateRate));
|
||||
}
|
||||
}
|
||||
OnStop();
|
||||
|
||||
+11
@@ -124,4 +124,15 @@ namespace AzToolsFramework
|
||||
|
||||
return cameraState;
|
||||
}
|
||||
|
||||
float GetScreenDisplayScaling(const int viewportId)
|
||||
{
|
||||
float scaling = 1.0f;
|
||||
ViewportInteraction::ViewportInteractionRequestBus::EventResult(
|
||||
scaling, viewportId,
|
||||
&ViewportInteraction::ViewportInteractionRequestBus::Events::DeviceScalingFactor);
|
||||
|
||||
return scaling;
|
||||
}
|
||||
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+3
@@ -60,6 +60,9 @@ namespace AzToolsFramework
|
||||
/// Wrapper for EBus call to return the CameraState for a given viewport.
|
||||
AzFramework::CameraState GetCameraState(int viewportId);
|
||||
|
||||
/// Wrapper for EBus call to return the DPI scaling for a given viewport.
|
||||
float GetScreenDisplayScaling(const int viewportId);
|
||||
|
||||
/// A utility to return the center of several points.
|
||||
/// Take several positions and store the min and max of each in
|
||||
/// turn - when all points have been added return the center/midpoint.
|
||||
|
||||
+4
-3
@@ -3573,9 +3573,10 @@ namespace AzToolsFramework
|
||||
debugDisplay.SetLineWidth(1.0f);
|
||||
|
||||
const float labelOffset = cl_viewportGizmoAxisLabelOffset;
|
||||
const auto labelXScreenPosition = (gizmoStart + (gizmoAxisX * labelOffset)) * editorCameraState.m_viewportSize;
|
||||
const auto labelYScreenPosition = (gizmoStart + (gizmoAxisY * labelOffset)) * editorCameraState.m_viewportSize;
|
||||
const auto labelZScreenPosition = (gizmoStart + (gizmoAxisZ * labelOffset)) * editorCameraState.m_viewportSize;
|
||||
const float screenScale = GetScreenDisplayScaling(viewportId);
|
||||
const auto labelXScreenPosition = (gizmoStart + (gizmoAxisX * labelOffset)) * editorCameraState.m_viewportSize * screenScale;
|
||||
const auto labelYScreenPosition = (gizmoStart + (gizmoAxisY * labelOffset)) * editorCameraState.m_viewportSize * screenScale;
|
||||
const auto labelZScreenPosition = (gizmoStart + (gizmoAxisZ * labelOffset)) * editorCameraState.m_viewportSize * screenScale;
|
||||
|
||||
// draw the label of of each axis for the gizmo
|
||||
const float labelSize = cl_viewportGizmoAxisLabelSize;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Launcher.h>
|
||||
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
@@ -22,6 +23,8 @@
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
#include <AzFramework/IO/RemoteStorageDrive.h>
|
||||
#include <AzFramework/Windowing/NativeWindow.h>
|
||||
#include <AzFramework/Windowing/WindowBus.h>
|
||||
|
||||
#include <AzGameFramework/Application/GameApplication.h>
|
||||
|
||||
@@ -45,6 +48,19 @@ extern "C" void CreateStaticModules(AZStd::vector<AZ::Module*>& modulesOut);
|
||||
|
||||
namespace
|
||||
{
|
||||
void OnViewportResize(const AZ::Vector2& value);
|
||||
|
||||
AZ_CVAR(AZ::Vector2, r_viewportSize, AZ::Vector2::CreateZero(), OnViewportResize, AZ::ConsoleFunctorFlags::DontReplicate,
|
||||
"The default size for the launcher viewport, 0 0 means full screen");
|
||||
|
||||
void OnViewportResize(const AZ::Vector2& value)
|
||||
{
|
||||
AzFramework::NativeWindowHandle windowHandle = nullptr;
|
||||
AzFramework::WindowSystemRequestBus::BroadcastResult(windowHandle, &AzFramework::WindowSystemRequestBus::Events::GetDefaultWindowHandle);
|
||||
AzFramework::WindowSize newSize = AzFramework::WindowSize(aznumeric_cast<int32_t>(value.GetX()), aznumeric_cast<int32_t>(value.GetY()));
|
||||
AzFramework::WindowRequestBus::Broadcast(&AzFramework::WindowRequestBus::Events::ResizeClientArea, newSize);
|
||||
}
|
||||
|
||||
void ExecuteConsoleCommandFile(AzFramework::Application& application)
|
||||
{
|
||||
const AZStd::string_view customConCmdKey = "console-command-file";
|
||||
|
||||
@@ -1233,7 +1233,7 @@ void EditorViewportWidget::SetViewportId(int id)
|
||||
|
||||
auto controller = AZStd::make_shared<AtomToolsFramework::ModularViewportCameraController>();
|
||||
controller->SetCameraListBuilderCallback(
|
||||
[](AzFramework::Cameras& cameras)
|
||||
[id](AzFramework::Cameras& cameras)
|
||||
{
|
||||
auto firstPersonRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(AzFramework::CameraFreeLookButton);
|
||||
auto firstPersonPanCamera =
|
||||
@@ -1243,17 +1243,17 @@ void EditorViewportWidget::SetViewportId(int id)
|
||||
|
||||
auto orbitCamera = AZStd::make_shared<AzFramework::OrbitCameraInput>();
|
||||
orbitCamera->SetLookAtFn(
|
||||
[](const AZ::Vector3& position, const AZ::Vector3& direction) -> AZStd::optional<AZ::Vector3>
|
||||
[id](const AZ::Vector3& position, const AZ::Vector3& direction) -> AZStd::optional<AZ::Vector3>
|
||||
{
|
||||
AZStd::optional<AZ::Transform> manipulatorTransform;
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
|
||||
manipulatorTransform, AzToolsFramework::GetEntityContextId(),
|
||||
&AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform);
|
||||
AZStd::optional<AZ::Vector3> lookAtAfterInterpolation;
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
|
||||
lookAtAfterInterpolation, id,
|
||||
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::LookAtAfterInterpolation);
|
||||
|
||||
// initially attempt to use manipulator transform if one exists (there is a selection)
|
||||
if (manipulatorTransform)
|
||||
// initially attempt to use the last set look at point after an interpolation has finished
|
||||
if (lookAtAfterInterpolation.has_value())
|
||||
{
|
||||
return manipulatorTransform->GetTranslation();
|
||||
return *lookAtAfterInterpolation;
|
||||
}
|
||||
|
||||
const float RayDistance = 1000.0f;
|
||||
|
||||
@@ -553,7 +553,7 @@ void CLogFile::OnWriteToConsole(const char* sText, bool bNewLine)
|
||||
|
||||
// remember selection and the top row
|
||||
int len = m_hWndEditBox->document()->toPlainText().length();
|
||||
int top;
|
||||
int top = 0;
|
||||
int from = m_hWndEditBox->textCursor().selectionStart();
|
||||
int to = from + m_hWndEditBox->textCursor().selectionEnd();
|
||||
bool keepPos = false;
|
||||
|
||||
@@ -121,7 +121,7 @@ protected:
|
||||
};
|
||||
#endif
|
||||
|
||||
Q_GLOBAL_STATIC(QtViewPaneManager, s_instance)
|
||||
Q_GLOBAL_STATIC(QtViewPaneManager, s_viewPaneManagerInstance)
|
||||
|
||||
|
||||
QWidget* QtViewPane::CreateWidget()
|
||||
@@ -611,12 +611,12 @@ void QtViewPaneManager::UnregisterPane(const QString& name)
|
||||
|
||||
QtViewPaneManager* QtViewPaneManager::instance()
|
||||
{
|
||||
return s_instance();
|
||||
return s_viewPaneManagerInstance();
|
||||
}
|
||||
|
||||
bool QtViewPaneManager::exists()
|
||||
{
|
||||
return s_instance.exists();
|
||||
return s_viewPaneManagerInstance.exists();
|
||||
}
|
||||
|
||||
void QtViewPaneManager::SetMainWindow(AzQtComponents::DockMainWindow* mainWindow, QSettings* settings, const QByteArray& lastMainWindowState)
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace
|
||||
{
|
||||
int fps;
|
||||
const char* fpsDesc;
|
||||
} fps[] = {
|
||||
} fpsOptions[] = {
|
||||
{24, "Film(24)"}, {25, "PAL(25)"}, {30, "NTSC(30)"},
|
||||
{48, "Show(48)"}, {50, "PAL Field(50)"}, {60, "NTSC Field(60)"}
|
||||
};
|
||||
@@ -213,9 +213,9 @@ void CSequenceBatchRenderDialog::OnInitDialog()
|
||||
m_ui->m_resolutionCombo->setCurrentIndex(0);
|
||||
|
||||
// Fill the FPS combo box.
|
||||
for (int i = 0; i < AZStd::size(fps); ++i)
|
||||
for (int i = 0; i < AZStd::size(fpsOptions); ++i)
|
||||
{
|
||||
m_ui->m_fpsCombo->addItem(fps[i].fpsDesc);
|
||||
m_ui->m_fpsCombo->addItem(fpsOptions[i].fpsDesc);
|
||||
}
|
||||
m_ui->m_fpsCombo->setCurrentIndex(0);
|
||||
|
||||
@@ -306,9 +306,9 @@ void CSequenceBatchRenderDialog::OnRenderItemSelChange()
|
||||
m_ui->m_destinationEdit->setText(item.folder);
|
||||
// fps
|
||||
bool bFound = false;
|
||||
for (int i = 0; i < arraysize(fps); ++i)
|
||||
for (int i = 0; i < arraysize(fpsOptions); ++i)
|
||||
{
|
||||
if (item.fps == fps[i].fps)
|
||||
if (item.fps == fpsOptions[i].fps)
|
||||
{
|
||||
m_ui->m_fpsCombo->setCurrentIndex(i);
|
||||
bFound = true;
|
||||
@@ -621,7 +621,7 @@ void CSequenceBatchRenderDialog::OnFPSEditChange()
|
||||
|
||||
void CSequenceBatchRenderDialog::OnFPSChange(int itemIndex)
|
||||
{
|
||||
m_customFPS = fps[itemIndex].fps;
|
||||
m_customFPS = fpsOptions[itemIndex].fps;
|
||||
CheckForEnableUpdateButton();
|
||||
}
|
||||
|
||||
@@ -1543,13 +1543,13 @@ bool CSequenceBatchRenderDialog::SetUpNewRenderItem(SRenderItem& item)
|
||||
item.frameRange = Range(m_ui->m_startFrame->value() / m_fpsForTimeToFrameConversion,
|
||||
m_ui->m_endFrame->value() / m_fpsForTimeToFrameConversion);
|
||||
// fps
|
||||
if (m_ui->m_fpsCombo->currentIndex() == -1 || m_ui->m_fpsCombo->currentText() != fps[m_ui->m_fpsCombo->currentIndex()].fpsDesc)
|
||||
if (m_ui->m_fpsCombo->currentIndex() == -1 || m_ui->m_fpsCombo->currentText() != fpsOptions[m_ui->m_fpsCombo->currentIndex()].fpsDesc)
|
||||
{
|
||||
item.fps = m_customFPS;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.fps = fps[m_ui->m_fpsCombo->currentIndex()].fps;
|
||||
item.fps = fpsOptions[m_ui->m_fpsCombo->currentIndex()].fps;
|
||||
}
|
||||
// prefix
|
||||
item.prefix = m_ui->BATCH_RENDER_FILE_PREFIX->text();
|
||||
|
||||
@@ -157,7 +157,7 @@ static Quatern Qt_FromMatrix(HMatrix mat)
|
||||
* |w| is greater than 1/2, which is as small as a largest component can be.
|
||||
* Otherwise, the largest diagonal entry corresponds to the largest of |x|,
|
||||
* |y|, or |z|, one of which must be larger than |w|, and at least 1/2. */
|
||||
Quatern qu;
|
||||
Quatern qu = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
double tr, s;
|
||||
|
||||
tr = mat[X][X] + mat[Y][Y] + mat[Z][Z];
|
||||
@@ -531,7 +531,7 @@ Quatern snuggle(Quatern q, HVect* k)
|
||||
#define swap(a, i, j) {a[3] = a[i]; a[i] = a[j]; a[j] = a[3]; }
|
||||
#define cycle(a, p) if (p) {a[3] = a[0]; a[0] = a[1]; a[1] = a[2]; a[2] = a[3]; } \
|
||||
else {a[3] = a[2]; a[2] = a[1]; a[1] = a[0]; a[0] = a[3]; }
|
||||
Quatern p;
|
||||
Quatern p = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
float ka[4];
|
||||
int i, turn = -1;
|
||||
ka[X] = k->x;
|
||||
|
||||
@@ -2239,7 +2239,8 @@ uint32 CFileUtil::GetAttributes(const char* filename, bool bUseSourceControl /*=
|
||||
bool CFileUtil::CompareFiles(const QString& strFilePath1, const QString& strFilePath2)
|
||||
{
|
||||
// Get the size of both files. If either fails we say they are different (most likely one doesn't exist)
|
||||
uint64 size1, size2;
|
||||
uint64 size1 = 0;
|
||||
uint64 size2 = 0;
|
||||
if (!GetDiskFileSize(strFilePath1.toUtf8().data(), size1) || !GetDiskFileSize(strFilePath2.toUtf8().data(), size2))
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -116,6 +116,7 @@ bool CImageBT::Load(const QString& fileName, CFloatImage& image)
|
||||
|
||||
// Get the BT header data
|
||||
BtHeader header;
|
||||
memset(&header, 0, sizeof(BtHeader)); // C4701 potentially uninitialized local variable 'header' used
|
||||
bool validData = true;
|
||||
validData = validData && (fread(&header, sizeof(BtHeader), 1, file) != 0);
|
||||
|
||||
|
||||
@@ -419,7 +419,7 @@ static inline bool MatchesWildcardsIgnoreCaseExt_Tpl(const TS& str, const TS& wi
|
||||
const typename TS::value_type* savedStrBegin = 0;
|
||||
const typename TS::value_type* savedStrEnd = 0;
|
||||
const typename TS::value_type* savedWild = 0;
|
||||
size_t savedWildCount;
|
||||
size_t savedWildCount = 0;
|
||||
|
||||
const typename TS::value_type* pStr = str.c_str();
|
||||
const typename TS::value_type* pWild = wildcards.c_str();
|
||||
|
||||
@@ -179,11 +179,11 @@ ComponentEntityEditorPlugin::ComponentEntityEditorPlugin([[maybe_unused]] IEdito
|
||||
LyViewPane::EntityOutliner,
|
||||
LyViewPane::CategoryTools,
|
||||
outlinerOptions);
|
||||
}
|
||||
|
||||
AzToolsFramework::ViewPaneOptions options;
|
||||
options.preferedDockingArea = Qt::NoDockWidgetArea;
|
||||
RegisterViewPane<SliceRelationshipWidget>(LyViewPane::SliceRelationships, LyViewPane::CategoryTools, options);
|
||||
AzToolsFramework::ViewPaneOptions options;
|
||||
options.preferedDockingArea = Qt::NoDockWidgetArea;
|
||||
RegisterViewPane<SliceRelationshipWidget>(LyViewPane::SliceRelationships, LyViewPane::CategoryTools, options);
|
||||
}
|
||||
|
||||
RegisterModuleResourceSelectors(GetIEditor()->GetResourceSelectorHost());
|
||||
|
||||
|
||||
@@ -1732,13 +1732,14 @@ void SandboxIntegrationManager::GoToEntitiesInViewports(const AzToolsFramework::
|
||||
// compute new camera transform
|
||||
const float fov = AzFramework::RetrieveFov(viewportContext->GetCameraProjectionMatrix());
|
||||
const float fovScale = (1.0f / AZStd::tan(fov * 0.5f));
|
||||
const float distanceToTarget = selectionSize * fovScale * centerScale;
|
||||
const float distanceToLookAt = selectionSize * fovScale * centerScale;
|
||||
const AZ::Transform nextCameraTransform =
|
||||
AZ::Transform::CreateLookAt(aabb.GetCenter() - (forward * distanceToTarget), aabb.GetCenter());
|
||||
AZ::Transform::CreateLookAt(aabb.GetCenter() - (forward * distanceToLookAt), aabb.GetCenter());
|
||||
|
||||
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
|
||||
viewportContext->GetId(),
|
||||
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform);
|
||||
&AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform,
|
||||
distanceToLookAt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ class ConfigurationManager(object):
|
||||
def configuration(self, new_configuration: ConfigurationManager) -> None:
|
||||
self._configuration = new_configuration
|
||||
|
||||
def setup(self, config_path: str) -> None:
|
||||
def setup(self, config_path: str) -> bool:
|
||||
result: bool = True
|
||||
logger.info("Setting up default configuration ...")
|
||||
try:
|
||||
normalized_config_path: str = file_utils.normalize_file_path(config_path);
|
||||
@@ -63,5 +64,7 @@ class ConfigurationManager(object):
|
||||
self._configuration.account_id = aws_utils.get_default_account_id()
|
||||
self._configuration.region = aws_utils.get_default_region()
|
||||
except (RuntimeError, FileNotFoundError) as e:
|
||||
logger.exception(e)
|
||||
logger.error(e)
|
||||
result = False
|
||||
logger.debug(self._configuration)
|
||||
return result
|
||||
|
||||
@@ -74,11 +74,18 @@ if __name__ == "__main__":
|
||||
logger.warning("Failed to load style sheet for resource mapping tool")
|
||||
|
||||
logger.info("Initializing boto3 default session ...")
|
||||
aws_utils.setup_default_session(arguments.profile)
|
||||
try:
|
||||
aws_utils.setup_default_session(arguments.profile)
|
||||
except RuntimeError as error:
|
||||
logger.error(error)
|
||||
environment_utils.cleanup_qt_environment()
|
||||
exit(-1)
|
||||
|
||||
logger.info("Initializing configuration manager ...")
|
||||
configuration_manager: ConfigurationManager = ConfigurationManager()
|
||||
configuration_manager.setup(arguments.config_path)
|
||||
if not configuration_manager.setup(arguments.config_path):
|
||||
environment_utils.cleanup_qt_environment()
|
||||
exit(-1)
|
||||
|
||||
logger.info("Initializing thread manager ...")
|
||||
thread_manager: ThreadManager = ThreadManager()
|
||||
|
||||
+1238
-1124
File diff suppressed because it is too large
Load Diff
@@ -12,10 +12,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
import boto3
|
||||
from botocore.paginate import (PageIterator, Paginator)
|
||||
from botocore.client import BaseClient
|
||||
from botocore.exceptions import ClientError
|
||||
from botocore.exceptions import (ClientError, ConfigNotFound, NoCredentialsError, ProfileNotFound)
|
||||
from typing import Dict, List
|
||||
|
||||
from model import (constants, error_messages)
|
||||
from model import error_messages
|
||||
from model.basic_resource_attributes import (BasicResourceAttributes, BasicResourceAttributesBuilder)
|
||||
|
||||
"""
|
||||
@@ -65,8 +65,11 @@ def _initialize_boto3_aws_client(service: str, region: str = "") -> BaseClient:
|
||||
|
||||
|
||||
def setup_default_session(profile: str) -> None:
|
||||
global default_session
|
||||
default_session = boto3.session.Session(profile_name=profile)
|
||||
try:
|
||||
global default_session
|
||||
default_session = boto3.session.Session(profile_name=profile)
|
||||
except (ConfigNotFound, ProfileNotFound) as error:
|
||||
raise RuntimeError(error)
|
||||
|
||||
|
||||
def get_default_account_id() -> str:
|
||||
@@ -76,6 +79,8 @@ def get_default_account_id() -> str:
|
||||
except ClientError as error:
|
||||
raise RuntimeError(error_messages.AWS_SERVICE_REQUEST_CLIENT_ERROR_MESSAGE.format(
|
||||
"get_caller_identity", error.response['Error']['Code'], error.response['Error']['Message']))
|
||||
except NoCredentialsError as error:
|
||||
raise RuntimeError(error)
|
||||
|
||||
|
||||
def get_default_region() -> str:
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace ImageProcessingAtom
|
||||
int dstPosition;
|
||||
signed short int n;
|
||||
bool trimZeros = true, stillzero;
|
||||
int lastnonzero, hWeight, highest;
|
||||
int lastnonzero = 0, hWeight, highest = 0;
|
||||
signed int sumiWeights, iWeight;
|
||||
signed short int* weightsPtr;
|
||||
signed short int* weightsMem;
|
||||
|
||||
+1
-1
@@ -1106,7 +1106,7 @@ namespace ImageProcessingAtom
|
||||
//fractional amount to apply change in tap intensity along edge to taps
|
||||
// in a perpendicular direction to edge
|
||||
CP_ITYPE fixupFrac = (CP_ITYPE)(fixupDist - iFixup) / (CP_ITYPE)(fixupDist);
|
||||
CP_ITYPE fixupWeight;
|
||||
CP_ITYPE fixupWeight = 0.0f;
|
||||
|
||||
switch(a_FixupType )
|
||||
{
|
||||
|
||||
@@ -37,7 +37,7 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial
|
||||
}
|
||||
|
||||
#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
|
||||
#include <Atom/Features/PBR/TransparentPassSrg.azsli>
|
||||
#include <Atom/Features/PBR/ForwardPassSrg.azsli>
|
||||
#include <Atom/Features/Shadow/DirectionalLightShadow.azsli>
|
||||
#include <Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli>
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
"DrawListSortType": "KeyThenReverseDepth",
|
||||
"PipelineViewTag": "MainCamera",
|
||||
"PassSrgAsset": {
|
||||
"FilePath": "shaderlib/atom/features/pbr/transparentpasssrg.azsli:PassSrg"
|
||||
"FilePath": "shaderlib/atom/features/pbr/forwardpasssrg.azsli:PassSrg"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,4 +35,5 @@ ShaderResourceGroup PassSrg : SRG_PerPass
|
||||
|
||||
Texture2D<uint4> m_tileLightData;
|
||||
StructuredBuffer<uint> m_lightListRemapped;
|
||||
Texture2D<float> m_linearDepthTexture;
|
||||
}
|
||||
|
||||
@@ -1,39 +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.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Atom/Features/SrgSemantics.azsli>
|
||||
|
||||
ShaderResourceGroup PassSrg : SRG_PerPass
|
||||
{
|
||||
// [GFX TODO][ATOM-2012] adapt to multiple shadowmaps
|
||||
Texture2DArray<float> m_directionalLightShadowmap;
|
||||
Texture2DArray<float> m_directionalLightExponentialShadowmap;
|
||||
Texture2DArray<float> m_projectedShadowmaps;
|
||||
Texture2DArray<float> m_projectedExponentialShadowmap;
|
||||
Texture2D m_brdfMap;
|
||||
|
||||
Sampler LinearSampler
|
||||
{
|
||||
MinFilter = Linear;
|
||||
MagFilter = Linear;
|
||||
MipFilter = Linear;
|
||||
AddressU = Clamp;
|
||||
AddressV = Clamp;
|
||||
AddressW = Clamp;
|
||||
};
|
||||
|
||||
Texture2D<uint4> m_tileLightData;
|
||||
StructuredBuffer<uint> m_lightListRemapped;
|
||||
Texture2D<float> m_linearDepthTexture;
|
||||
}
|
||||
@@ -246,7 +246,6 @@ set(FILES
|
||||
ShaderLib/Atom/Features/PBR/Hammersley.azsli
|
||||
ShaderLib/Atom/Features/PBR/LightingOptions.azsli
|
||||
ShaderLib/Atom/Features/PBR/LightingUtils.azsli
|
||||
ShaderLib/Atom/Features/PBR/TransparentPassSrg.azsli
|
||||
ShaderLib/Atom/Features/PBR/Lighting/DualSpecularLighting.azsli
|
||||
ShaderLib/Atom/Features/PBR/Lighting/EnhancedLighting.azsli
|
||||
ShaderLib/Atom/Features/PBR/Lighting/LightingData.azsli
|
||||
|
||||
-2
@@ -46,8 +46,6 @@ namespace AZ
|
||||
uint16_t m_padding; // Explicit padding.
|
||||
};
|
||||
|
||||
static constexpr size_t size = sizeof(DiskLightData);
|
||||
|
||||
//! DiskLightFeatureProcessorInterface provides an interface to acquire, release, and update a disk light. This is necessary for code outside of
|
||||
//! the Atom features gem to communicate with the DiskLightFeatureProcessor.
|
||||
class DiskLightFeatureProcessorInterface
|
||||
|
||||
@@ -484,6 +484,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
D3D12_RESOURCE_TRANSITION_BARRIER transition;
|
||||
memset(&transition, 0, sizeof(D3D12_RESOURCE_TRANSITION_BARRIER)); // C4701 potentially unitialized local variable 'transition' used
|
||||
transition.pResource = image.GetMemoryView().GetMemory();
|
||||
|
||||
Scope& firstScope = static_cast<Scope&>(scopeAttachment->GetScope());
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace AZ
|
||||
Fence* fenceToSignal)
|
||||
{
|
||||
AZStd::vector<VkCommandBuffer> vkCommandBuffers;
|
||||
AZStd::vector<VkSemaphore> vkWaitSemaphores;
|
||||
AZStd::vector<VkSemaphore> vkWaitSemaphoreVector; // vulkan.h has a #define called vkWaitSemaphores, so we name this differently
|
||||
AZStd::vector<VkPipelineStageFlags> vkWaitPipelineStages;
|
||||
AZStd::vector<VkSemaphore> vkSignalSemaphores;
|
||||
VkSubmitInfo submitInfo;
|
||||
@@ -65,11 +65,11 @@ namespace AZ
|
||||
return item->GetNativeSemaphore();
|
||||
});
|
||||
vkWaitPipelineStages.reserve(waitSemaphoresInfo.size());
|
||||
vkWaitSemaphores.reserve(waitSemaphoresInfo.size());
|
||||
vkWaitSemaphoreVector.reserve(waitSemaphoresInfo.size());
|
||||
AZStd::for_each(waitSemaphoresInfo.begin(), waitSemaphoresInfo.end(), [&](auto& item)
|
||||
{
|
||||
vkWaitPipelineStages.push_back(item.first);
|
||||
vkWaitSemaphores.push_back(item.second->GetNativeSemaphore());
|
||||
vkWaitSemaphoreVector.push_back(item.second->GetNativeSemaphore());
|
||||
// Wait until the wait semaphores has been submitted for signaling.
|
||||
item.second->WaitEvent();
|
||||
});
|
||||
@@ -77,8 +77,8 @@ namespace AZ
|
||||
submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.pNext = nullptr;
|
||||
submitInfo.waitSemaphoreCount = static_cast<uint32_t>(vkWaitSemaphores.size());
|
||||
submitInfo.pWaitSemaphores = vkWaitSemaphores.empty() ? nullptr : vkWaitSemaphores.data();
|
||||
submitInfo.waitSemaphoreCount = static_cast<uint32_t>(vkWaitSemaphoreVector.size());
|
||||
submitInfo.pWaitSemaphores = vkWaitSemaphoreVector.empty() ? nullptr : vkWaitSemaphoreVector.data();
|
||||
submitInfo.pWaitDstStageMask = vkWaitPipelineStages.empty() ? nullptr : vkWaitPipelineStages.data();
|
||||
submitInfo.commandBufferCount = static_cast<uint32_t>(vkCommandBuffers.size());
|
||||
submitInfo.pCommandBuffers = vkCommandBuffers.empty() ? nullptr : vkCommandBuffers.data();
|
||||
|
||||
@@ -244,16 +244,26 @@ namespace AZ
|
||||
|
||||
void CullingScene::RegisterOrUpdateCullable(Cullable& cullable)
|
||||
{
|
||||
m_cullDataConcurrencyCheck.soft_lock();
|
||||
// Multiple threads can call RegisterOrUpdateCullable at the same time
|
||||
// since the underlying visScene is thread safe, but if you're inserting or
|
||||
// updating between BeginCulling and EndCulling, you'll get non-deterministic
|
||||
// results depending on a race condition if you happen to update before or after
|
||||
// the culling system starts Enumerating, so use soft_lock_shared here
|
||||
m_cullDataConcurrencyCheck.soft_lock_shared();
|
||||
m_visScene->InsertOrUpdateEntry(cullable.m_cullData.m_visibilityEntry);
|
||||
m_cullDataConcurrencyCheck.soft_unlock();
|
||||
m_cullDataConcurrencyCheck.soft_unlock_shared();
|
||||
}
|
||||
|
||||
void CullingScene::UnregisterCullable(Cullable& cullable)
|
||||
{
|
||||
m_cullDataConcurrencyCheck.soft_lock();
|
||||
// Multiple threads can call RegisterOrUpdateCullable at the same time
|
||||
// since the underlying visScene is thread safe, but if you're inserting or
|
||||
// updating between BeginCulling and EndCulling, you'll get non-deterministic
|
||||
// results depending on a race condition if you happen to update before or after
|
||||
// the culling system starts Enumerating, so use soft_lock_shared here
|
||||
m_cullDataConcurrencyCheck.soft_lock_shared();
|
||||
m_visScene->RemoveEntry(cullable.m_cullData.m_visibilityEntry);
|
||||
m_cullDataConcurrencyCheck.soft_unlock();
|
||||
m_cullDataConcurrencyCheck.soft_unlock_shared();
|
||||
}
|
||||
|
||||
uint32_t CullingScene::GetNumCullables() const
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*
|
||||
*/
|
||||
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
|
||||
#include <Atom/RPI.Reflect/Shader/ShaderCommonTypes.h>
|
||||
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
@@ -34,10 +35,6 @@ namespace AZ
|
||||
|
||||
uint32_t ShaderAsset::MakeAssetProductSubId(uint32_t rhiApiUniqueIndex, uint32_t subProductType)
|
||||
{
|
||||
static constexpr uint32_t RhiIndexBitPosition = 30;
|
||||
static constexpr uint32_t RhiIndexNumBits = 32 - RhiIndexBitPosition;
|
||||
static constexpr uint32_t RhiIndexMaxValue = (1 << RhiIndexNumBits) - 1;
|
||||
|
||||
static constexpr uint32_t SubProductTypeBitPosition = 0;
|
||||
static constexpr uint32_t SubProductTypeNumBits = RhiIndexBitPosition - SubProductTypeBitPosition;
|
||||
static constexpr uint32_t SubProductTypeMaxValue = (1 << SubProductTypeNumBits) - 1;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*
|
||||
*/
|
||||
#include <Atom/RPI.Reflect/Shader/ShaderVariantAsset.h>
|
||||
#include <Atom/RPI.Reflect/Shader/ShaderCommonTypes.h>
|
||||
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
@@ -24,10 +25,6 @@ namespace AZ
|
||||
uint32_t ShaderVariantAsset::MakeAssetProductSubId(
|
||||
uint32_t rhiApiUniqueIndex, ShaderVariantStableId variantStableId, uint32_t subProductType)
|
||||
{
|
||||
static constexpr uint32_t RhiIndexBitPosition = 30;
|
||||
static constexpr uint32_t RhiIndexNumBits = 32 - RhiIndexBitPosition;
|
||||
static constexpr uint32_t RhiIndexMaxValue = (1 << RhiIndexNumBits) - 1;
|
||||
|
||||
static constexpr uint32_t SubProductTypeBitPosition = 17;
|
||||
static constexpr uint32_t SubProductTypeNumBits = RhiIndexBitPosition - SubProductTypeBitPosition;
|
||||
static constexpr uint32_t SubProductTypeMaxValue = (1 << SubProductTypeNumBits) - 1;
|
||||
|
||||
+4
-1
@@ -51,7 +51,8 @@ namespace AtomToolsFramework
|
||||
void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override;
|
||||
|
||||
// ModularViewportCameraControllerRequestBus overrides ...
|
||||
void InterpolateToTransform(const AZ::Transform& worldFromLocal) override;
|
||||
void InterpolateToTransform(const AZ::Transform& worldFromLocal, float lookAtDistance) override;
|
||||
AZStd::optional<AZ::Vector3> LookAtAfterInterpolation() const override;
|
||||
|
||||
private:
|
||||
// AzFramework::ViewportDebugDisplayEventBus overrides ...
|
||||
@@ -71,6 +72,8 @@ namespace AtomToolsFramework
|
||||
AZ::Transform m_transformEnd = AZ::Transform::CreateIdentity();
|
||||
float m_animationT = 0.0f;
|
||||
CameraMode m_cameraMode = CameraMode::Control;
|
||||
AZStd::optional<AZ::Vector3> m_lookAtAfterInterpolation; //!< The look at point after an interpolation has finished.
|
||||
//!< Will be cleared when the view changes (camera looks away).
|
||||
bool m_updatingTransform = false;
|
||||
|
||||
AZ::RPI::ViewportContext::MatrixChangedEvent::Handler m_cameraViewMatrixChangeHandler;
|
||||
|
||||
+6
-1
@@ -32,7 +32,12 @@ namespace AtomToolsFramework
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
//! Begin a smooth transition of the camera to the requested transform.
|
||||
virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal) = 0;
|
||||
//! @param worldFromLocal The transform of where the camera should end up.
|
||||
//! @param lookAtDistance The distance between the camera transform and the imagined look at point.
|
||||
virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal, float lookAtDistance) = 0;
|
||||
|
||||
//! Look at point after an interpolation has finished and no translation has occurred.
|
||||
virtual AZStd::optional<AZ::Vector3> LookAtAfterInterpolation() const = 0;
|
||||
|
||||
protected:
|
||||
~ModularViewportCameraControllerRequests() = default;
|
||||
|
||||
+20
-2
@@ -140,6 +140,18 @@ namespace AtomToolsFramework
|
||||
m_targetCamera = m_cameraSystem.StepCamera(m_targetCamera, event.m_deltaTime.count());
|
||||
m_camera = AzFramework::SmoothCamera(m_camera, m_targetCamera, event.m_deltaTime.count());
|
||||
|
||||
// if there has been an interpolation, only clear the look at point if it is no longer
|
||||
// centered in the view (the camera has looked away from it)
|
||||
if (m_lookAtAfterInterpolation.has_value())
|
||||
{
|
||||
if (const float lookDirection =
|
||||
(*m_lookAtAfterInterpolation - m_camera.Translation()).GetNormalized().Dot(m_camera.Transform().GetBasisY());
|
||||
!AZ::IsCloseMag(lookDirection, 1.0f, 0.001f))
|
||||
{
|
||||
m_lookAtAfterInterpolation = {};
|
||||
}
|
||||
}
|
||||
|
||||
viewportContext->SetCameraTransform(m_camera.Transform());
|
||||
}
|
||||
else if (m_cameraMode == CameraMode::Animation)
|
||||
@@ -148,8 +160,8 @@ namespace AtomToolsFramework
|
||||
{
|
||||
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
|
||||
};
|
||||
const float transitionT = smootherStepFn(m_animationT);
|
||||
|
||||
const float transitionT = smootherStepFn(m_animationT);
|
||||
const AZ::Transform current = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
m_transformStart.GetRotation().Slerp(m_transformEnd.GetRotation(), transitionT),
|
||||
m_transformStart.GetTranslation().Lerp(m_transformEnd.GetTranslation(), transitionT));
|
||||
@@ -185,11 +197,17 @@ namespace AtomToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void ModernViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal)
|
||||
void ModernViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal, const float lookAtDistance)
|
||||
{
|
||||
m_animationT = 0.0f;
|
||||
m_cameraMode = CameraMode::Animation;
|
||||
m_transformStart = m_camera.Transform();
|
||||
m_transformEnd = worldFromLocal;
|
||||
m_lookAtAfterInterpolation = m_transformEnd.GetTranslation() + m_transformEnd.GetBasisY() * lookAtDistance;
|
||||
}
|
||||
|
||||
AZStd::optional<AZ::Vector3> ModernViewportCameraControllerInstance::LookAtAfterInterpolation() const
|
||||
{
|
||||
return m_lookAtAfterInterpolation;
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace LyIntegration
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
//! ThumbnailFeatureProcessorProviderRequests allows registering custom Feature Processors for thumbnail generation
|
||||
//! Duplicates will be ignored
|
||||
//! You can check minimal feature processors that are already registered in CommonThumbnailRenderer.cpp
|
||||
class ThumbnailFeatureProcessorProviderRequests
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//! Get a list of custom feature processors to register with thumbnail renderer
|
||||
virtual const AZStd::vector<AZStd::string>& GetCustomFeatureProcessors() const = 0;
|
||||
};
|
||||
|
||||
using ThumbnailFeatureProcessorProviderBus = AZ::EBus<ThumbnailFeatureProcessorProviderRequests>;
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
} // namespace AZ
|
||||
+28
@@ -34,12 +34,34 @@ namespace AZ
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::MaterialAsset::RTTI_Type());
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusConnect(RPI::ModelAsset::RTTI_Type());
|
||||
SystemTickBus::Handler::BusConnect();
|
||||
ThumbnailFeatureProcessorProviderBus::Handler::BusConnect();
|
||||
|
||||
m_steps[Step::Initialize] = AZStd::make_shared<InitializeStep>(this);
|
||||
m_steps[Step::FindThumbnailToRender] = AZStd::make_shared<FindThumbnailToRenderStep>(this);
|
||||
m_steps[Step::WaitForAssetsToLoad] = AZStd::make_shared<WaitForAssetsToLoadStep>(this);
|
||||
m_steps[Step::Capture] = AZStd::make_shared<CaptureStep>(this);
|
||||
m_steps[Step::ReleaseResources] = AZStd::make_shared<ReleaseResourcesStep>(this);
|
||||
|
||||
m_minimalFeatureProcessors =
|
||||
{
|
||||
"AZ::Render::TransformServiceFeatureProcessor",
|
||||
"AZ::Render::MeshFeatureProcessor",
|
||||
"AZ::Render::SimplePointLightFeatureProcessor",
|
||||
"AZ::Render::SimpleSpotLightFeatureProcessor",
|
||||
"AZ::Render::PointLightFeatureProcessor",
|
||||
// There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow
|
||||
// flickering [ATOM-13568]
|
||||
// as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now.
|
||||
// Possibly re-enable with [GFX TODO][ATOM-13639]
|
||||
// "AZ::Render::DirectionalLightFeatureProcessor",
|
||||
"AZ::Render::DiskLightFeatureProcessor",
|
||||
"AZ::Render::CapsuleLightFeatureProcessor",
|
||||
"AZ::Render::QuadLightFeatureProcessor",
|
||||
"AZ::Render::DecalTextureArrayFeatureProcessor",
|
||||
"AZ::Render::ImageBasedLightFeatureProcessor",
|
||||
"AZ::Render::PostProcessFeatureProcessor",
|
||||
"AZ::Render::SkyBoxFeatureProcessor"
|
||||
};
|
||||
}
|
||||
|
||||
CommonThumbnailRenderer::~CommonThumbnailRenderer()
|
||||
@@ -50,6 +72,7 @@ namespace AZ
|
||||
}
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler::BusDisconnect();
|
||||
SystemTickBus::Handler::BusDisconnect();
|
||||
ThumbnailFeatureProcessorProviderBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void CommonThumbnailRenderer::SetStep(Step step)
|
||||
@@ -77,6 +100,11 @@ namespace AZ
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::ExecuteQueuedEvents();
|
||||
}
|
||||
|
||||
const AZStd::vector<AZStd::string>& CommonThumbnailRenderer::GetCustomFeatureProcessors() const
|
||||
{
|
||||
return m_minimalFeatureProcessors;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<ThumbnailRendererData> CommonThumbnailRenderer::GetData() const
|
||||
{
|
||||
return m_data;
|
||||
|
||||
+9
-2
@@ -17,6 +17,8 @@
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
|
||||
|
||||
#include <AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h>
|
||||
|
||||
// Disables warning messages triggered by the Qt library
|
||||
// 4251: class needs to have dll-interface to be used by clients of class
|
||||
// 4800: forcing value to bool 'true' or 'false' (performance warning)
|
||||
@@ -34,9 +36,10 @@ namespace AZ
|
||||
|
||||
//! Provides custom rendering of material and model thumbnails
|
||||
class CommonThumbnailRenderer
|
||||
: private AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler
|
||||
: public ThumbnailRendererContext
|
||||
, private AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::MultiHandler
|
||||
, private SystemTickBus::Handler
|
||||
, public ThumbnailRendererContext
|
||||
, private ThumbnailFeatureProcessorProviderBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(CommonThumbnailRenderer, AZ::SystemAllocator, 0)
|
||||
@@ -57,9 +60,13 @@ namespace AZ
|
||||
//! SystemTickBus::Handler interface overrides...
|
||||
void OnSystemTick() override;
|
||||
|
||||
//! Render::ThumbnailFeatureProcessorProviderBus::Handler interface overrides...
|
||||
const AZStd::vector<AZStd::string>& GetCustomFeatureProcessors() const override;
|
||||
|
||||
AZStd::unordered_map<Step, AZStd::shared_ptr<ThumbnailRendererStep>> m_steps;
|
||||
Step m_currentStep = Step::None;
|
||||
AZStd::shared_ptr<ThumbnailRendererData> m_data;
|
||||
AZStd::vector<AZStd::string> m_minimalFeatureProcessors;
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace LyIntegration
|
||||
|
||||
+25
-20
@@ -11,10 +11,16 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
#include <AzCore/EBus/Results.h>
|
||||
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
|
||||
#include <Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/PostProcess/PostProcessFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/Utils/LightingPreset.h>
|
||||
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
@@ -23,10 +29,11 @@
|
||||
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
|
||||
#include <Atom/RPI.Reflect/System/RenderPipelineDescriptor.h>
|
||||
#include <Atom/RPI.Reflect/System/SceneDescriptor.h>
|
||||
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentConstants.h>
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h>
|
||||
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererData.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererContext.h>
|
||||
#include <Thumbnails/Rendering/ThumbnailRendererSteps/InitializeStep.h>
|
||||
@@ -37,7 +44,6 @@ namespace AZ
|
||||
{
|
||||
namespace Thumbnails
|
||||
{
|
||||
|
||||
InitializeStep::InitializeStep(ThumbnailRendererContext* context)
|
||||
: ThumbnailRendererStep(context)
|
||||
{
|
||||
@@ -50,24 +56,23 @@ namespace AZ
|
||||
data->m_entityContext = AZStd::make_unique<AzFramework::EntityContext>();
|
||||
data->m_entityContext->InitContext();
|
||||
|
||||
// Create and register a scene with minimum required feature processors
|
||||
// Create and register a scene with all required feature processors
|
||||
RPI::SceneDescriptor sceneDesc;
|
||||
sceneDesc.m_featureProcessorNames.push_back("AZ::Render::TransformServiceFeatureProcessor");
|
||||
sceneDesc.m_featureProcessorNames.push_back("AZ::Render::MeshFeatureProcessor");
|
||||
sceneDesc.m_featureProcessorNames.push_back("AZ::Render::SimplePointLightFeatureProcessor");
|
||||
sceneDesc.m_featureProcessorNames.push_back("AZ::Render::SimpleSpotLightFeatureProcessor");
|
||||
sceneDesc.m_featureProcessorNames.push_back("AZ::Render::PointLightFeatureProcessor");
|
||||
// There is currently a bug where having multiple DirectionalLightFeatureProcessors active can result in shadow flickering [ATOM-13568]
|
||||
// as well as continually rebuilding MeshDrawPackets [ATOM-13633]. Lets just disable the directional light FP for now.
|
||||
// Possibly re-enable with [GFX TODO][ATOM-13639]
|
||||
// sceneDesc.m_featureProcessorNames.push_back("AZ::Render::DirectionalLightFeatureProcessor");
|
||||
sceneDesc.m_featureProcessorNames.push_back("AZ::Render::DiskLightFeatureProcessor");
|
||||
sceneDesc.m_featureProcessorNames.push_back("AZ::Render::CapsuleLightFeatureProcessor");
|
||||
sceneDesc.m_featureProcessorNames.push_back("AZ::Render::QuadLightFeatureProcessor");
|
||||
sceneDesc.m_featureProcessorNames.push_back("AZ::Render::DecalTextureArrayFeatureProcessor");
|
||||
sceneDesc.m_featureProcessorNames.push_back("AZ::Render::ImageBasedLightFeatureProcessor");
|
||||
sceneDesc.m_featureProcessorNames.push_back("AZ::Render::PostProcessFeatureProcessor");
|
||||
sceneDesc.m_featureProcessorNames.push_back("AZ::Render::SkyBoxFeatureProcessor");
|
||||
|
||||
AZ::EBusAggregateResults<AZStd::vector<AZStd::string>> results;
|
||||
ThumbnailFeatureProcessorProviderBus::BroadcastResult(results, &ThumbnailFeatureProcessorProviderBus::Handler::GetCustomFeatureProcessors);
|
||||
|
||||
AZStd::set<AZStd::string> featureProcessorNames;
|
||||
for (auto& resultCollection : results.values)
|
||||
{
|
||||
for (auto& featureProcessorName : resultCollection)
|
||||
{
|
||||
if (featureProcessorNames.emplace(featureProcessorName).second)
|
||||
{
|
||||
sceneDesc.m_featureProcessorNames.push_back(featureProcessorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data->m_scene = RPI::Scene::CreateScene(sceneDesc);
|
||||
|
||||
|
||||
+3
-2
@@ -10,11 +10,12 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h
|
||||
Include/AtomLyIntegration/CommonFeatures/ReflectionProbe/EditorReflectionProbeBus.h
|
||||
Include/AtomLyIntegration/CommonFeatures/Thumbnails/ThumbnailFeatureProcessorProviderBus.h
|
||||
Source/Module.cpp
|
||||
Source/Animation/EditorAttachmentComponent.h
|
||||
Source/Animation/EditorAttachmentComponent.cpp
|
||||
Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h
|
||||
Include/AtomLyIntegration/CommonFeatures/ReflectionProbe/EditorReflectionProbeBus.h
|
||||
Source/EditorCommonFeaturesSystemComponent.h
|
||||
Source/EditorCommonFeaturesSystemComponent.cpp
|
||||
Source/CoreLights/EditorAreaLightComponent.h
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
if(NOT PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
ly_add_target(
|
||||
NAME DccScriptingInterface.Static STATIC
|
||||
NAMESPACE Gem
|
||||
@@ -38,3 +42,9 @@ ly_add_target(
|
||||
PRIVATE
|
||||
Gem::DccScriptingInterface.Static
|
||||
)
|
||||
|
||||
# Any 'tool' type applications should use Gem::DccScriptingInterface.Editor:
|
||||
ly_create_alias(NAME DccScriptingInterface.Tools NAMESPACE Gem TARGETS Gem::DccScriptingInterface.Editor)
|
||||
# Add an empty 'builders' alias to allow the DccScriptInterface root gem path to be added to the generated
|
||||
# cmake_dependencies.<project>.assetprocessor.setreg to allow the asset scan folder for it to be added
|
||||
ly_create_alias(NAME DccScriptingInterface.Builders NAMESPACE Gem)
|
||||
|
||||
@@ -165,8 +165,8 @@ namespace EMotionFX
|
||||
const AZ::Outcome<size_t> boolYParamIndexOutcome = m_animGraphInstance->FindParameterIndex(nameBoolY);
|
||||
success = boolXParamIndexOutcome.IsSuccess() && boolYParamIndexOutcome.IsSuccess();
|
||||
|
||||
uint32 boolXOutputPortIndex;
|
||||
uint32 boolYOutputPortIndex;
|
||||
uint32 boolXOutputPortIndex = InvalidIndex32;
|
||||
uint32 boolYOutputPortIndex = InvalidIndex32;
|
||||
const int portIndicesTosetCount = 2;
|
||||
int portIndicesFound = 0;
|
||||
const AZStd::vector<EMotionFX::AnimGraphNode::Port>& parameterNodeOutputPorts = parameterNode->GetOutputPorts();
|
||||
|
||||
+15
-6
@@ -612,7 +612,9 @@ FN_DECIMAL FastNoise::SingleValue(unsigned char offset, FN_DECIMAL x, FN_DECIMAL
|
||||
int y1 = y0 + 1;
|
||||
int z1 = z0 + 1;
|
||||
|
||||
FN_DECIMAL xs, ys, zs;
|
||||
FN_DECIMAL xs = 0.0f;
|
||||
FN_DECIMAL ys = 0.0f;
|
||||
FN_DECIMAL zs = 0.0f;
|
||||
switch (m_interp)
|
||||
{
|
||||
case Linear:
|
||||
@@ -726,7 +728,8 @@ FN_DECIMAL FastNoise::SingleValue(unsigned char offset, FN_DECIMAL x, FN_DECIMAL
|
||||
int x1 = x0 + 1;
|
||||
int y1 = y0 + 1;
|
||||
|
||||
FN_DECIMAL xs, ys;
|
||||
FN_DECIMAL xs = 0.0f;
|
||||
FN_DECIMAL ys = 0.0f;
|
||||
switch (m_interp)
|
||||
{
|
||||
case Linear:
|
||||
@@ -840,7 +843,9 @@ FN_DECIMAL FastNoise::SinglePerlin(unsigned char offset, FN_DECIMAL x, FN_DECIMA
|
||||
int y1 = y0 + 1;
|
||||
int z1 = z0 + 1;
|
||||
|
||||
FN_DECIMAL xs, ys, zs;
|
||||
FN_DECIMAL xs = 0.0f;
|
||||
FN_DECIMAL ys = 0.0f;
|
||||
FN_DECIMAL zs = 0.0f;
|
||||
switch (m_interp)
|
||||
{
|
||||
case Linear:
|
||||
@@ -962,7 +967,8 @@ FN_DECIMAL FastNoise::SinglePerlin(unsigned char offset, FN_DECIMAL x, FN_DECIMA
|
||||
int x1 = x0 + 1;
|
||||
int y1 = y0 + 1;
|
||||
|
||||
FN_DECIMAL xs, ys;
|
||||
FN_DECIMAL xs = 0.0f;
|
||||
FN_DECIMAL ys = 0.0f;
|
||||
switch (m_interp)
|
||||
{
|
||||
case Linear:
|
||||
@@ -1699,7 +1705,9 @@ FN_DECIMAL FastNoise::SingleCellular(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) c
|
||||
int zr = FastRound(z);
|
||||
|
||||
FN_DECIMAL distance = 999999;
|
||||
int xc, yc, zc;
|
||||
int xc = 0;
|
||||
int yc = 0;
|
||||
int zc = 0;
|
||||
|
||||
switch (m_cellularDistanceFunction)
|
||||
{
|
||||
@@ -1923,7 +1931,8 @@ FN_DECIMAL FastNoise::SingleCellular(FN_DECIMAL x, FN_DECIMAL y) const
|
||||
int yr = FastRound(y);
|
||||
|
||||
FN_DECIMAL distance = 999999;
|
||||
int xc, yc;
|
||||
int xc = 0;
|
||||
int yc = 0;
|
||||
|
||||
switch (m_cellularDistanceFunction)
|
||||
{
|
||||
|
||||
@@ -1072,8 +1072,7 @@ namespace GraphCanvas
|
||||
|
||||
if (!id.empty())
|
||||
{
|
||||
Selector selector = Selector::Get(id);
|
||||
result.emplace_back(selector);
|
||||
result.emplace_back(Selector::Get(id));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1111,8 +1110,7 @@ namespace GraphCanvas
|
||||
{
|
||||
bits.emplace_back(stateSelector);
|
||||
}
|
||||
Selector selector = aznew CompoundSelector(std::move(bits));
|
||||
nestedSelectors.emplace_back(selector);
|
||||
nestedSelectors.emplace_back(aznew CompoundSelector(std::move(bits)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1239,7 +1239,7 @@ namespace GraphCanvas
|
||||
|
||||
bool GraphUtils::IsValidModelConnection(const GraphId& graphId, const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint)
|
||||
{
|
||||
bool validConnection;
|
||||
bool validConnection = false;
|
||||
|
||||
AZStd::unordered_set< Endpoint > finalSourceEndpoints = RemapEndpointForModel(sourceEndpoint);
|
||||
AZStd::unordered_set< Endpoint > finalTargetEndpoints = RemapEndpointForModel(targetEndpoint);
|
||||
|
||||
@@ -23,10 +23,6 @@
|
||||
#include <QPainter>
|
||||
#include <QStaticText>
|
||||
|
||||
static const QColor timeMarkerCol = QColor(255, 0, 255);
|
||||
static const QColor textCol = QColor(0, 0, 0);
|
||||
static const QColor ltgrayCol = QColor(110, 110, 110);
|
||||
|
||||
QColor InterpolateColor(const QColor& c1, const QColor& c2, float fraction)
|
||||
{
|
||||
const int r = (c2.red() - c1.red()) * fraction + c1.red();
|
||||
|
||||
@@ -48,7 +48,6 @@ static const EUiAnimCurveType DEFAULT_TRACK_TYPE = eUiAnimCurveType_BezierFloat;
|
||||
|
||||
// Old serialization values that are no longer
|
||||
// defined in IUiAnimationSystem.h, but needed for conversion:
|
||||
static const int OLD_APARAM_USER = 100;
|
||||
static const int OLD_ACURVE_GOTO = 21;
|
||||
static const int OLD_APARAM_PARTICLE_COUNT_SCALE = 95;
|
||||
static const int OLD_APARAM_PARTICLE_PULSE_PERIOD = 96;
|
||||
|
||||
@@ -691,7 +691,7 @@ IUiAnimTrack* CUiAnimAzEntityNode::CreateTrackForAzField(const UiAnimParamData&
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EUiAnimValue valueType;
|
||||
EUiAnimValue valueType = eUiAnimValue_Unknown;
|
||||
switch (numElements)
|
||||
{
|
||||
case 2:
|
||||
|
||||
@@ -375,7 +375,7 @@ namespace LyShine
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void LyShineSystemComponent::OnCrySystemInitialized(ISystem& system, [[maybe_unused]] const SSystemInitParams& startupParams)
|
||||
void LyShineSystemComponent::OnCrySystemInitialized([[maybe_unused]] ISystem& system, [[maybe_unused]] const SSystemInitParams& startupParams)
|
||||
{
|
||||
#if !defined(AZ_MONOLITHIC_BUILD)
|
||||
// When module is linked dynamically, we must set our gEnv pointer.
|
||||
|
||||
@@ -107,7 +107,8 @@ void UiLayoutGridComponent::ApplyLayoutHeight()
|
||||
AZStd::vector<AZ::EntityId> childEntityIds;
|
||||
EBUS_EVENT_ID_RESULT(childEntityIds, GetEntityId(), UiElementBus, GetChildEntityIds);
|
||||
int childIndex = 0;
|
||||
int columnIndex, rowIndex;
|
||||
int columnIndex = 0;
|
||||
int rowIndex = 0;
|
||||
for (auto child : childEntityIds)
|
||||
{
|
||||
// Set the anchors
|
||||
@@ -627,7 +628,8 @@ AZ::Vector2 UiLayoutGridComponent::GetChildrenBoundingRectSize(const AZ::Vector2
|
||||
UiLayoutHelpers::GetSizeInsidePadding(GetEntityId(), m_padding, layoutRectSize);
|
||||
|
||||
// Calculate number of rows and columns
|
||||
int numColumns, numRows;
|
||||
int numColumns = 0;
|
||||
int numRows = 0;
|
||||
switch (m_startingDirection)
|
||||
{
|
||||
case StartingDirection::HorizontalOrder:
|
||||
|
||||
@@ -151,6 +151,8 @@ namespace UiNavigationHelpers
|
||||
}
|
||||
|
||||
UiTransformInterface::Rect parentRect;
|
||||
parentRect.Set(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
AZ::Matrix4x4 parentTransformFromViewport;
|
||||
if (parentElement.IsValid() && !isCurElementDescendantOfParentElement)
|
||||
{
|
||||
|
||||
@@ -60,7 +60,6 @@ static const EAnimCurveType DEFAULT_TRACK_TYPE = eAnimCurveType_BezierFloat;
|
||||
|
||||
// Old serialization values that are no longer
|
||||
// defined in IMovieSystem.h, but needed for conversion:
|
||||
static const int OLD_APARAM_USER = 100;
|
||||
static const int OLD_ACURVE_GOTO = 21;
|
||||
static const int OLD_APARAM_PARTICLE_COUNT_SCALE = 95;
|
||||
static const int OLD_APARAM_PARTICLE_PULSE_PERIOD = 96;
|
||||
|
||||
@@ -281,7 +281,6 @@ void CAnimPostFXNode::SerializeAnims(XmlNodeRef& xmlNode, bool bLoading, bool bL
|
||||
paramType.Serialize(trackNode, true);
|
||||
// Don't use APARAM_USER because it could change in newer versions
|
||||
// CAnimNode::SerializeAnims will then take care of that
|
||||
static const unsigned int OLD_APARAM_USER = 100;
|
||||
paramType = static_cast<AnimParamType>(static_cast<int>(paramType.GetType()) + OLD_APARAM_USER);
|
||||
paramType.Serialize(trackNode, false);
|
||||
}
|
||||
|
||||
@@ -51,11 +51,11 @@ namespace Audio
|
||||
// To avoid errors, we initialize COM here with the same model.
|
||||
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
|
||||
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
|
||||
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
|
||||
const CLSID CLSID_MMDeviceEnumerator_UUID = __uuidof(MMDeviceEnumerator);
|
||||
const IID IID_IMMDeviceEnumerator_UUID = __uuidof(IMMDeviceEnumerator);
|
||||
HRESULT hresult = CoCreateInstance(
|
||||
CLSID_MMDeviceEnumerator, nullptr,
|
||||
CLSCTX_ALL, IID_IMMDeviceEnumerator,
|
||||
CLSID_MMDeviceEnumerator_UUID, nullptr,
|
||||
CLSCTX_ALL, IID_IMMDeviceEnumerator_UUID,
|
||||
reinterpret_cast<void**>(&m_enumerator)
|
||||
);
|
||||
|
||||
@@ -133,8 +133,8 @@ namespace Audio
|
||||
AZ_Assert(m_device != nullptr, "Attempting to start a Microphone session while the device is uninitialized - Windows!\n");
|
||||
|
||||
// Get the IAudioClient from the device
|
||||
const IID IID_IAudioClient = __uuidof(IAudioClient);
|
||||
HRESULT hresult = m_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, reinterpret_cast<void**>(&m_audioClient));
|
||||
const IID IID_IAudioClient_UUID = __uuidof(IAudioClient);
|
||||
HRESULT hresult = m_device->Activate(IID_IAudioClient_UUID, CLSCTX_ALL, nullptr, reinterpret_cast<void**>(&m_audioClient));
|
||||
|
||||
if (FAILED(hresult))
|
||||
{
|
||||
@@ -182,8 +182,8 @@ namespace Audio
|
||||
}
|
||||
|
||||
// Get the IAudioCaptureClient
|
||||
const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
|
||||
hresult = m_audioClient->GetService(IID_IAudioCaptureClient, reinterpret_cast<void**>(&m_audioCaptureClient));
|
||||
const IID IID_IAudioCaptureClient_UUID = __uuidof(IAudioCaptureClient);
|
||||
hresult = m_audioClient->GetService(IID_IAudioCaptureClient_UUID, reinterpret_cast<void**>(&m_audioCaptureClient));
|
||||
|
||||
if (FAILED(hresult))
|
||||
{
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace Multiplayer
|
||||
using EntityMigrationStartEvent = AZ::Event<ClientInputId>;
|
||||
using EntityMigrationEndEvent = AZ::Event<>;
|
||||
using EntityServerMigrationEvent = AZ::Event<const ConstNetworkEntityHandle&, HostId, AzNetworking::ConnectionId>;
|
||||
using EntityPreRenderEvent = AZ::Event<float, float>;
|
||||
|
||||
//! @class NetBindComponent
|
||||
//! @brief Component that provides net-binding to a networked entity.
|
||||
@@ -97,6 +98,7 @@ namespace Multiplayer
|
||||
void NotifyMigrationStart(ClientInputId migratedInputId);
|
||||
void NotifyMigrationEnd();
|
||||
void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId);
|
||||
void NotifyPreRender(float deltaTime, float blendFactor);
|
||||
|
||||
void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler);
|
||||
void AddEntityDirtiedEventHandler(EntityDirtiedEvent::Handler& eventHandler);
|
||||
@@ -104,6 +106,7 @@ namespace Multiplayer
|
||||
void AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler);
|
||||
void AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler);
|
||||
void AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler);
|
||||
void AddEntityPreRenderEventHandler(EntityPreRenderEvent::Handler& eventHandler);
|
||||
|
||||
bool SerializeEntityCorrection(AzNetworking::ISerializer& serializer);
|
||||
|
||||
@@ -152,6 +155,7 @@ namespace Multiplayer
|
||||
EntityMigrationStartEvent m_entityMigrationStartEvent;
|
||||
EntityMigrationEndEvent m_entityMigrationEndEvent;
|
||||
EntityServerMigrationEvent m_entityServerMigrationEvent;
|
||||
EntityPreRenderEvent m_entityPreRenderEvent;
|
||||
AZ::Event<> m_onRemove;
|
||||
RpcSendEvent::Handler m_handleLocalServerRpcMessageEventHandle;
|
||||
AZ::Event<>::Handler m_handleMarkedDirty;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Source/AutoGen/NetworkTransformComponent.AutoComponent.h>
|
||||
#include <Multiplayer/Components/NetBindComponent.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
|
||||
namespace Multiplayer
|
||||
@@ -32,13 +33,22 @@ namespace Multiplayer
|
||||
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
|
||||
private:
|
||||
void OnPreRender(float deltaTime, float blendFactor);
|
||||
|
||||
void OnRotationChangedEvent(const AZ::Quaternion& rotation);
|
||||
void OnTranslationChangedEvent(const AZ::Vector3& translation);
|
||||
void OnScaleChangedEvent(float scale);
|
||||
void OnResetCountChangedEvent();
|
||||
|
||||
AZ::Transform m_previousTransform = AZ::Transform::CreateIdentity();
|
||||
AZ::Transform m_targetTransform = AZ::Transform::CreateIdentity();
|
||||
|
||||
AZ::Event<AZ::Quaternion>::Handler m_rotationEventHandler;
|
||||
AZ::Event<AZ::Vector3>::Handler m_translationEventHandler;
|
||||
AZ::Event<float>::Handler m_scaleEventHandler;
|
||||
AZ::Event<uint8_t>::Handler m_resetCountEventHandler;
|
||||
|
||||
EntityPreRenderEvent::Handler m_entityPreRenderEventHandler;
|
||||
};
|
||||
|
||||
class NetworkTransformComponentController
|
||||
|
||||
+4
-4
@@ -45,10 +45,10 @@ namespace Multiplayer
|
||||
static constexpr uint32_t MaxRecordBits = 2048;
|
||||
|
||||
ReplicationRecord() = default;
|
||||
ReplicationRecord(NetEntityRole netEntityRole);
|
||||
ReplicationRecord(NetEntityRole remoteNetEntityRole);
|
||||
|
||||
void SetNetworkRole(NetEntityRole netEntityRole);
|
||||
NetEntityRole GetNetworkRole() const;
|
||||
void SetRemoteNetworkRole(NetEntityRole remoteNetEntityRole);
|
||||
NetEntityRole GetRemoteNetworkRole() const;
|
||||
|
||||
bool AreAllBitsConsumed() const;
|
||||
void ResetConsumedBits();
|
||||
@@ -92,6 +92,6 @@ namespace Multiplayer
|
||||
// Sequence number this ReplicationRecord was sent on
|
||||
AzNetworking::PacketId m_sentPacketId = AzNetworking::InvalidPacketId;
|
||||
|
||||
NetEntityRole m_netEntityRole = NetEntityRole::InvalidRole;;
|
||||
NetEntityRole m_remoteNetEntityRole = NetEntityRole::InvalidRole;;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ void Handle{{ PropertyName }}(AzNetworking::IConnection* invokingConnection, {{
|
||||
//! {{ PropertyName }} Handler
|
||||
//! {{ Property.attrib['Description'] }}
|
||||
//! HandleOn {{ HandleOn }}
|
||||
virtual void Handle{{ PropertyName }}(AzNetworking::IConnection* invokingConnection, {{ ', '.join(paramDefines) }}) = 0;
|
||||
virtual void Handle{{ PropertyName }}([[maybe_unused]] AzNetworking::IConnection* invokingConnection, [[maybe_unused]] {{ ', [[maybe_unused]] '.join(paramDefines) }}) {}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{#
|
||||
|
||||
@@ -311,7 +311,7 @@ void {{ ClassName }}::Set{{ UpperFirst(Property.attrib['Name']) }}(const {{ Prop
|
||||
{{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }}
|
||||
void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramDefines) }})
|
||||
{
|
||||
constexpr RpcIndex rpcId = static_cast<RpcIndex>({{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ UpperFirst(Property.attrib['Name']) }});
|
||||
constexpr Multiplayer::RpcIndex rpcId = static_cast<Multiplayer::RpcIndex>({{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ UpperFirst(Property.attrib['Name']) }});
|
||||
{% if Property.attrib['IsReliable']|booleanTrue %}
|
||||
constexpr AzNetworking::ReliabilityType isReliable = Multiplayer::ReliabilityType::Reliable;
|
||||
{% else %}
|
||||
@@ -368,6 +368,31 @@ void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.jo
|
||||
->Method("{{ UpperFirst(Property.attrib['Name']) }}", [](const {{ ClassName }}* self, {{ ', '.join(paramDefines) }}) {
|
||||
self->m_controller->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }});
|
||||
})
|
||||
->Method("{{ UpperFirst(Property.attrib['Name']) }}ByEntity", [](AZ::EntityId id, {{ ', '.join(paramDefines) }}) {
|
||||
|
||||
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(id);
|
||||
if (!entity)
|
||||
{
|
||||
AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }} failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
|
||||
return;
|
||||
}
|
||||
|
||||
{{ ClassName }}* networkComponent = entity->FindComponent<{{ ClassName }}>();
|
||||
if (!networkComponent)
|
||||
{
|
||||
AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }} failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str())
|
||||
return;
|
||||
}
|
||||
|
||||
{{ ClassName }}Controller* controller = static_cast<{{ ClassName }}Controller*>(networkComponent->GetController());
|
||||
if (!controller)
|
||||
{
|
||||
AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }} method failed. Entity '%s' (id: %s) {{ ClassName }} is missing the network controller. This RemoteProcedure can only be invoked from {{InvokeFrom}} network entities, because this entity doesn't have a controller, it must not be a {{InvokeFrom}} entity. Please check your network context before attempting to call {{ UpperFirst(Property.attrib['Name']) }}.", entity->GetName().c_str(), id.ToString().c_str())
|
||||
return;
|
||||
}
|
||||
|
||||
controller->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }});
|
||||
})
|
||||
{% endif %}
|
||||
{% endcall %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace Multiplayer
|
||||
AZ_CVAR(AZ::TimeMs, cl_MaxRewindHistoryMs, AZ::TimeMs{ 2000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum number of milliseconds to keep for server correction rewind and replay");
|
||||
#ifndef AZ_RELEASE_BUILD
|
||||
AZ_CVAR(float, cl_DebugHackTimeMultiplier, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Scalar value used to simulate clock hacking cheats for validating bank time system and anticheat");
|
||||
AZ_CVAR(bool, cl_EnableDesyncDebugging, false, nullptr, AZ::ConsoleFunctorFlags::Null, "If enabled, debug logs will contain verbose information on detected state desyncs");
|
||||
#endif
|
||||
|
||||
AZ_CVAR(bool, sv_EnableCorrections, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Enables server corrections on autonomous proxy desyncs");
|
||||
@@ -214,11 +215,12 @@ namespace Multiplayer
|
||||
// Send correction
|
||||
SendClientInputCorrection(GetLastInputId(), correction);
|
||||
|
||||
#ifdef _DEBUG
|
||||
// In debug, show which states caused the correction
|
||||
#ifndef AZ_RELEASE_BUILD
|
||||
AZStd::string clientStateString;
|
||||
AZStd::string serverStateString;
|
||||
if (cl_EnableDesyncDebugging)
|
||||
{
|
||||
// In debug, show which states caused the correction
|
||||
// Write in client state
|
||||
AzNetworking::NetworkOutputSerializer clientStateSerializer(clientState.GetBuffer(), clientState.GetSize());
|
||||
GetNetBindComponent()->SerializeEntityCorrection(clientStateSerializer);
|
||||
@@ -236,11 +238,13 @@ namespace Multiplayer
|
||||
GetNetBindComponent()->SerializeEntityCorrection(serverValues);
|
||||
|
||||
AZStd::map<AZStd::string, AZStd::pair<AZStd::string, AZStd::string>> mapComparison;
|
||||
|
||||
// put the server value in the first part of the pair
|
||||
for (const auto& pair : serverValues.GetValueMap())
|
||||
{
|
||||
mapComparison[pair.first].first = pair.second;
|
||||
}
|
||||
|
||||
// put the client value in the second part of the pair
|
||||
for (const auto& pair : clientValues.GetValueMap())
|
||||
{
|
||||
@@ -266,12 +270,13 @@ namespace Multiplayer
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
const AZStd::string clientStateString = "available in debug only";
|
||||
const AZStd::string serverStateString = "available in debug only";
|
||||
#endif
|
||||
|
||||
else
|
||||
{
|
||||
clientStateString = "available in debug only";
|
||||
serverStateString = "available in debug only";
|
||||
}
|
||||
AZLOG_ERROR("** Autonomous proxy desync detected! ** clientState=[%s], serverState=[%s]", clientStateString.c_str(), serverStateString.c_str());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -416,7 +421,7 @@ namespace Multiplayer
|
||||
|
||||
ClientInputId LocalPredictionPlayerInputComponentController::GetLastInputId() const
|
||||
{
|
||||
return m_clientInputId;
|
||||
return m_lastClientInputId;
|
||||
}
|
||||
|
||||
HostFrameId LocalPredictionPlayerInputComponentController::GetInputFrameId(const NetworkInput& input) const
|
||||
@@ -520,10 +525,13 @@ namespace Multiplayer
|
||||
|
||||
// In debug, send the entire client output state to the server to make it easier to debug desync issues
|
||||
AzNetworking::PacketEncodingBuffer processInputResult;
|
||||
#ifdef _DEBUG
|
||||
AzNetworking::NetworkInputSerializer processInputResultSerializer(processInputResult.GetBuffer(), processInputResult.GetCapacity());
|
||||
GetNetBindComponent()->SerializeEntityCorrection(processInputResultSerializer);
|
||||
processInputResult.Resize(processInputResultSerializer.GetSize());
|
||||
#ifndef AZ_RELEASE_BUILD
|
||||
if (cl_EnableDesyncDebugging)
|
||||
{
|
||||
AzNetworking::NetworkInputSerializer processInputResultSerializer(processInputResult.GetBuffer(), processInputResult.GetCapacity());
|
||||
GetNetBindComponent()->SerializeEntityCorrection(processInputResultSerializer);
|
||||
processInputResult.Resize(processInputResultSerializer.GetSize());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Save this input and discard move history outside our client rewind window
|
||||
|
||||
@@ -390,6 +390,11 @@ namespace Multiplayer
|
||||
m_entityServerMigrationEvent.Signal(m_netEntityHandle, hostId, connectionId);
|
||||
}
|
||||
|
||||
void NetBindComponent::NotifyPreRender(float deltaTime, float blendFactor)
|
||||
{
|
||||
m_entityPreRenderEvent.Signal(deltaTime, blendFactor);
|
||||
}
|
||||
|
||||
void NetBindComponent::AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler)
|
||||
{
|
||||
eventHandler.Connect(m_entityStopEvent);
|
||||
@@ -420,6 +425,11 @@ namespace Multiplayer
|
||||
eventHandler.Connect(m_entityServerMigrationEvent);
|
||||
}
|
||||
|
||||
void NetBindComponent::AddEntityPreRenderEventHandler(EntityPreRenderEvent::Handler& eventHandler)
|
||||
{
|
||||
eventHandler.Connect(m_entityPreRenderEvent);
|
||||
}
|
||||
|
||||
bool NetBindComponent::SerializeEntityCorrection(AzNetworking::ISerializer& serializer)
|
||||
{
|
||||
m_predictableRecord.ResetConsumedBits();
|
||||
|
||||
@@ -33,6 +33,8 @@ namespace Multiplayer
|
||||
: m_rotationEventHandler([this](const AZ::Quaternion& rotation) { OnRotationChangedEvent(rotation); })
|
||||
, m_translationEventHandler([this](const AZ::Vector3& translation) { OnTranslationChangedEvent(translation); })
|
||||
, m_scaleEventHandler([this](float scale) { OnScaleChangedEvent(scale); })
|
||||
, m_resetCountEventHandler([this](const uint8_t&) { OnResetCountChangedEvent(); })
|
||||
, m_entityPreRenderEventHandler([this](float deltaTime, float blendFactor) { OnPreRender(deltaTime, blendFactor); })
|
||||
{
|
||||
;
|
||||
}
|
||||
@@ -47,6 +49,11 @@ namespace Multiplayer
|
||||
RotationAddEvent(m_rotationEventHandler);
|
||||
TranslationAddEvent(m_translationEventHandler);
|
||||
ScaleAddEvent(m_scaleEventHandler);
|
||||
ResetCountAddEvent(m_resetCountEventHandler);
|
||||
GetNetBindComponent()->AddEntityPreRenderEventHandler(m_entityPreRenderEventHandler);
|
||||
|
||||
// When coming into relevance, reset all blending factors so we don't interpolate to our start position
|
||||
OnResetCountChangedEvent();
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
@@ -56,23 +63,40 @@ namespace Multiplayer
|
||||
|
||||
void NetworkTransformComponent::OnRotationChangedEvent(const AZ::Quaternion& rotation)
|
||||
{
|
||||
AZ::Transform worldTm = GetTransformComponent()->GetWorldTM();
|
||||
worldTm.SetRotation(rotation);
|
||||
GetTransformComponent()->SetWorldTM(worldTm);
|
||||
m_previousTransform.SetRotation(m_targetTransform.GetRotation());
|
||||
m_targetTransform.SetRotation(rotation);
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::OnTranslationChangedEvent(const AZ::Vector3& translation)
|
||||
{
|
||||
AZ::Transform worldTm = GetTransformComponent()->GetWorldTM();
|
||||
worldTm.SetTranslation(translation);
|
||||
GetTransformComponent()->SetWorldTM(worldTm);
|
||||
m_previousTransform.SetTranslation(m_targetTransform.GetTranslation());
|
||||
m_targetTransform.SetTranslation(translation);
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::OnScaleChangedEvent(float scale)
|
||||
{
|
||||
AZ::Transform worldTm = GetTransformComponent()->GetWorldTM();
|
||||
worldTm.SetUniformScale(scale);
|
||||
GetTransformComponent()->SetWorldTM(worldTm);
|
||||
m_previousTransform.SetUniformScale(m_targetTransform.GetUniformScale());
|
||||
m_targetTransform.SetUniformScale(scale);
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::OnResetCountChangedEvent()
|
||||
{
|
||||
m_targetTransform.SetRotation(GetRotation());
|
||||
m_targetTransform.SetTranslation(GetTranslation());
|
||||
m_targetTransform.SetUniformScale(GetScale());
|
||||
m_previousTransform = m_targetTransform;
|
||||
}
|
||||
|
||||
void NetworkTransformComponent::OnPreRender([[maybe_unused]] float deltaTime, float blendFactor)
|
||||
{
|
||||
if (!HasController())
|
||||
{
|
||||
AZ::Transform blendTransform;
|
||||
blendTransform.SetRotation(m_previousTransform.GetRotation().Slerp(m_targetTransform.GetRotation(), blendFactor));
|
||||
blendTransform.SetTranslation(m_previousTransform.GetTranslation().Lerp(m_targetTransform.GetTranslation(), blendFactor));
|
||||
blendTransform.SetUniformScale(AZ::Lerp(m_previousTransform.GetUniformScale(), m_targetTransform.GetUniformScale(), blendFactor));
|
||||
GetTransformComponent()->SetWorldTM(blendTransform);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -96,11 +120,8 @@ namespace Multiplayer
|
||||
|
||||
void NetworkTransformComponentController::OnTransformChangedEvent(const AZ::Transform& worldTm)
|
||||
{
|
||||
if (IsAuthority())
|
||||
{
|
||||
SetRotation(worldTm.GetRotation());
|
||||
SetTranslation(worldTm.GetTranslation());
|
||||
SetScale(worldTm.GetUniformScale());
|
||||
}
|
||||
SetRotation(worldTm.GetRotation());
|
||||
SetTranslation(worldTm.GetTranslation());
|
||||
SetScale(worldTm.GetUniformScale());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace Multiplayer
|
||||
AZ::CVarFixedString remoteAddress;
|
||||
uint16_t remotePort;
|
||||
if (console->GetCvarValue("editorsv_serveraddr", remoteAddress) != AZ::GetValueResult::ConsoleVarNotFound &&
|
||||
console->GetCvarValue("editorsv_port", remotePort) != AZ::GetValueResult::ConsoleVarNotFound)
|
||||
console->GetCvarValue("sv_port", remotePort) != AZ::GetValueResult::ConsoleVarNotFound)
|
||||
{
|
||||
// Connect the Editor to the editor server for Multiplayer simulation
|
||||
AZ::Interface<IMultiplayer>::Get()->InitializeMultiplayer(MultiplayerAgentType::Client);
|
||||
@@ -149,6 +149,8 @@ namespace Multiplayer
|
||||
|
||||
const IpAddress ipAddress(remoteAddress.c_str(), remotePort, networkInterface->GetType());
|
||||
networkInterface->Connect(ipAddress);
|
||||
|
||||
AZ::Interface<IMultiplayer>::Get()->SendReadyForEntityUpdates(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace Multiplayer
|
||||
|
||||
// BeginGameMode and Prefab Processing have completed at this point
|
||||
IMultiplayerTools* mpTools = AZ::Interface<IMultiplayerTools>::Get();
|
||||
if (editorsv_enabled && mpTools != nullptr && mpTools->DidProcessNetworkPrefabs())
|
||||
if (editorsv_enabled && mpTools != nullptr)
|
||||
{
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& assetData = prefabEditorEntityOwnershipInterface->GetPlayInEditorAssetData();
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include <Multiplayer/MultiplayerConstants.h>
|
||||
#include <Multiplayer/Components/MultiplayerComponent.h>
|
||||
|
||||
#include <MultiplayerSystemComponent.h>
|
||||
#include <ConnectionData/ClientToServerConnectionData.h>
|
||||
#include <ConnectionData/ServerToClientConnectionData.h>
|
||||
@@ -24,14 +23,23 @@
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/Utils.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
#include <AzCore/Math/ShapeIntersection.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Asset/AssetManagerBus.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <AzFramework/Components/CameraBus.h>
|
||||
#include <AzFramework/Visibility/IVisibilitySystem.h>
|
||||
#include <AzFramework/Visibility/EntityBoundsUnionBus.h>
|
||||
#include <AzFramework/Spawnable/Spawnable.h>
|
||||
|
||||
#include <AzNetworking/Framework/INetworking.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace AZ::ConsoleTypeHelpers
|
||||
{
|
||||
template <>
|
||||
@@ -74,6 +82,7 @@ namespace Multiplayer
|
||||
AZ_CVAR(ProtocolType, sv_protocol, ProtocolType::Udp, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "This flag controls whether we use TCP or UDP for game networking");
|
||||
AZ_CVAR(bool, sv_isDedicated, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Whether the host command creates an independent or client hosted server");
|
||||
AZ_CVAR(AZ::TimeMs, cl_defaultNetworkEntityActivationTimeSliceMs, AZ::TimeMs{ 0 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Max Ms to use to activate entities coming from the network, 0 means instantiate everything");
|
||||
AZ_CVAR(AZ::TimeMs, sv_serverSendRateMs, AZ::TimeMs{ 50 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum number of milliseconds between each network update");
|
||||
AZ_CVAR(AZ::CVarFixedString, sv_defaultPlayerSpawnAsset, "prefabs/player.network.spawnable", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The default spawnable to use when a new player connects");
|
||||
|
||||
void MultiplayerSystemComponent::Reflect(AZ::ReflectContext* context)
|
||||
@@ -156,10 +165,26 @@ namespace Multiplayer
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void MultiplayerSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
void MultiplayerSystemComponent::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
{
|
||||
AZ::TimeMs deltaTimeMs = aznumeric_cast<AZ::TimeMs>(static_cast<int32_t>(deltaTime * 1000.0f));
|
||||
AZ::TimeMs hostTimeMs = AZ::GetElapsedTimeMs();
|
||||
const AZ::TimeMs deltaTimeMs = aznumeric_cast<AZ::TimeMs>(static_cast<int32_t>(deltaTime * 1000.0f));
|
||||
const AZ::TimeMs hostTimeMs = AZ::GetElapsedTimeMs();
|
||||
const AZ::TimeMs serverRateMs = static_cast<AZ::TimeMs>(sv_serverSendRateMs);
|
||||
const float serverRateSeconds = static_cast<float>(serverRateMs) / 1000.0f;
|
||||
|
||||
TickVisibleNetworkEntities(deltaTime, serverRateSeconds);
|
||||
|
||||
if (GetAgentType() == MultiplayerAgentType::ClientServer
|
||||
|| GetAgentType() == MultiplayerAgentType::DedicatedServer)
|
||||
{
|
||||
m_serverSendAccumulator += deltaTime;
|
||||
if (m_serverSendAccumulator < serverRateSeconds)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_serverSendAccumulator -= serverRateSeconds;
|
||||
m_networkTime.IncrementHostFrameId();
|
||||
}
|
||||
|
||||
// Handle deferred local rpc messages that were generated during the updates
|
||||
m_networkEntityManager.DispatchLocalDeferredRpcMessages();
|
||||
@@ -365,13 +390,21 @@ namespace Multiplayer
|
||||
}
|
||||
|
||||
EntityReplicationManager& replicationManager = reinterpret_cast<IConnectionData*>(connection->GetUserData())->GetReplicationManager();
|
||||
|
||||
// Ignore a_Request.GetServerGameTimePoint(), clients can't affect the server gametime
|
||||
|
||||
if ((GetAgentType() == MultiplayerAgentType::Client) && (packet.GetHostFrameId() > m_lastReplicatedHostFrameId))
|
||||
{
|
||||
// Update client to latest server time
|
||||
m_renderBlendFactor = 0.0f;
|
||||
m_lastReplicatedHostTimeMs = packet.GetHostTimeMs();
|
||||
m_lastReplicatedHostFrameId = packet.GetHostFrameId();
|
||||
m_networkTime.AlterTime(m_lastReplicatedHostFrameId, m_lastReplicatedHostTimeMs, AzNetworking::InvalidConnectionId);
|
||||
}
|
||||
|
||||
for (AZStd::size_t i = 0; i < packet.GetEntityMessages().size(); ++i)
|
||||
{
|
||||
const NetworkEntityUpdateMessage& updateMessage = packet.GetEntityMessages()[i];
|
||||
handledAll &= replicationManager.HandleEntityUpdateMessage(connection, packetHeader, updateMessage);
|
||||
AZ_Assert(handledAll, "GameServerToClientNetworkRequestHandler EntityUpdates Did not handle all updates");
|
||||
AZ_Assert(handledAll, "EntityUpdates did not handle all update messages");
|
||||
}
|
||||
|
||||
return handledAll;
|
||||
@@ -440,7 +473,7 @@ namespace Multiplayer
|
||||
|
||||
// Hosts will spawn a new default player prefab for the user that just connected
|
||||
if (GetAgentType() == MultiplayerAgentType::ClientServer
|
||||
|| GetAgentType() == MultiplayerAgentType::DedicatedServer)
|
||||
|| GetAgentType() == MultiplayerAgentType::DedicatedServer)
|
||||
{
|
||||
NetworkEntityHandle controlledEntity = SpawnDefaultPlayerPrefab();
|
||||
if (controlledEntity.Exists())
|
||||
@@ -602,6 +635,74 @@ namespace Multiplayer
|
||||
AZLOG_INFO("Total RPCs received bytes: %llu", aznumeric_cast<AZ::u64>(rpcsRecv.m_totalBytes));
|
||||
}
|
||||
|
||||
void MultiplayerSystemComponent::TickVisibleNetworkEntities(float deltaTime, float serverRateSeconds)
|
||||
{
|
||||
const float targetAdjustBlend = AZStd::clamp(deltaTime / serverRateSeconds, 0.0f, 1.0f);
|
||||
m_renderBlendFactor += targetAdjustBlend;
|
||||
|
||||
// Linear close to the origin, but asymptote at y = 1
|
||||
const float adjustedBlendFactor = 1.0f - (std::pow(0.2f, m_renderBlendFactor));
|
||||
AZLOG(NET_Blending, "Computed blend factor of %f", adjustedBlendFactor);
|
||||
|
||||
if (Camera::ActiveCameraRequestBus::HasHandlers())
|
||||
{
|
||||
// If there's a camera, update only what's visible
|
||||
AZ::Transform activeCameraTransform;
|
||||
Camera::Configuration activeCameraConfiguration;
|
||||
Camera::ActiveCameraRequestBus::BroadcastResult(activeCameraTransform, &Camera::ActiveCameraRequestBus::Events::GetActiveCameraTransform);
|
||||
Camera::ActiveCameraRequestBus::BroadcastResult(activeCameraConfiguration, &Camera::ActiveCameraRequestBus::Events::GetActiveCameraConfiguration);
|
||||
|
||||
const AZ::ViewFrustumAttributes frustumAttributes
|
||||
(
|
||||
activeCameraTransform,
|
||||
activeCameraConfiguration.m_frustumHeight / activeCameraConfiguration.m_frustumWidth,
|
||||
activeCameraConfiguration.m_fovRadians,
|
||||
activeCameraConfiguration.m_nearClipDistance,
|
||||
activeCameraConfiguration.m_farClipDistance
|
||||
);
|
||||
const AZ::Frustum viewFrustum = AZ::Frustum(frustumAttributes);
|
||||
|
||||
// Unfortunately necessary, as NotifyPreRender can update transforms and thus cause a deadlock inside the vis system
|
||||
AZStd::vector<NetBindComponent*> gatheredEntities;
|
||||
AzFramework::IEntityBoundsUnion* entityBoundsUnion = AZ::Interface<AzFramework::IEntityBoundsUnion>::Get();
|
||||
AZ::Interface<AzFramework::IVisibilitySystem>::Get()->GetDefaultVisibilityScene()->Enumerate(viewFrustum,
|
||||
[&gatheredEntities, entityBoundsUnion](const AzFramework::IVisibilityScene::NodeData& nodeData)
|
||||
{
|
||||
gatheredEntities.reserve(gatheredEntities.size() + nodeData.m_entries.size());
|
||||
for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries)
|
||||
{
|
||||
if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity)
|
||||
{
|
||||
AZ::Entity* entity = static_cast<AZ::Entity*>(visEntry->m_userData);
|
||||
NetBindComponent* netBindComponent = entity->FindComponent<NetBindComponent>();
|
||||
if (netBindComponent != nullptr)
|
||||
{
|
||||
gatheredEntities.push_back(netBindComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (NetBindComponent* netBindComponent : gatheredEntities)
|
||||
{
|
||||
netBindComponent->NotifyPreRender(deltaTime, adjustedBlendFactor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there's no camera, fall back to updating all net entities
|
||||
for (auto& iter : *(m_networkEntityManager.GetNetworkEntityTracker()))
|
||||
{
|
||||
AZ::Entity* entity = iter.second;
|
||||
NetBindComponent* netBindComponent = entity->FindComponent<NetBindComponent>();
|
||||
if (netBindComponent != nullptr)
|
||||
{
|
||||
netBindComponent->NotifyPreRender(deltaTime, adjustedBlendFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MultiplayerSystemComponent::OnConsoleCommandInvoked
|
||||
(
|
||||
AZStd::string_view command,
|
||||
|
||||
@@ -102,6 +102,7 @@ namespace Multiplayer
|
||||
|
||||
private:
|
||||
|
||||
void TickVisibleNetworkEntities(float deltaTime, float serverRateSeconds);
|
||||
void OnConsoleCommandInvoked(AZStd::string_view command, const AZ::ConsoleCommandContainer& args, AZ::ConsoleFunctorFlags flags, AZ::ConsoleInvokedFrom invokedFrom);
|
||||
void ExecuteConsoleCommandList(AzNetworking::IConnection* connection, const AZStd::fixed_vector<Multiplayer::LongNetworkString, 32>& commands);
|
||||
NetworkEntityHandle SpawnDefaultPlayerPrefab();
|
||||
@@ -124,6 +125,9 @@ namespace Multiplayer
|
||||
AZ::TimeMs m_lastReplicatedHostTimeMs = AZ::TimeMs{ 0 };
|
||||
HostFrameId m_lastReplicatedHostFrameId = InvalidHostFrameId;
|
||||
|
||||
double m_serverSendAccumulator = 0.0;
|
||||
float m_renderBlendFactor = 0.0f;
|
||||
|
||||
#if !defined(AZ_RELEASE_BUILD)
|
||||
MultiplayerEditorConnection m_editorConnectionListener;
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@ namespace Multiplayer
|
||||
EntityReplicatorList replicatorUpdatedList;
|
||||
MultiplayerPackets::EntityUpdates entityUpdatePacket;
|
||||
entityUpdatePacket.SetHostTimeMs(hostTimeMs);
|
||||
entityUpdatePacket.SetHostFrameId(InvalidHostFrameId);
|
||||
entityUpdatePacket.SetHostFrameId(GetNetworkTime()->GetHostFrameId());
|
||||
// Serialize everything
|
||||
while (!toSendList.empty())
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Multiplayer
|
||||
, m_sentRecords(net_EntityReplicatorRecordsMax)
|
||||
{
|
||||
AZ_Assert(m_netBindComponent, "NetBindComponent is nullptr");
|
||||
m_pendingRecord.SetNetworkRole(remoteNetworkRole);
|
||||
m_pendingRecord.SetRemoteNetworkRole(remoteNetworkRole);
|
||||
}
|
||||
|
||||
bool PropertyPublisher::IsDeleting() const
|
||||
@@ -67,7 +67,7 @@ namespace Multiplayer
|
||||
|
||||
void PropertyPublisher::SetRebasing()
|
||||
{
|
||||
AZ_Assert(m_pendingRecord.GetNetworkRole() == NetEntityRole::Autonomous, "Expected to be rebasing on a Autonomous entity");
|
||||
AZ_Assert(m_pendingRecord.GetRemoteNetworkRole() == NetEntityRole::Autonomous, "Expected to be rebasing on a Autonomous entity");
|
||||
m_replicatorState = EntityReplicatorState::Rebasing;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace Multiplayer
|
||||
m_sentRecords.clear();
|
||||
m_netBindComponent->FillTotalReplicationRecord(m_pendingRecord);
|
||||
// Don't send predictable properties back to the Autonomous unless we correct them
|
||||
if (m_pendingRecord.GetNetworkRole() == NetEntityRole::Autonomous)
|
||||
if (m_pendingRecord.GetRemoteNetworkRole() == NetEntityRole::Autonomous)
|
||||
{
|
||||
m_pendingRecord.Subtract(m_netBindComponent->GetPredictableRecord());
|
||||
}
|
||||
@@ -137,7 +137,7 @@ namespace Multiplayer
|
||||
// We need to clear out old records, and build up a list of everything that has changed since the last acked packet
|
||||
m_sentRecords.push_front(m_pendingRecord);
|
||||
auto iter = m_sentRecords.begin();
|
||||
++iter; // consider everything after the record we are going to send
|
||||
++iter; // Consider everything after the record we are going to send
|
||||
for (; iter != m_sentRecords.end(); ++iter)
|
||||
{
|
||||
// Sequence wasn't acked, so we need to send these bits again
|
||||
@@ -145,7 +145,7 @@ namespace Multiplayer
|
||||
}
|
||||
|
||||
// Don't send predictable properties back to the Autonomous unless we correct them
|
||||
if (m_pendingRecord.GetNetworkRole() == NetEntityRole::Autonomous)
|
||||
if (m_pendingRecord.GetRemoteNetworkRole() == NetEntityRole::Autonomous)
|
||||
{
|
||||
m_pendingRecord.Subtract(m_netBindComponent->GetPredictableRecord());
|
||||
}
|
||||
|
||||
+13
-13
@@ -49,19 +49,19 @@ namespace Multiplayer
|
||||
}
|
||||
|
||||
ReplicationRecord::ReplicationRecord(NetEntityRole netEntityRole)
|
||||
: m_netEntityRole(netEntityRole)
|
||||
: m_remoteNetEntityRole(netEntityRole)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void ReplicationRecord::SetNetworkRole(NetEntityRole netEntityRole)
|
||||
void ReplicationRecord::SetRemoteNetworkRole(NetEntityRole remoteNetEntityRole)
|
||||
{
|
||||
m_netEntityRole = netEntityRole;
|
||||
m_remoteNetEntityRole = remoteNetEntityRole;
|
||||
}
|
||||
|
||||
NetEntityRole ReplicationRecord::GetNetworkRole() const
|
||||
NetEntityRole ReplicationRecord::GetRemoteNetworkRole() const
|
||||
{
|
||||
return m_netEntityRole;
|
||||
return m_remoteNetEntityRole;
|
||||
}
|
||||
|
||||
bool ReplicationRecord::AreAllBitsConsumed() const
|
||||
@@ -196,26 +196,26 @@ namespace Multiplayer
|
||||
|
||||
bool ReplicationRecord::ContainsAuthorityToClientBits() const
|
||||
{
|
||||
return (m_netEntityRole != NetEntityRole::Authority)
|
||||
|| (m_netEntityRole == NetEntityRole::InvalidRole);
|
||||
return (m_remoteNetEntityRole != NetEntityRole::Authority)
|
||||
|| (m_remoteNetEntityRole == NetEntityRole::InvalidRole);
|
||||
}
|
||||
|
||||
bool ReplicationRecord::ContainsAuthorityToServerBits() const
|
||||
{
|
||||
return (m_netEntityRole == NetEntityRole::Server)
|
||||
|| (m_netEntityRole == NetEntityRole::InvalidRole);
|
||||
return (m_remoteNetEntityRole == NetEntityRole::Server)
|
||||
|| (m_remoteNetEntityRole == NetEntityRole::InvalidRole);
|
||||
}
|
||||
|
||||
bool ReplicationRecord::ContainsAuthorityToAutonomousBits() const
|
||||
{
|
||||
return (m_netEntityRole == NetEntityRole::Autonomous || m_netEntityRole == NetEntityRole::Server)
|
||||
|| (m_netEntityRole == NetEntityRole::InvalidRole);
|
||||
return (m_remoteNetEntityRole == NetEntityRole::Autonomous || m_remoteNetEntityRole == NetEntityRole::Server)
|
||||
|| (m_remoteNetEntityRole == NetEntityRole::InvalidRole);
|
||||
}
|
||||
|
||||
bool ReplicationRecord::ContainsAutonomousToAuthorityBits() const
|
||||
{
|
||||
return (m_netEntityRole == NetEntityRole::Authority)
|
||||
|| (m_netEntityRole == NetEntityRole::InvalidRole);
|
||||
return (m_remoteNetEntityRole == NetEntityRole::Authority)
|
||||
|| (m_remoteNetEntityRole == NetEntityRole::InvalidRole);
|
||||
}
|
||||
|
||||
uint32_t ReplicationRecord::GetRemainingAuthorityToClientBits() const
|
||||
|
||||
@@ -27,6 +27,6 @@ namespace NumericalMethods::Optimization
|
||||
const double epsilon = 1e-7;
|
||||
|
||||
// values recommended in Nocedal and Wright for constants in the Wolfe conditions for satisfactory solution improvement
|
||||
const double c1 = 1e-4;
|
||||
const double c2 = 0.9;
|
||||
const double WolfeConditionsC1 = 1e-4;
|
||||
const double WolfeConditionsC2 = 0.9;
|
||||
} // namespace NumericalMethods::Optimization
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace NumericalMethods::Optimization
|
||||
|
||||
for (AZ::u32 iteration = 0; iteration < lineSearchIterations; iteration++)
|
||||
{
|
||||
ScalarVariable alphaNew;
|
||||
ScalarVariable alphaNew = 0.0;
|
||||
if (iteration > 0)
|
||||
{
|
||||
// first try selecting a new alpha value based on cubic interpolation through the most recent points
|
||||
@@ -162,16 +162,16 @@ namespace NumericalMethods::Optimization
|
||||
{
|
||||
// if the value of f corresponding to alpha1 isn't sufficiently small compared to f at x0,
|
||||
// then the interval [alpha0 ... alpha1] must bracket a suitable point.
|
||||
if ((f_alpha1 > f_x0 + c1 * alpha1 * df_x0) || (iteration > 0 && f_alpha1 > f_alpha0))
|
||||
if ((f_alpha1 > f_x0 + WolfeConditionsC1 * alpha1 * df_x0) || (iteration > 0 && f_alpha1 > f_alpha0))
|
||||
{
|
||||
return SelectStepSizeFromInterval(alpha0, alpha1, f_alpha0, f_alpha1, df_alpha0,
|
||||
f, x0, searchDirection, f_x0, df_x0, c1, c2);
|
||||
f, x0, searchDirection, f_x0, df_x0, WolfeConditionsC1, WolfeConditionsC2);
|
||||
}
|
||||
|
||||
// otherwise, if the derivative corresponding to alpha1 is large enough, alpha1 already
|
||||
// satisfies the Wolfe conditions and so return alpha1.
|
||||
double df_alpha1 = DirectionalDerivative(f, x0 + alpha1 * searchDirection, searchDirection);
|
||||
if (fabs(df_alpha1) <= -c2 * df_x0)
|
||||
if (fabs(df_alpha1) <= -WolfeConditionsC2 * df_x0)
|
||||
{
|
||||
LineSearchResult result;
|
||||
result.m_outcome = LineSearchOutcome::Success;
|
||||
@@ -184,7 +184,7 @@ namespace NumericalMethods::Optimization
|
||||
if (df_alpha1 >= 0.0)
|
||||
{
|
||||
return SelectStepSizeFromInterval(alpha1, alpha0, f_alpha1, f_alpha0, df_alpha1,
|
||||
f, x0, searchDirection, f_x0, df_x0, c1, c2);
|
||||
f, x0, searchDirection, f_x0, df_x0, WolfeConditionsC1, WolfeConditionsC2);
|
||||
}
|
||||
|
||||
// haven't found an interval which is guaranteed to bracket a suitable point,
|
||||
|
||||
@@ -158,12 +158,12 @@ namespace NumericalMethods::Optimization
|
||||
double f_x0 = f_alpha0;
|
||||
double df_x0 = df_alpha0;
|
||||
LineSearchResult lineSearchResult = SelectStepSizeFromInterval(alpha0, alpha1, f_alpha0, f_alpha1, df_alpha0,
|
||||
testFunctionRosenbrock, x0, searchDirection, f_x0, df_x0, c1, c2);
|
||||
testFunctionRosenbrock, x0, searchDirection, f_x0, df_x0, WolfeConditionsC1, WolfeConditionsC2);
|
||||
|
||||
EXPECT_TRUE(lineSearchResult.m_outcome == LineSearchOutcome::Success);
|
||||
// check that the Wolfe conditions are satisfied by the returned step size
|
||||
EXPECT_TRUE(lineSearchResult.m_functionValue < f_x0 + c1 * df_x0 * lineSearchResult.m_stepSize);
|
||||
EXPECT_TRUE(fabs(lineSearchResult.m_derivativeValue) <= -c2 * df_x0);
|
||||
EXPECT_TRUE(lineSearchResult.m_functionValue < f_x0 + WolfeConditionsC1 * df_x0 * lineSearchResult.m_stepSize);
|
||||
EXPECT_TRUE(fabs(lineSearchResult.m_derivativeValue) <= -WolfeConditionsC2 * df_x0);
|
||||
}
|
||||
|
||||
TEST(OptimizationTest, LineSearch_VariousSearchDirections_SatisfiesWolfeCondition)
|
||||
@@ -180,8 +180,8 @@ namespace NumericalMethods::Optimization
|
||||
|
||||
EXPECT_TRUE(lineSearchResult.m_outcome == LineSearchOutcome::Success);
|
||||
// check that the Wolfe conditions are satisfied by the returned step size
|
||||
EXPECT_TRUE(lineSearchResult.m_functionValue < f_x0 + c1 * df_x0 * lineSearchResult.m_stepSize);
|
||||
EXPECT_TRUE(fabs(lineSearchResult.m_derivativeValue) <= -c2 * df_x0);
|
||||
EXPECT_TRUE(lineSearchResult.m_functionValue < f_x0 + WolfeConditionsC1 * df_x0 * lineSearchResult.m_stepSize);
|
||||
EXPECT_TRUE(fabs(lineSearchResult.m_derivativeValue) <= -WolfeConditionsC2 * df_x0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,9 +112,9 @@ namespace PhysX::Benchmarks
|
||||
for (double percentile : percentiles)
|
||||
{
|
||||
//ensure the percentile is between 0.0 and 1.0
|
||||
const double epsilon = 0.001;
|
||||
AZ::ClampIfCloseMag(percentile, 0.0, epsilon);
|
||||
AZ::ClampIfCloseMag(percentile, 1.0, epsilon);
|
||||
const double testEpsilon = 0.001;
|
||||
AZ::ClampIfCloseMag(percentile, 0.0, testEpsilon);
|
||||
AZ::ClampIfCloseMag(percentile, 1.0, testEpsilon);
|
||||
|
||||
size_t idx = aznumeric_cast<size_t>(std::round(percentile * (values.size() - 1)));
|
||||
std::nth_element(values.begin(), values.begin() + idx, values.end());
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
|
||||
#include <PhysX/SystemComponentBus.h>
|
||||
#include <PhysX/MathConversion.h>
|
||||
@@ -183,9 +184,7 @@ namespace PhysXDebug
|
||||
void SystemComponent::OnCrySystemInitialized([[maybe_unused]] ISystem& system, const SSystemInitParams&)
|
||||
{
|
||||
InitPhysXColorMappings();
|
||||
RegisterCommands();
|
||||
ConfigurePhysXVisualizationParameters();
|
||||
|
||||
}
|
||||
|
||||
void SystemComponent::Reflect(AZ::ReflectContext* context)
|
||||
@@ -537,12 +536,13 @@ namespace PhysXDebug
|
||||
}
|
||||
}
|
||||
|
||||
static void CmdEnableWireFrame([[maybe_unused]] IConsoleCmdArgs* args)
|
||||
static void physx_CullingBox([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
|
||||
{
|
||||
PhysXDebug::PhysXDebugRequestBus::Broadcast(&PhysXDebug::PhysXDebugRequestBus::Events::ToggleCullingWireFrame);
|
||||
}
|
||||
AZ_CONSOLEFREEFUNC(physx_CullingBox, AZ::ConsoleFunctorFlags::DontReplicate, "Enables physx wireframe view");
|
||||
|
||||
static void CmdConnectToPvd([[maybe_unused]] IConsoleCmdArgs* args)
|
||||
static void physx_PvdConnect([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
|
||||
{
|
||||
auto* debug = AZ::Interface<PhysX::Debug::PhysXDebugInterface>::Get();
|
||||
if (debug)
|
||||
@@ -550,8 +550,9 @@ namespace PhysXDebug
|
||||
debug->ConnectToPvd();
|
||||
}
|
||||
}
|
||||
AZ_CONSOLEFREEFUNC(physx_PvdConnect, AZ::ConsoleFunctorFlags::DontReplicate, "Connects to the physx visual debugger");
|
||||
|
||||
static void CmdDisconnectFromPvd([[maybe_unused]] IConsoleCmdArgs* args)
|
||||
static void physx_PvdDisconnect([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
|
||||
{
|
||||
auto* debug = AZ::Interface<PhysX::Debug::PhysXDebugInterface>::Get();
|
||||
if (debug)
|
||||
@@ -559,13 +560,14 @@ namespace PhysXDebug
|
||||
debug->DisconnectFromPvd();
|
||||
}
|
||||
}
|
||||
AZ_CONSOLEFREEFUNC(physx_PvdDisconnect, AZ::ConsoleFunctorFlags::DontReplicate, "Disconnects from the physx visual debugger");
|
||||
|
||||
static void CmdSetPhysXDebugCullingBoxSize(IConsoleCmdArgs* args)
|
||||
static void physx_CullingBoxSize([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
|
||||
{
|
||||
const int argumentCount = args->GetArgCount();
|
||||
const int argumentCount = arguments.size();
|
||||
if (argumentCount == 2)
|
||||
{
|
||||
float newCullingBoxSize = (float)strtol(args->GetArg(1), nullptr, 10);
|
||||
float newCullingBoxSize = (float)strtol(AZ::CVarFixedString(arguments[1]).c_str(), nullptr, 10);
|
||||
PhysXDebug::PhysXDebugRequestBus::Broadcast(&PhysXDebug::PhysXDebugRequestBus::Events::SetCullingBoxSize, newCullingBoxSize);
|
||||
}
|
||||
else
|
||||
@@ -574,16 +576,17 @@ namespace PhysXDebug
|
||||
"Please use physx_SetDebugCullingBoxSize <boxSize> e.g. physx_SetDebugCullingBoxSize 100.");
|
||||
}
|
||||
}
|
||||
AZ_CONSOLEFREEFUNC(physx_CullingBoxSize, AZ::ConsoleFunctorFlags::DontReplicate, "Sets physx debug culling box size");
|
||||
|
||||
static void CmdTogglePhysXDebugVisualization(IConsoleCmdArgs* args)
|
||||
static void physx_Debug([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
|
||||
{
|
||||
using namespace CryStringUtils;
|
||||
|
||||
const int argumentCount = args->GetArgCount();
|
||||
const int argumentCount = arguments.size();
|
||||
|
||||
if (argumentCount == 2)
|
||||
{
|
||||
const auto userPreference = static_cast<DebugCVarValues>(strtol(args->GetArg(1), nullptr, 10));
|
||||
const auto userPreference = static_cast<DebugCVarValues>(strtol(AZ::CVarFixedString(arguments[1]).c_str(), nullptr, 10));
|
||||
|
||||
switch (userPreference)
|
||||
{
|
||||
@@ -609,29 +612,7 @@ namespace PhysXDebug
|
||||
AZ_Warning("PhysXDebug", false, "Invalid physx_Debug Arguments. Please use physx_Debug 1 to enable, physx_Debug 0 to disable or physx_Debug 2 to enable all configuration settings.");
|
||||
}
|
||||
}
|
||||
|
||||
void SystemComponent::RegisterCommands()
|
||||
{
|
||||
if (m_registered)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (gEnv)
|
||||
{
|
||||
IConsole* console = gEnv->pSystem->GetIConsole();
|
||||
if (console)
|
||||
{
|
||||
console->AddCommand("physx_Debug", CmdTogglePhysXDebugVisualization);
|
||||
console->AddCommand("physx_CullingBox", CmdEnableWireFrame);
|
||||
console->AddCommand("physx_CullingBoxSize", CmdSetPhysXDebugCullingBoxSize);
|
||||
console->AddCommand("physx_PvdConnect", CmdConnectToPvd);
|
||||
console->AddCommand("physx_PvdDisconnect", CmdDisconnectFromPvd);
|
||||
}
|
||||
|
||||
m_registered = true;
|
||||
}
|
||||
}
|
||||
AZ_CONSOLEFREEFUNC(physx_Debug, AZ::ConsoleFunctorFlags::DontReplicate, "Toggles physx debug visualization");
|
||||
|
||||
void SystemComponent::ConfigurePhysXVisualizationParameters()
|
||||
{
|
||||
|
||||
@@ -161,9 +161,6 @@ namespace PhysXDebug
|
||||
/// Initialise the PhysX debug draw colors based on defaults.
|
||||
void InitPhysXColorMappings();
|
||||
|
||||
/// Register debug drawing PhysX commands with Open 3D Engine console during game mode.
|
||||
void RegisterCommands();
|
||||
|
||||
/// Draw the culling box being used by the viewport.
|
||||
/// @param cullingBoxAabb culling box Aabb to debug draw.
|
||||
void DrawDebugCullingBox(const AZ::Aabb& cullingBoxAabb);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# {END_LICENSE}
|
||||
|
||||
set(ENABLED_GEMS
|
||||
Project::${Name}
|
||||
${Name}
|
||||
Atom_AtomBridge
|
||||
Camera
|
||||
CameraFramework
|
||||
|
||||
+5
-5
@@ -29,9 +29,6 @@ function(ly_create_alias)
|
||||
message(FATAL_ERROR "Provide the namespace of the alias to create using the NAMESPACE keyword")
|
||||
endif()
|
||||
|
||||
if (NOT ly_create_alias_TARGETS)
|
||||
message(FATAL_ERROR "Provide the name of the targets the alias be associated with, using the TARGETS keyword")
|
||||
endif()
|
||||
|
||||
if(TARGET ${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME})
|
||||
message(FATAL_ERROR "Target already exists, cannot create an alias for it: ${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME}\n"
|
||||
@@ -78,8 +75,11 @@ function(ly_create_alias)
|
||||
list(APPEND final_targets ${de_aliased_target_name})
|
||||
endforeach()
|
||||
|
||||
ly_parse_third_party_dependencies("${final_targets}")
|
||||
ly_add_dependencies(${ly_create_alias_NAME} ${final_targets})
|
||||
# add_dependencies must be called with at least one dependent target
|
||||
if(final_targets)
|
||||
ly_parse_third_party_dependencies("${final_targets}")
|
||||
ly_add_dependencies(${ly_create_alias_NAME} ${final_targets})
|
||||
endif()
|
||||
|
||||
# now add the final alias:
|
||||
add_library(${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME} ALIAS ${ly_create_alias_NAME})
|
||||
|
||||
@@ -443,7 +443,6 @@ function(ly_setup_others)
|
||||
|
||||
install(DIRECTORY
|
||||
${LY_ROOT_FOLDER}/scripts/bundler
|
||||
${LY_ROOT_FOLDER}/scripts/project_manager
|
||||
${LY_ROOT_FOLDER}/scripts/o3de
|
||||
DESTINATION ./scripts
|
||||
COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT}
|
||||
|
||||
@@ -74,8 +74,6 @@ ly_append_configurations_options(
|
||||
/wd4436 # the result of unary operator may be unaligned
|
||||
/wd4450 # declaration hides global declaration
|
||||
/wd4457 # declaration hides function parameter
|
||||
/wd4459 # declaration hides global declaration
|
||||
/wd4701 # potentially unintialized local variable
|
||||
|
||||
# Enabling warnings that are disabled by default from /W4
|
||||
# https://docs.microsoft.com/en-us/cpp/preprocessor/compiler-warnings-that-are-off-by-default?view=vs-2019
|
||||
|
||||
@@ -25,14 +25,15 @@ set(gems_json_template [[
|
||||
@target_gem_dependencies_names@
|
||||
}
|
||||
}
|
||||
}]]
|
||||
}
|
||||
]]
|
||||
)
|
||||
set(gem_module_template [[
|
||||
"@stripped_gem_target@":
|
||||
{
|
||||
"Modules":["$<TARGET_FILE_NAME:@gem_target@>"],
|
||||
"SourcePaths":["@gem_module_root_relative_to_engine_root@"]
|
||||
}]]
|
||||
string(APPEND gem_module_template
|
||||
[=[ "@stripped_gem_target@":]=] "\n"
|
||||
[=[ {]=] "\n"
|
||||
[=[$<$<NOT:$<IN_LIST:$<TARGET_PROPERTY:@gem_target@,TYPE>,INTERFACE_LIBRARY>>: "Modules":["$<TARGET_FILE_NAME:@gem_target@>"]]=] "$<COMMA>\n>"
|
||||
[=[ "SourcePaths":["@gem_module_root_relative_to_engine_root@"]]=] "\n"
|
||||
[=[ }]=]
|
||||
)
|
||||
|
||||
#!ly_get_gem_load_dependencies: Retrieves the list of "load" dependencies for a target
|
||||
@@ -161,10 +162,12 @@ function(ly_delayed_generate_settings_registry)
|
||||
message(FATAL_ERROR "Dependency ${gem_target} from ${target} does not exist")
|
||||
endif()
|
||||
|
||||
get_property(has_manually_added_dependencies TARGET ${gem_target} PROPERTY MANUALLY_ADDED_DEPENDENCIES SET)
|
||||
get_target_property(target_type ${gem_target} TYPE)
|
||||
if (target_type STREQUAL "INTERFACE_LIBRARY")
|
||||
# don't use interface libraries here, we only want ones which produce actual binaries.
|
||||
# we have still already recursed into their dependencies - they'll show up later.
|
||||
if (target_type STREQUAL "INTERFACE_LIBRARY" AND has_manually_added_dependencies)
|
||||
# don't use interface libraries here, we only want ones which produce actual binaries unless the target
|
||||
# is empty. We have still already recursed into their dependencies - they'll show up later.
|
||||
# When the target has no dependencies however we want to add the gem root path to the generated setreg
|
||||
continue()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -12,5 +12,4 @@
|
||||
add_subdirectory(detect_file_changes)
|
||||
add_subdirectory(commit_validation)
|
||||
add_subdirectory(o3de)
|
||||
add_subdirectory(project_manager)
|
||||
add_subdirectory(ctest)
|
||||
|
||||
+5
-2
@@ -32,7 +32,7 @@ def add_args(parser, subparsers) -> None:
|
||||
# add the scripts/o3de directory to the front of the sys.path
|
||||
sys.path.insert(0, str(o3de_package_dir))
|
||||
from o3de import engine_template, global_project, register, print_registration, get_registration, \
|
||||
enable_gem, disable_gem, sha256
|
||||
enable_gem, disable_gem, project_properties, sha256
|
||||
# Remove the temporarily added path
|
||||
sys.path = sys.path[1:]
|
||||
|
||||
@@ -55,7 +55,10 @@ def add_args(parser, subparsers) -> None:
|
||||
|
||||
# remove a gem from a project
|
||||
disable_gem.add_args(subparsers)
|
||||
|
||||
|
||||
# modify project properties
|
||||
project_properties.add_args(subparsers)
|
||||
|
||||
# sha256
|
||||
sha256.add_args(subparsers)
|
||||
|
||||
|
||||
@@ -573,9 +573,7 @@ def get_registered(engine_name: str = None,
|
||||
return engine_path
|
||||
|
||||
elif isinstance(project_name, str):
|
||||
enging_projects = get_engine_projects()
|
||||
projects = json_data['projects'].copy()
|
||||
projects.extend(engine_object['projects'])
|
||||
projects = get_all_projects()
|
||||
for project_path in projects:
|
||||
project_path = pathlib.Path(project_path).resolve()
|
||||
project_json = project_path / 'project.json'
|
||||
@@ -605,9 +603,7 @@ def get_registered(engine_name: str = None,
|
||||
return gem_path
|
||||
|
||||
elif isinstance(template_name, str):
|
||||
engine_templates = get_engine_templates()
|
||||
templates = json_data['templates'].copy()
|
||||
templates.extend(engine_templates)
|
||||
templates = get_all_templates()
|
||||
for template_path in templates:
|
||||
template_path = pathlib.Path(template_path).resolve()
|
||||
template_json = template_path / 'template.json'
|
||||
@@ -622,9 +618,7 @@ def get_registered(engine_name: str = None,
|
||||
return template_path
|
||||
|
||||
elif isinstance(restricted_name, str):
|
||||
engine_restricted = get_engine_restricted()
|
||||
restricted = json_data['restricted'].copy()
|
||||
restricted.extend(engine_restricted)
|
||||
restricted = get_all_restricted()
|
||||
for restricted_path in restricted:
|
||||
restricted_path = pathlib.Path(restricted_path).resolve()
|
||||
restricted_json = restricted_path / 'restricted.json'
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#
|
||||
# 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 argparse
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import logging
|
||||
|
||||
from o3de import manifest
|
||||
|
||||
logger = logging.getLogger()
|
||||
logging.basicConfig()
|
||||
|
||||
def get_project_props(name: str = None, path: pathlib.Path = None) -> dict:
|
||||
proj_json = manifest.get_project_json_data(project_name=name, project_path=path)
|
||||
if not proj_json:
|
||||
param = name if name else path
|
||||
logger.error(f'Could not retrieve project.json file for {param}')
|
||||
return None
|
||||
return proj_json
|
||||
|
||||
def edit_project_props(proj_path, proj_name, new_origin, new_display,
|
||||
new_summary, new_icon, new_tag, remove_tag) -> int:
|
||||
proj_json = get_project_props(proj_name, proj_path)
|
||||
|
||||
if not proj_json:
|
||||
return 1
|
||||
|
||||
if new_origin:
|
||||
proj_json['origin'] = new_origin
|
||||
if new_display:
|
||||
proj_json['display_name'] = new_display
|
||||
if new_summary:
|
||||
proj_json['summary'] = new_summary
|
||||
if new_icon:
|
||||
proj_json['icon_path'] = new_icon
|
||||
if new_tag:
|
||||
proj_json.setdefault('user_tags', []).append(new_tag)
|
||||
if remove_tag:
|
||||
if 'user_tags' in proj_json:
|
||||
if remove_tag in proj_json['user_tags']:
|
||||
proj_json['user_tags'].remove(remove_tag)
|
||||
else:
|
||||
logger.warn(f'{remove_tag} not found in user_tags for removal.')
|
||||
else:
|
||||
logger.warn(f'user_tags property not found for removal of tag {remove_tag}.')
|
||||
|
||||
manifest.save_o3de_manifest(proj_json, pathlib.Path(proj_path) / 'project.json')
|
||||
return 0
|
||||
|
||||
def _edit_project_props(args: argparse) -> int:
|
||||
return edit_project_props(args.project_path,
|
||||
args.project_name,
|
||||
args.project_origin,
|
||||
args.project_display,
|
||||
args.project_summary,
|
||||
args.project_icon,
|
||||
args.project_tag,
|
||||
args.remove_tag)
|
||||
|
||||
def add_parser_args(parser):
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument('-pp', '--project-path', type=pathlib.Path, required=False,
|
||||
help='The path to the project.')
|
||||
group.add_argument('-pn', '--project-name', type=str, required=False,
|
||||
help='The name of the project.')
|
||||
group = parser.add_argument_group('properties', 'arguments for modifying individual project properties.')
|
||||
group.add_argument('-po', '--project-origin', type=str, required=False,
|
||||
help='Sets description or url for project origin (such as project host, repository, owner...etc).')
|
||||
group.add_argument('-pd', '--project-display', type=str, required=False,
|
||||
help='Sets the project display name.')
|
||||
group.add_argument('-ps', '--project-summary', type=str, required=False,
|
||||
help='Sets the summary description of the project.')
|
||||
group.add_argument('-pi', '--project-icon', type=str, required=False,
|
||||
help='Sets the path to the projects icon resource.')
|
||||
group.add_argument('-pt', '--project-tag', type=str, required=False,
|
||||
help='Adds a tag to user_tags property. These tags are intended for documentation and filtering.')
|
||||
group.add_argument('-rt', '--remove-tag', type=str, required=False,
|
||||
help='Removes a tag from the user_tags property.')
|
||||
parser.set_defaults(func=_edit_project_props)
|
||||
|
||||
def add_args(subparsers) -> None:
|
||||
enable_project_props_subparser = subparsers.add_parser('edit-project-properties')
|
||||
add_parser_args(enable_project_props_subparser)
|
||||
|
||||
def main():
|
||||
the_parser = argparse.ArgumentParser()
|
||||
add_parser_args(the_parser)
|
||||
the_args = the_parser.parse_args()
|
||||
ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1
|
||||
sys.exit(ret)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,22 +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.
|
||||
#
|
||||
|
||||
ly_download_associated_package(pyside2)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME test_pyside
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/tests/test_pyside.py
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME test_projects
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/tests/test_projects.py
|
||||
)
|
||||
@@ -1,10 +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.
|
||||
#
|
||||
@@ -1,804 +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.
|
||||
#
|
||||
|
||||
# PySide project and gem selector GUI
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
import subprocess
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from typing import List
|
||||
from pyside import add_pyside_environment, is_pyside_ready, uninstall_env
|
||||
|
||||
engine_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
sys.path.append(engine_path)
|
||||
executable_path = ''
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
from o3de import disable_gem, enable_gem, cmake, engine_template, manifest, register
|
||||
|
||||
o3de_folder = manifest.get_o3de_folder()
|
||||
o3de_logs_folder = manifest.get_o3de_logs_folder()
|
||||
project_manager_log_file_path = o3de_logs_folder / "project_manager.log"
|
||||
log_file_handler = RotatingFileHandler(filename=project_manager_log_file_path, maxBytes=1024 * 1024, backupCount=1)
|
||||
formatter = logging.Formatter('%(asctime)s | %(levelname)s : %(message)s')
|
||||
log_file_handler.setFormatter(formatter)
|
||||
logger.addHandler(log_file_handler)
|
||||
|
||||
logger.info("Starting Project Manager")
|
||||
|
||||
|
||||
def initialize_pyside_from_parser():
|
||||
# Parse arguments up top. We need to know the path to our binaries and QT libs in particular to load up
|
||||
# PySide
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--executable-path', required=True, help='Path to Executable to launch with project')
|
||||
parser.add_argument('--binaries-path', default=None, help='Path to QT Binaries necessary for PySide. If not'
|
||||
' provided executable_path folder is assumed')
|
||||
parser.add_argument('--parent-pid', default=0, help='Process ID of launching process')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
logger.info(f"parent_pid is {args.parent_pid}")
|
||||
global executable_path
|
||||
executable_path = args.executable_path
|
||||
binaries_path = args.binaries_path or os.path.dirname(executable_path)
|
||||
|
||||
# Initialize PySide before imports below. This adds both PySide python modules to the python system interpreter
|
||||
# path and adds the necessary paths to binaries for the DLLs to be found and load their dependencies
|
||||
add_pyside_environment(binaries_path)
|
||||
|
||||
|
||||
if not is_pyside_ready():
|
||||
initialize_pyside_from_parser()
|
||||
|
||||
try:
|
||||
from PySide2.QtWidgets import QApplication, QDialogButtonBox, QPushButton, QComboBox, QMessageBox, QFileDialog
|
||||
from PySide2.QtWidgets import QListView, QLabel
|
||||
from PySide2.QtUiTools import QUiLoader
|
||||
from PySide2.QtCore import QFile, QObject, Qt, Signal, Slot
|
||||
from PySide2.QtGui import QIcon, QStandardItemModel, QStandardItem
|
||||
except ImportError as e:
|
||||
logger.error(f"Failed to import PySide2 with error {e}")
|
||||
exit(-1)
|
||||
|
||||
logger.error(f"PySide2 imports successful")
|
||||
|
||||
|
||||
class DialogLoggerSignaller(QObject):
|
||||
send_to_dialog = Signal(str)
|
||||
|
||||
def __init__(self, dialog_logger):
|
||||
super(DialogLoggerSignaller, self).__init__()
|
||||
|
||||
self.dialog_logger = dialog_logger
|
||||
|
||||
|
||||
# Independent class to handle log forwarding. Logger and qt signals both use emit method.
|
||||
# This class's job is to receive the logger record and then emit the formatted message through
|
||||
# DialogLoggerSignaller which is what the ProjectDialog handler listens for
|
||||
class DialogLogger(logging.Handler):
|
||||
|
||||
def __init__(self, log_dialog, log_level=logging.INFO, forward_log_level=logging.WARNING,
|
||||
message_box_log_level=logging.ERROR):
|
||||
super(DialogLogger, self).__init__()
|
||||
|
||||
self.log_dialog = log_dialog
|
||||
self.log_level = log_level
|
||||
self.forward_log_level = forward_log_level
|
||||
self.message_box_log_level = message_box_log_level
|
||||
self.log_records = []
|
||||
self.formatter = logging.Formatter('%(levelname)s : %(message)s')
|
||||
self.setFormatter(self.formatter)
|
||||
self.signaller = DialogLoggerSignaller(self)
|
||||
|
||||
def emit(self, record):
|
||||
self.log_records.append(record)
|
||||
if record.levelno >= self.message_box_log_level:
|
||||
QMessageBox.warning(None, record.levelname, record.message)
|
||||
elif record.levelno >= self.forward_log_level:
|
||||
self.signaller.send_to_dialog.emit(self.format(record))
|
||||
|
||||
|
||||
class ProjectManagerDialog(QObject):
|
||||
"""
|
||||
Main project manager dialog is responsible for displaying the project selection list and output pane
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(ProjectManagerDialog, self).__init__(parent)
|
||||
|
||||
self.ui_path = (pathlib.Path(__file__).parent / 'ui').resolve()
|
||||
self.home_folder = manifest.get_home_folder()
|
||||
|
||||
self.log_display = None
|
||||
self.dialog_logger = DialogLogger(self)
|
||||
logger.addHandler(self.dialog_logger)
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
self.dialog_logger.signaller.send_to_dialog.connect(self.handle_log_message)
|
||||
self.mru_file_path = o3de_folder / 'mru.json'
|
||||
|
||||
self.create_from_template_ui_file_path = self.ui_path / 'create_from_template.ui'
|
||||
self.create_gem_ui_file_path = self.ui_path / 'create_gem.ui'
|
||||
self.create_project_ui_file_path = self.ui_path / 'create_project.ui'
|
||||
self.manage_project_gem_targets_ui_file_path = self.ui_path / 'manage_gem_targets.ui'
|
||||
self.project_manager_icon_file_path = self.ui_path / 'project_manager.ico'
|
||||
self.project_manager_ui_file_path = self.ui_path / 'project_manager.ui'
|
||||
|
||||
self.project_manager_ui_file = QFile(self.project_manager_ui_file_path.as_posix())
|
||||
self.project_manager_ui_file.open(QFile.ReadOnly)
|
||||
|
||||
loader = QUiLoader()
|
||||
self.dialog = loader.load(self.project_manager_ui_file)
|
||||
self.dialog.setWindowIcon(QIcon(self.project_manager_icon_file_path.as_posix()))
|
||||
self.dialog.setFixedSize(self.dialog.size())
|
||||
|
||||
self.project_list_box = self.dialog.findChild(QComboBox, 'projectListBox')
|
||||
self.refresh_project_list()
|
||||
mru = self.get_mru_list()
|
||||
if len(mru):
|
||||
last_mru = pathlib.Path(mru[0]).resolve()
|
||||
for this_slot in range(self.project_list_box.count()):
|
||||
item_text = self.project_list_box.itemText(this_slot)
|
||||
if last_mru.as_posix() in item_text:
|
||||
self.project_list_box.setCurrentIndex(this_slot)
|
||||
break
|
||||
|
||||
self.create_project_button = self.dialog.findChild(QPushButton, 'createProjectButton')
|
||||
self.create_project_button.clicked.connect(self.create_project_handler)
|
||||
self.create_gem_button = self.dialog.findChild(QPushButton, 'createGemButton')
|
||||
self.create_gem_button.clicked.connect(self.create_gem_handler)
|
||||
self.create_template_button = self.dialog.findChild(QPushButton, 'createTemplateButton')
|
||||
self.create_template_button.clicked.connect(self.create_template_handler)
|
||||
self.create_from_template_button = self.dialog.findChild(QPushButton, 'createFromTemplateButton')
|
||||
self.create_from_template_button.clicked.connect(self.create_from_template_handler)
|
||||
|
||||
self.add_project_button = self.dialog.findChild(QPushButton, 'addProjectButton')
|
||||
self.add_project_button.clicked.connect(self.add_project_handler)
|
||||
self.add_gem_button = self.dialog.findChild(QPushButton, 'addGemButton')
|
||||
self.add_gem_button.clicked.connect(self.add_gem_handler)
|
||||
self.add_template_button = self.dialog.findChild(QPushButton, 'addTemplateButton')
|
||||
self.add_template_button.clicked.connect(self.add_template_handler)
|
||||
self.add_restricted_button = self.dialog.findChild(QPushButton, 'addRestrictedButton')
|
||||
self.add_restricted_button.clicked.connect(self.add_restricted_handler)
|
||||
|
||||
self.remove_project_button = self.dialog.findChild(QPushButton, 'removeProjectButton')
|
||||
self.remove_project_button.clicked.connect(self.remove_project_handler)
|
||||
self.remove_gem_button = self.dialog.findChild(QPushButton, 'removeGemButton')
|
||||
self.remove_gem_button.clicked.connect(self.remove_gem_handler)
|
||||
self.remove_template_button = self.dialog.findChild(QPushButton, 'removeTemplateButton')
|
||||
self.remove_template_button.clicked.connect(self.remove_template_handler)
|
||||
self.remove_restricted_button = self.dialog.findChild(QPushButton, 'removeRestrictedButton')
|
||||
self.remove_restricted_button.clicked.connect(self.remove_restricted_handler)
|
||||
|
||||
self.manage_project_gem_targets_button = self.dialog.findChild(QPushButton, 'manageRuntimeGemTargetsButton')
|
||||
self.manage_project_gem_targets_button.clicked.connect(self.manage_project_gem_targets_handler)
|
||||
|
||||
self.log_display = self.dialog.findChild(QLabel, 'logDisplay')
|
||||
|
||||
self.ok_cancel_button = self.dialog.findChild(QDialogButtonBox, 'okCancel')
|
||||
self.ok_cancel_button.accepted.connect(self.accepted_handler)
|
||||
|
||||
self.dialog.show()
|
||||
|
||||
def refresh_project_list(self) -> None:
|
||||
projects = manifest.get_all_projects()
|
||||
self.project_list_box.clear()
|
||||
for this_slot in range(len(projects)):
|
||||
display_name = f'{os.path.basename(os.path.normpath(projects[this_slot]))} ({projects[this_slot]})'
|
||||
self.project_list_box.addItem(display_name)
|
||||
self.project_list_box.setItemData(self.project_list_box.count() - 1, projects[this_slot],
|
||||
Qt.ToolTipRole)
|
||||
|
||||
def accepted_handler(self) -> None:
|
||||
"""
|
||||
Override for handling "Ok" on main project dialog to first check whether the user has selected a project and
|
||||
prompt them to if not. If a project is selected will attempt to open it.
|
||||
:return: None
|
||||
"""
|
||||
if not self.project_list_box.currentText():
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText("Please select a project")
|
||||
msg_box.exec()
|
||||
return
|
||||
self.launch_with_project_path(self.get_selected_project_path())
|
||||
|
||||
def get_launch_project(self) -> str:
|
||||
return os.path.normpath(self.get_selected_project_path())
|
||||
|
||||
def get_executable_launch_params(self) -> list:
|
||||
"""
|
||||
Retrieve the necessary launch parameters to make the subprocess launch call with - this is the path
|
||||
to the executable such as the Editor and the path to the selected project
|
||||
:return: list of params
|
||||
"""
|
||||
launch_params = [executable_path,
|
||||
f'-regset="/Amazon/AzCore/Bootstrap/project_path={self.get_launch_project()}"']
|
||||
return launch_params
|
||||
|
||||
def launch_with_project_path(self, project_path: str) -> None:
|
||||
"""
|
||||
Launch the desired application given the selected project
|
||||
:param project_path: Path to currently selected project
|
||||
:return: None
|
||||
"""
|
||||
logger.info(f'Attempting to open {project_path}')
|
||||
self.update_mru_list(project_path)
|
||||
launch_params = self.get_executable_launch_params()
|
||||
logger.info(f'Launching with params {launch_params}')
|
||||
subprocess.run(launch_params, env=uninstall_env())
|
||||
|
||||
def get_selected_project_path(self) -> str:
|
||||
if self.project_list_box.currentIndex() == -1:
|
||||
logger.warning("No project selected")
|
||||
return ""
|
||||
return self.project_list_box.itemData(self.project_list_box.currentIndex(), Qt.ToolTipRole)
|
||||
|
||||
def get_selected_project_name(self) -> str:
|
||||
project_data = manifest.get_project_json_data(project_path=self.get_selected_project_path())
|
||||
return project_data['project_name']
|
||||
|
||||
def create_project_handler(self):
|
||||
"""
|
||||
Opens the Create Project pane. Retrieves a list of available templates for display
|
||||
:return: None
|
||||
"""
|
||||
loader = QUiLoader()
|
||||
self.create_project_file = QFile(self.create_project_ui_file_path.as_posix())
|
||||
|
||||
if not self.create_project_file:
|
||||
logger.error(f'Failed to create project UI file at {self.create_project_file}')
|
||||
return
|
||||
|
||||
self.create_project_dialog = loader.load(self.create_project_file)
|
||||
|
||||
if not self.create_project_dialog:
|
||||
logger.error(f'Failed to load create project dialog file at {self.create_project_file}')
|
||||
return
|
||||
|
||||
self.create_project_ok_button = self.create_project_dialog.findChild(QDialogButtonBox, 'okCancel')
|
||||
self.create_project_ok_button.accepted.connect(self.create_project_accepted_handler)
|
||||
|
||||
self.create_project_template_list = self.create_project_dialog.findChild(QListView, 'projectTemplates')
|
||||
self.refresh_create_project_template_list()
|
||||
|
||||
self.create_project_dialog.exec()
|
||||
|
||||
def create_project_accepted_handler(self) -> None:
|
||||
"""
|
||||
Searches the available gems list for selected gems and attempts to add each one to the current project.
|
||||
Updates UI after completion.
|
||||
:return: None
|
||||
"""
|
||||
|
||||
selected_item = self.create_project_template_list.selectionModel().currentIndex()
|
||||
project_template_path = self.create_project_template_list.model().data(selected_item)
|
||||
if not project_template_path:
|
||||
return
|
||||
|
||||
folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Project Name",
|
||||
manifest.get_o3de_projects_folder().as_posix())
|
||||
folder_dialog.setFileMode(QFileDialog.AnyFile)
|
||||
folder_dialog.setOptions(QFileDialog.ShowDirsOnly)
|
||||
project_count = 0
|
||||
project_name = "MyNewProject"
|
||||
while os.path.exists(os.path.join(engine_path, project_name)):
|
||||
project_name = f"MyNewProject{project_count}"
|
||||
project_count += 1
|
||||
folder_dialog.selectFile(project_name)
|
||||
project_folder = None
|
||||
if folder_dialog.exec():
|
||||
project_folder = folder_dialog.selectedFiles()
|
||||
if project_folder:
|
||||
if engine_template.create_project(project_path=project_folder[0],
|
||||
template_path=project_template_path) == 0:
|
||||
# Success
|
||||
register.register(project_path=project_folder[0])
|
||||
self.refresh_project_list()
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Project {project_folder[0]} created.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def create_gem_handler(self):
|
||||
"""
|
||||
Opens the Create Gem pane. Retrieves a list of available templates for display
|
||||
:return: None
|
||||
"""
|
||||
loader = QUiLoader()
|
||||
self.create_gem_file = QFile(self.create_gem_ui_file_path.as_posix())
|
||||
|
||||
if not self.create_gem_file:
|
||||
logger.error(f'Failed to create gem UI file at {self.create_gem_file}')
|
||||
return
|
||||
|
||||
self.create_gem_dialog = loader.load(self.create_gem_file)
|
||||
|
||||
if not self.create_gem_dialog:
|
||||
logger.error(f'Failed to load create gem dialog file at {self.create_gem_file}')
|
||||
return
|
||||
|
||||
self.create_gem_ok_button = self.create_gem_dialog.findChild(QDialogButtonBox, 'okCancel')
|
||||
self.create_gem_ok_button.accepted.connect(self.create_gem_accepted_handler)
|
||||
|
||||
self.create_gem_template_list = self.create_gem_dialog.findChild(QListView, 'gemTemplates')
|
||||
self.refresh_create_gem_template_list()
|
||||
|
||||
self.create_gem_dialog.exec()
|
||||
|
||||
def create_gem_accepted_handler(self) -> None:
|
||||
"""
|
||||
Searches the available gems list for selected gems and attempts to add each one to the current gem.
|
||||
Updates UI after completion.
|
||||
:return: None
|
||||
"""
|
||||
selected_item = self.create_gem_template_list.selectionModel().currentIndex()
|
||||
gem_template_path = self.create_gem_template_list.model().data(selected_item)
|
||||
if not gem_template_path:
|
||||
return
|
||||
|
||||
folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Gem Name",
|
||||
manifest.get_o3de_gems_folder().as_posix())
|
||||
folder_dialog.setFileMode(QFileDialog.AnyFile)
|
||||
folder_dialog.setOptions(QFileDialog.ShowDirsOnly)
|
||||
gem_count = 0
|
||||
gem_name = "MyNewGem"
|
||||
while os.path.exists(os.path.join(engine_path, gem_name)):
|
||||
gem_name = f"MyNewGem{gem_count}"
|
||||
gem_count += 1
|
||||
folder_dialog.selectFile(gem_name)
|
||||
gem_folder = None
|
||||
if folder_dialog.exec():
|
||||
gem_folder = folder_dialog.selectedFiles()
|
||||
if gem_folder:
|
||||
if engine_template.create_gem(gem_path=gem_folder[0],
|
||||
template_path=gem_template_path) == 0:
|
||||
# Success
|
||||
register.register(gem_path=gem_folder[0])
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Gem {gem_folder[0]} created.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def create_template_handler(self):
|
||||
"""
|
||||
Opens a foldr select dialog and lets the user select the source folder they want to make a template
|
||||
out of, then opens a second folder select dialog to get where they want to put the template and it name
|
||||
:return: None
|
||||
"""
|
||||
|
||||
source_folder = QFileDialog.getExistingDirectory(self.dialog,
|
||||
"Select a Folder to make a template out of.",
|
||||
manifest.get_o3de_folder().as_posix())
|
||||
if not source_folder:
|
||||
return
|
||||
|
||||
destination_template_folder_dialog = QFileDialog(self.dialog,
|
||||
"Select where the template is to be created and named.",
|
||||
manifest.get_o3de_templates_folder().as_posix())
|
||||
destination_template_folder_dialog.setFileMode(QFileDialog.AnyFile)
|
||||
destination_template_folder_dialog.setOptions(QFileDialog.ShowDirsOnly)
|
||||
destination_folder = None
|
||||
if destination_template_folder_dialog.exec():
|
||||
destination_folder = destination_template_folder_dialog.selectedFiles()
|
||||
if not destination_folder:
|
||||
return
|
||||
|
||||
if engine_template.create_template(source_path=source_folder,
|
||||
template_path=destination_folder[0]) == 0:
|
||||
# Success
|
||||
register.register(template_path=destination_folder[0])
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Template {destination_folder[0]} created.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def create_from_template_handler(self):
|
||||
"""
|
||||
Opens the Create from_template pane. Retrieves a list of available from_templates for display
|
||||
:return: None
|
||||
"""
|
||||
loader = QUiLoader()
|
||||
self.create_from_template_file = QFile(self.create_from_template_ui_file_path.as_posix())
|
||||
|
||||
if not self.create_from_template_file:
|
||||
logger.error(f'Failed to create from_template UI file at {self.create_from_template_file}')
|
||||
return
|
||||
|
||||
self.create_from_template_dialog = loader.load(self.create_from_template_file)
|
||||
|
||||
if not self.create_from_template_dialog:
|
||||
logger.error(f'Failed to load create from_template dialog file at {self.create_from_template_file}')
|
||||
return
|
||||
|
||||
self.create_from_template_ok_button = self.create_from_template_dialog.findChild(QDialogButtonBox, 'okCancel')
|
||||
self.create_from_template_ok_button.accepted.connect(self.create_from_template_accepted_handler)
|
||||
|
||||
self.create_from_template_list = self.create_from_template_dialog.findChild(QListView, 'genericTemplates')
|
||||
self.refresh_create_from_template_list()
|
||||
|
||||
self.create_from_template_dialog.exec()
|
||||
|
||||
def create_from_template_accepted_handler(self) -> None:
|
||||
"""
|
||||
Searches the available gems list for selected gems and attempts to add each one to the current gem.
|
||||
Updates UI after completion.
|
||||
:return: None
|
||||
"""
|
||||
create_gem_item = self.get_selected_gem_template()
|
||||
if not create_gem_item:
|
||||
return
|
||||
|
||||
folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Gem Name",
|
||||
manifest.get_o3de_gems_folder().as_posix())
|
||||
folder_dialog.setFileMode(QFileDialog.AnyFile)
|
||||
folder_dialog.setOptions(QFileDialog.ShowDirsOnly)
|
||||
gem_count = 0
|
||||
gem_name = "MyNewGem"
|
||||
while os.path.exists(os.path.join(engine_path, gem_name)):
|
||||
gem_name = f"MyNewGem{gem_count}"
|
||||
gem_count += 1
|
||||
folder_dialog.selectFile(gem_name)
|
||||
gem_folder = None
|
||||
if folder_dialog.exec():
|
||||
gem_folder = folder_dialog.selectedFiles()
|
||||
if gem_folder:
|
||||
if engine_template.create_gem(gem_folder[0], create_gem_item[1]) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"gem {os.path.basename(os.path.normpath(gem_folder[0]))} created."
|
||||
" Build your\nnew gem before hitting OK to launch.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def add_project_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a valid project. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
project_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Project Folder",
|
||||
manifest.get_o3de_projects_folder().as_posix())
|
||||
if project_folder:
|
||||
if register.register(project_path=project_folder) == 0:
|
||||
# Success
|
||||
self.refresh_project_list()
|
||||
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Added Project {project_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def add_gem_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a gem. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
gem_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Gem Folder",
|
||||
manifest.get_o3de_gems_folder().as_posix())
|
||||
if gem_folder:
|
||||
if register.register(gem_path=gem_folder) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Added Gem {gem_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def add_template_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a valid template. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
template_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Template Folder",
|
||||
manifest.get_o3de_templates_folder().as_posix())
|
||||
if template_folder:
|
||||
if register.register(template_path=template_folder) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Added Template {template_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def add_restricted_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a valid template. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
restricted_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Restricted Folder",
|
||||
manifest.get_o3de_restricted_folder().as_posix())
|
||||
if restricted_folder:
|
||||
if register.register(restricted_path=restricted_folder) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Added Restricted {restricted_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def remove_project_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a valid project. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
project_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Project Folder",
|
||||
manifest.get_o3de_projects_folder().as_posix())
|
||||
if project_folder:
|
||||
if register.register(project_path=project_folder, remove=True) == 0:
|
||||
# Success
|
||||
self.refresh_project_list()
|
||||
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Removed Project {project_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def remove_gem_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a gem. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
gem_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Gem Folder",
|
||||
manifest.get_o3de_gems_folder().as_posix())
|
||||
if gem_folder:
|
||||
if register.register(gem_path=gem_folder, remove=True) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Removed Gem {gem_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def remove_template_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a valid template. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
template_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Template Folder",
|
||||
manifest.get_o3de_templates_folder().as_posix())
|
||||
if template_folder:
|
||||
if register.register(template_path=template_folder, remove=True) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Removed Template {template_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def remove_restricted_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a valid template. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
restricted_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Restricted Folder",
|
||||
manifest.get_o3de_restricted_folder().as_posix())
|
||||
if restricted_folder:
|
||||
if register.register(restricted_path=restricted_folder, remove=True) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Removed Restricted {restricted_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def manage_project_gem_targets_handler(self):
|
||||
"""
|
||||
Opens the Gem management pane. Waits for the load thread to complete if still running and displays all
|
||||
active gems for the current project as well as all available gems which aren't currently active.
|
||||
:return: None
|
||||
"""
|
||||
|
||||
if not self.get_selected_project_path():
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText("Please select a project")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
loader = QUiLoader()
|
||||
self.manage_project_gem_targets_file = QFile(self.manage_project_gem_targets_ui_file_path.as_posix())
|
||||
|
||||
if not self.manage_project_gem_targets_file:
|
||||
logger.error(f'Failed to load manage gem targets UI file at {self.manage_project_gem_targets_ui_file_path}')
|
||||
return
|
||||
|
||||
self.manage_project_gem_targets_dialog = loader.load(self.manage_project_gem_targets_file)
|
||||
|
||||
if not self.manage_project_gem_targets_dialog:
|
||||
logger.error(f'Failed to load gems dialog file at {self.manage_project_gem_targets_ui_file_path.as_posix()}')
|
||||
return
|
||||
|
||||
self.manage_project_gem_targets_dialog.setWindowTitle(f"Manage Gems for Project:"
|
||||
f" {self.get_selected_project_name()}")
|
||||
|
||||
self.add_gem_button = self.manage_project_gem_targets_dialog.findChild(QPushButton, 'addGemTargetsButton')
|
||||
self.add_gem_button.clicked.connect(self.add_project_gem_targets_handler)
|
||||
|
||||
self.available_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView,
|
||||
'availableGemTargetsList')
|
||||
self.refresh_project_gem_targets_available_list()
|
||||
|
||||
self.remove_project_gem_targets_button = self.manage_project_gem_targets_dialog.findChild(QPushButton,
|
||||
'removeGemTargetsButton')
|
||||
self.remove_project_gem_targets_button.clicked.connect(self.remove_project_gem_targets_handler)
|
||||
|
||||
self.enabled_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView,
|
||||
'enabledGemTargetsList')
|
||||
self.refresh_project_gem_targets_enabled_list()
|
||||
|
||||
self.manage_project_gem_targets_dialog.exec()
|
||||
|
||||
|
||||
def manage_project_gem_targets_get_selected_available_gems(self) -> list:
|
||||
selected_items = self.available_gem_targets_list.selectionModel().selectedRows()
|
||||
return [(self.available_gem_targets_list.model().data(item)) for item in selected_items]
|
||||
|
||||
def manage_project_gem_targets_get_selected_enabled_gems(self) -> list:
|
||||
selected_items = self.enabled_gem_targets_list.selectionModel().selectedRows()
|
||||
return [(self.enabled_gem_targets_list.model().data(item)) for item in selected_items]
|
||||
|
||||
def add_project_gem_targets_handler(self) -> None:
|
||||
gem_paths = manifest.get_all_gems()
|
||||
for gem_target in self.manage_project_gem_targets_get_selected_available_gems():
|
||||
for gem_path in gem_paths:
|
||||
enable_gem.enable_gem_in_project(gem_path=gem_path,
|
||||
project_path=self.get_selected_project_path())
|
||||
self.refresh_project_gem_targets_available_list()
|
||||
self.refresh_project_gem_targets_enabled_list()
|
||||
return
|
||||
self.refresh_project_gem_targets_available_list()
|
||||
self.refresh_project_gem_targets_enabled_list()
|
||||
|
||||
def remove_project_gem_targets_handler(self):
|
||||
gem_paths = manifest.get_all_gems()
|
||||
for gem_target in self.manage_project_gem_targets_get_selected_enabled_gems():
|
||||
for gem_path in gem_paths:
|
||||
disable_gem.disable_gem_in_project(gem_path=gem_path,
|
||||
project_path=self.get_selected_project_path())
|
||||
self.refresh_project_gem_targets_available_list()
|
||||
self.refresh_project_gem_targets_enabled_list()
|
||||
return
|
||||
self.refresh_project_gem_targets_available_list()
|
||||
self.refresh_project_gem_targets_enabled_list()
|
||||
|
||||
def refresh_project_gem_targets_enabled_list(self) -> None:
|
||||
enabled_project_gem_targets_model = QStandardItemModel()
|
||||
enabled_project_gems = cmake.get_project_gems(project_path=self.get_selected_project_path())
|
||||
for gem_target in sorted(enabled_project_gems):
|
||||
model_item = QStandardItem(gem_target)
|
||||
enabled_project_gem_targets_model.appendRow(model_item)
|
||||
self.enabled_gem_targets_list.setModel(enabled_project_gem_targets_model)
|
||||
|
||||
|
||||
def refresh_project_gem_targets_available_list(self) -> None:
|
||||
available_project_gem_targets_model = QStandardItemModel()
|
||||
enabled_project_gem_targets = cmake.get_project_gems(project_path=self.get_selected_project_path())
|
||||
all_gem_targets = manifest.get_all_gems()
|
||||
for gem_target in sorted(all_gem_targets):
|
||||
if gem_target not in enabled_project_gem_targets:
|
||||
model_item = QStandardItem(gem_target)
|
||||
available_project_gem_targets_model.appendRow(model_item)
|
||||
self.available_gem_targets_list.setModel(available_project_gem_targets_model)
|
||||
|
||||
|
||||
def refresh_create_project_template_list(self) -> None:
|
||||
self.create_project_template_model = QStandardItemModel()
|
||||
for project_template_path in manifest.get_project_templates():
|
||||
model_item = QStandardItem(project_template_path)
|
||||
self.create_project_template_model.appendRow(model_item)
|
||||
self.create_project_template_list.setModel(self.create_project_template_model)
|
||||
|
||||
def refresh_create_gem_template_list(self) -> None:
|
||||
self.create_gem_template_model = QStandardItemModel()
|
||||
for gem_template_path in manifest.get_gem_templates():
|
||||
model_item = QStandardItem(gem_template_path)
|
||||
self.create_gem_template_model.appendRow(model_item)
|
||||
self.create_gem_template_list.setModel(self.create_gem_template_model)
|
||||
|
||||
def refresh_create_from_template_list(self) -> None:
|
||||
self.create_from_template_model = QStandardItemModel()
|
||||
for generic_template_path in manifest.get_generic_templates():
|
||||
model_item = QStandardItem(generic_template_path)
|
||||
self.create_from_template_model.appendRow(model_item)
|
||||
self.create_from_template_list.setModel(self.create_from_template_model)
|
||||
|
||||
def update_mru_list(self, used_project: str) -> None:
|
||||
"""
|
||||
Promote a supplied project name to the "most recent" in a given MRU list.
|
||||
:param used_project: path to project to promote
|
||||
:param file_path: path to mru list file
|
||||
:return: None
|
||||
"""
|
||||
used_project = os.path.normpath(used_project)
|
||||
if not os.path.exists(os.path.dirname(self.mru_file_path)):
|
||||
os.makedirs(os.path.dirname(self.mru_file_path), exist_ok=True)
|
||||
mru_data = {}
|
||||
try:
|
||||
with open(self.mru_file_path, 'r') as mru_file:
|
||||
mru_data = json.loads(mru_file.read())
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
|
||||
recent_list = mru_data.get('Projects', [])
|
||||
recent_list = [item for item in recent_list if item.get('Path') != used_project and
|
||||
self.is_project_folder(item.get('Path'))]
|
||||
|
||||
new_list = [{'Path': used_project}]
|
||||
new_list.extend(recent_list)
|
||||
|
||||
mru_data['Projects'] = new_list
|
||||
try:
|
||||
with open(self.mru_file_path, 'w') as mru_file:
|
||||
mru_file.write(json.dumps(mru_data, indent=1))
|
||||
except PermissionError as e:
|
||||
logger.warning(f"Failed to write {self.mru_file_path} with error {e}")
|
||||
|
||||
def get_mru_list(self) -> List[str]:
|
||||
"""
|
||||
Retrieve the current MRU list. Does not perform validation that the projects still appear valid
|
||||
:return: list of full path strings to project folders
|
||||
"""
|
||||
if not os.path.exists(os.path.dirname(self.mru_file_path)):
|
||||
return []
|
||||
try:
|
||||
with open(self.mru_file_path, 'r') as mru_file:
|
||||
mru_data = json.loads(mru_file.read())
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
except json.JSONDecodeError:
|
||||
logger.error(f'MRU list at {self.mru_file_path} is not valid JSON')
|
||||
return []
|
||||
|
||||
recent_list = mru_data.get('Projects', [])
|
||||
return [item.get('Path') for item in recent_list if item.get('Path') is not None]
|
||||
|
||||
@Slot(str)
|
||||
def handle_log_message(self, message: str) -> None:
|
||||
"""
|
||||
Signal handler for messages from the logger. Displays the most recent warning/error
|
||||
:param message: formatted log message from DialogLoggerSignaller
|
||||
:return:
|
||||
"""
|
||||
if not self.log_display:
|
||||
return
|
||||
self.log_display.setText(message)
|
||||
self.log_display.setToolTip(message)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
dialog_app = QApplication(sys.argv)
|
||||
my_dialog = ProjectManagerDialog()
|
||||
dialog_app.exec_()
|
||||
sys.exit(0)
|
||||
@@ -1,61 +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.
|
||||
#
|
||||
|
||||
import os
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
pyside_initialized = False
|
||||
old_env = os.environ.copy()
|
||||
|
||||
# Helper to extend OS PATH for pyside to locate our QT binaries based on our build folder
|
||||
def add_pyside_environment(bin_path):
|
||||
if is_pyside_ready():
|
||||
# No need to reinitialize currently
|
||||
logger.info("Pyside environment already initialized")
|
||||
return
|
||||
global old_env
|
||||
old_env = os.environ.copy()
|
||||
binaries_path = Path(os.path.normpath(bin_path))
|
||||
platforms_path = binaries_path.joinpath("platforms")
|
||||
logger.info(f'Adding binaries path {binaries_path}')
|
||||
os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = str(platforms_path)
|
||||
|
||||
path = os.environ['PATH']
|
||||
|
||||
new_path = os.pathsep.join([str(binaries_path), str(platforms_path), path])
|
||||
os.environ['PATH'] = new_path
|
||||
|
||||
global pyside_initialized
|
||||
pyside_initialized = True
|
||||
|
||||
|
||||
def is_pyside_ready():
|
||||
return pyside_initialized
|
||||
|
||||
|
||||
def is_configuration_valid(workspace):
|
||||
return os.path.basename(workspace.paths.build_directory()) != "debug"
|
||||
|
||||
|
||||
def uninstall_env():
|
||||
if not is_pyside_ready():
|
||||
logger.warning("Pyside not initialized")
|
||||
return os.environ
|
||||
|
||||
global old_env
|
||||
if old_env.get("QT_QPA_PLATFORM_PLUGIN_PATH"):
|
||||
old_env.pop("QT_QPA_PLATFORM_PLUGIN_PATH")
|
||||
os.environ = old_env
|
||||
return old_env
|
||||
@@ -1,10 +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.
|
||||
#
|
||||
@@ -1,255 +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.
|
||||
#
|
||||
|
||||
|
||||
import pytest
|
||||
'''
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import logging
|
||||
import pathlib
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
# Code lives one folder above
|
||||
project_manager_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
|
||||
sys.path.append(project_manager_path)
|
||||
|
||||
from pyside import add_pyside_environment, is_configuration_valid
|
||||
from ly_test_tools import WINDOWS
|
||||
|
||||
sys.path.append(os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..', '..')))
|
||||
executable_path = ''
|
||||
from cmake.Tools import registration
|
||||
from cmake.Tools import engine_template
|
||||
|
||||
|
||||
class ProjectHelper:
|
||||
def __init__(self):
|
||||
self._temp_directory = pathlib.Path(tempfile.TemporaryDirectory().name).resolve()
|
||||
self._temp_directory.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
self.home_path = self._temp_directory
|
||||
registration.override_home_folder = self.home_path
|
||||
self.engine_path = registration.get_this_engine_path()
|
||||
if registration.register(engine_path=self.engine_path):
|
||||
assert True, f"Failed to register the engine."
|
||||
|
||||
if registration.register_shipped_engine_o3de_objects():
|
||||
assert True, f"Failed to register shipped engine objects."
|
||||
|
||||
self.projects_folder = registration.get_o3de_projects_folder()
|
||||
if not self.projects_folder.is_dir():
|
||||
assert True
|
||||
|
||||
self.application = None
|
||||
self.dialog = None
|
||||
|
||||
def create_empty_projects(self):
|
||||
self.project_1_dir = self.projects_folder / "Project1"
|
||||
if engine_template.create_project(project_manager_path=self.project_1_dir):
|
||||
assert True, f"Failed to create Project1."
|
||||
|
||||
self.project_2_dir = self.projects_folder / "Project2"
|
||||
if engine_template.create_project(project_manager_path=self.project_2_dir):
|
||||
assert True, f"Failed to create Project2."
|
||||
|
||||
self.project_3_dir = self.projects_folder / "Project3"
|
||||
if engine_template.create_project(project_manager_path=self.project_3_dir):
|
||||
assert True, f"Failed to create Project3."
|
||||
|
||||
self.invalid_project_dir = self.projects_folder / "InvalidProject"
|
||||
self.invalid_project_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def setup_dialog_test(self, workspace):
|
||||
add_pyside_environment(workspace.paths.build_directory())
|
||||
|
||||
if not is_configuration_valid(workspace):
|
||||
# This is essentially skipif debug. Our debug tests use our profile version of python, but that means we'd
|
||||
# need to use the profile version of PySide which works with the profile QT libs which aren't in the debug
|
||||
# folder we've built.
|
||||
return None
|
||||
|
||||
from PySide2.QtWidgets import QApplication, QMessageBox
|
||||
|
||||
if QApplication.instance():
|
||||
self.application = QApplication.instance()
|
||||
else:
|
||||
self.application = QApplication(sys.argv)
|
||||
assert self.application
|
||||
|
||||
from projects import ProjectManagerDialog
|
||||
|
||||
try:
|
||||
self.dialog = ProjectManagerDialog(settings_folder=self.home_path)
|
||||
return self.dialog
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to create ProjectManagerDialog with error {e}')
|
||||
return None
|
||||
|
||||
def create_project_from_template(self, project_name) -> bool:
|
||||
"""
|
||||
Uses the dialog to create a temporary project based on the first template found
|
||||
:param project_name: Name of project to create. Will be created under temp_project_root
|
||||
:return: True for Success, False for failure
|
||||
"""
|
||||
from PySide2.QtWidgets import QWidget, QFileDialog
|
||||
from projects import ProjectManagerDialog
|
||||
|
||||
QWidget.exec = MagicMock()
|
||||
self.dialog.create_project_handler()
|
||||
QWidget.exec.assert_called_once()
|
||||
|
||||
assert len(self.dialog.project_templates), 'Failed to find any project templates'
|
||||
ProjectManagerDialog.get_selected_project_template = MagicMock(return_value=self.dialog.project_templates[0])
|
||||
|
||||
QFileDialog.exec = MagicMock()
|
||||
create_project_path = self.projects_folder / project_name
|
||||
QFileDialog.selectedFiles = MagicMock(return_value=[create_project_path])
|
||||
self.dialog.create_project_accepted_handler()
|
||||
if create_project_path.is_dir():
|
||||
assert True, f"Expected project creation folder not found at {create_project_path}"
|
||||
|
||||
if QWidget.exec.call_count == 2:
|
||||
assert True, "Message box confirming project creation failed to show"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def project_helper():
|
||||
return ProjectHelper()
|
||||
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently")
|
||||
@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent
|
||||
def test_logger_handler(workspace, project_helper):
|
||||
my_dialog = project_helper.setup_dialog_test(workspace)
|
||||
if not my_dialog:
|
||||
return
|
||||
|
||||
from PySide2.QtWidgets import QMessageBox
|
||||
QMessageBox.warning = MagicMock()
|
||||
logger.error(f'Testing logger')
|
||||
QMessageBox.warning.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently")
|
||||
@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent
|
||||
def test_mru_list(workspace, project_helper):
|
||||
my_dialog = project_helper.setup_dialog_test(workspace)
|
||||
if not my_dialog:
|
||||
return
|
||||
|
||||
project_helper.create_empty_projects()
|
||||
|
||||
from PySide2.QtWidgets import QMessageBox
|
||||
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 0, f'MRU list unexpectedly had entries: {mru_list}'
|
||||
|
||||
QMessageBox.warning = MagicMock()
|
||||
my_dialog.add_project(project_helper.invalid_project_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 0, f'MRU list unexpectedly added an invalid project : {mru_list}'
|
||||
QMessageBox.warning.assert_called_once()
|
||||
|
||||
my_dialog.add_project(project_helper.project_1_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 1, f'MRU list failed to add project at {project_helper.project_1_dir}'
|
||||
|
||||
my_dialog.add_project(project_helper.project_1_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 1, f'MRU list added project at {project_helper.project_1_dir} a second time : {mru_list}'
|
||||
|
||||
my_dialog.update_mru_list(project_helper.project_1_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 1, f'MRU list added project at {project_helper.project_1_dir} a second time : {mru_list}'
|
||||
|
||||
my_dialog.add_project(project_helper.project_2_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 2, f'MRU list failed to add project at {project_helper.project_2_dir}'
|
||||
|
||||
assert mru_list[0] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't first item"
|
||||
assert mru_list[1] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't second item"
|
||||
|
||||
my_dialog.update_mru_list(project_helper.project_1_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 2, f'MRU list added wrong items {mru_list}'
|
||||
assert mru_list[0] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't first item"
|
||||
assert mru_list[1] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't second item"
|
||||
|
||||
my_dialog.add_project(project_helper.invalid_project_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 2, f'MRU list added invalid item {mru_list}'
|
||||
assert mru_list[0] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't first item"
|
||||
assert mru_list[1] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't second item"
|
||||
|
||||
my_dialog.add_project(project_helper.project_3_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 3, f'MRU list failed to add {project_helper.project_3_dir} : {mru_list}'
|
||||
assert mru_list[0] == project_helper.project_3_dir, f"{project_helper.project_3_dir} wasn't first item"
|
||||
assert mru_list[1] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't second item"
|
||||
assert mru_list[2] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't third item"
|
||||
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently")
|
||||
@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent
|
||||
def test_create_project(workspace, project_helper):
|
||||
my_dialog = project_helper.setup_dialog_test(workspace)
|
||||
if not my_dialog:
|
||||
return
|
||||
|
||||
project_helper.create_project_from_template("TestCreateProject")
|
||||
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently")
|
||||
@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent
|
||||
def test_add_remove_gems(workspace, project_helper):
|
||||
my_dialog = project_helper.setup_dialog_test(workspace)
|
||||
if not my_dialog:
|
||||
return
|
||||
|
||||
my_project_name = "TestAddRemoveGems"
|
||||
|
||||
project_helper.create_project_from_template(project_manager_path=my_project_name)
|
||||
my_project_path = project_helper.projects_folder / my_project_name
|
||||
|
||||
from PySide2.QtWidgets import QWidget, QFileDialog
|
||||
from projects import ProjectManagerDialog
|
||||
|
||||
assert my_dialog.get_selected_project_path() == my_project_path, "TestAddRemoveGems project not selected"
|
||||
QWidget.exec = MagicMock()
|
||||
my_dialog.manage_gems_handler()
|
||||
assert my_dialog.manage_gem_targets_dialog, "No gem management dialog created"
|
||||
QWidget.exec.assert_called_once()
|
||||
|
||||
if not len(my_dialog.all_gems_list):
|
||||
assert True, 'Failed to find any gems'
|
||||
|
||||
my_test_gem_path = my_dialog.all_gems_list[0]
|
||||
gem_data = registration.get_gem_data(my_test_gem_path)
|
||||
my_test_gem_selection = (my_test_gem_name, my_test_gem_path)
|
||||
ProjectManagerDialog.get_selected_add_gems = MagicMock(return_value=[my_test_gem_selection])
|
||||
|
||||
assert my_test_gem_name, "No Name set in test gem"
|
||||
assert my_test_gem_name not in my_dialog.project_gem_list, f'Gem {my_test_gem_name} already in project gem list'
|
||||
|
||||
my_dialog.add_gems_handler()
|
||||
assert my_test_gem_name in my_dialog.project_gem_list, f'Gem {my_test_gem_name} failed to add to gem list'
|
||||
|
||||
ProjectManagerDialog.get_selected_project_gems = MagicMock(return_value=[my_test_gem_name])
|
||||
my_dialog.remove_gems_handler()
|
||||
assert my_test_gem_name not in my_dialog.project_gem_list, f'Gem {my_test_gem_name} still in project gem list'
|
||||
'''
|
||||
|
||||
def test_project_place_holder():
|
||||
pass
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user