Merge remote-tracking branch 'upstream/stabilization/2110' into Atom/santorac/MaterialEditorHandlesMissingTextures
This commit is contained in:
@@ -125,7 +125,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>General Availability</string>
|
||||
<string>Stable 21.11</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::AutoText</enum>
|
||||
|
||||
@@ -199,41 +199,6 @@ namespace AzAssetBrowserRequestHandlerPrivate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper utility - determines if the thing being dragged is a FBX from the scene import pipeline
|
||||
// This is important to differentiate.
|
||||
// when someone drags a MTL file directly into the viewport, even from a FBX, we want to spawn it as a decal
|
||||
// but when someone drags a FBX that contains MTL files, we want only to spawn the meshes.
|
||||
// so we have to specifically differentiate here between the mimeData type that contains the source as the root
|
||||
// (dragging the fbx file itself)
|
||||
// and one which contains the actual product at its root.
|
||||
|
||||
bool IsDragOfFBX(const QMimeData* mimeData)
|
||||
{
|
||||
AZStd::vector<AssetBrowserEntry*> entries;
|
||||
if (!AssetBrowserEntry::FromMimeData(mimeData, entries))
|
||||
{
|
||||
// if mimedata does not even contain entries, no point in proceeding.
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto entry : entries)
|
||||
{
|
||||
if (entry->GetEntryType() != AssetBrowserEntry::AssetEntryType::Source)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// this is a source file. Is it the filetype we're looking for?
|
||||
if (SourceAssetBrowserEntry* source = azrtti_cast<SourceAssetBrowserEntry*>(entry))
|
||||
{
|
||||
if (AzFramework::StringFunc::Equal(source->GetExtension().c_str(), ".fbx", false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AzAssetBrowserRequestHandler::AzAssetBrowserRequestHandler()
|
||||
|
||||
@@ -4181,6 +4181,8 @@ extern "C" int AZ_DLL_EXPORT CryEditMain(int argc, char* argv[])
|
||||
"\nThis could be because of incorrectly configured components, or missing required gems."
|
||||
"\nSee other errors for more details.");
|
||||
|
||||
AzToolsFramework::EditorEventsBus::Broadcast(&AzToolsFramework::EditorEvents::NotifyEditorInitialized);
|
||||
|
||||
if (didCryEditStart)
|
||||
{
|
||||
app->EnableOnIdle();
|
||||
|
||||
@@ -9,10 +9,6 @@
|
||||
#define CRYINCLUDE_EDITOR_MATERIAL_IEDITORMATERIALMANAGER_H
|
||||
#pragma once
|
||||
|
||||
#define MATERIAL_FILE_EXT ".mtl"
|
||||
#define DCC_MATERIAL_FILE_EXT ".dccmtl"
|
||||
#define MATERIALS_PATH "materials/"
|
||||
|
||||
#include <Include/IBaseLibraryManager.h>
|
||||
#include <IMaterial.h>
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include <LmbrCentral/Rendering/LensFlareAsset.h>
|
||||
#include <LmbrCentral/Rendering/MeshAsset.h>
|
||||
#include <LmbrCentral/Rendering/MaterialAsset.h>
|
||||
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/RTTI/TypeInfo.h>
|
||||
@@ -136,14 +135,6 @@ AssetCatalogModel::AssetCatalogModel(QObject* parent)
|
||||
}
|
||||
}
|
||||
|
||||
// Special cases for SimpleAssets. If these get full-fledged AssetData types, these cases can be removed.
|
||||
QString textureExtensions = LmbrCentral::TextureAsset::GetFileFilter();
|
||||
m_extensionToAssetType.insert(AZStd::make_pair(textureExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector<AZ::Uuid> { AZ::AzTypeInfo<LmbrCentral::TextureAsset>::Uuid() }));
|
||||
QString materialExtensions = LmbrCentral::MaterialAsset::GetFileFilter();
|
||||
m_extensionToAssetType.insert(AZStd::make_pair(materialExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector<AZ::Uuid> { AZ::AzTypeInfo<LmbrCentral::MaterialAsset>::Uuid() }));
|
||||
QString dccMaterialExtensions = LmbrCentral::DccMaterialAsset::GetFileFilter();
|
||||
m_extensionToAssetType.insert(AZStd::make_pair(dccMaterialExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector<AZ::Uuid> { AZ::AzTypeInfo<LmbrCentral::DccMaterialAsset>::Uuid() }));
|
||||
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext);
|
||||
AZ_Assert(serializeContext, "Failed to acquire application serialize context.");
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>General Availability</string>
|
||||
<string>Stable 21.11</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -1677,9 +1677,13 @@ namespace AZ
|
||||
// they will trigger a ReleaseAsset call sometime after the AssetManager has begun to shut down, which can lead to
|
||||
// race conditions.
|
||||
|
||||
// Make sure the streamer request is removed first before the asset is released
|
||||
// If the asset is released first it could lead to a race condition where another thread starts loading the asset
|
||||
// again and attempts to add a new streamer request with the same ID before the old one has been removed, causing
|
||||
// that load request to fail
|
||||
RemoveActiveStreamerRequest(assetId);
|
||||
weakAsset = {};
|
||||
loadingAsset.Reset();
|
||||
RemoveActiveStreamerRequest(assetId);
|
||||
};
|
||||
|
||||
auto&& [deadline, priority] = GetEffectiveDeadlineAndPriority(*handler, asset.GetType(), loadParams);
|
||||
|
||||
@@ -56,11 +56,12 @@ namespace AZ
|
||||
int numberOfWorkerThreads = m_numberOfWorkerThreads;
|
||||
if (numberOfWorkerThreads <= 0) // spawn default number of threads
|
||||
{
|
||||
#if (AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS)
|
||||
numberOfWorkerThreads = AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS;
|
||||
#else
|
||||
uint32_t scaledHardwareThreads = Threading::CalcNumWorkerThreads(cl_jobThreadsConcurrencyRatio, cl_jobThreadsMinNumber, cl_jobThreadsNumReserved);
|
||||
numberOfWorkerThreads = AZ::GetMin(static_cast<unsigned int>(desc.m_workerThreads.capacity()), scaledHardwareThreads);
|
||||
#if (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS)
|
||||
numberOfWorkerThreads = AZ::GetMin(numberOfWorkerThreads, AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS);
|
||||
#endif // (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS)
|
||||
#endif // (AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS)
|
||||
}
|
||||
|
||||
threadDesc.m_cpuId = AFFINITY_MASK_USERTHREADS;
|
||||
|
||||
@@ -104,6 +104,8 @@ namespace AZ
|
||||
->HandlesType<AZStd::variant>();
|
||||
jsonContext->Serializer<JsonOptionalSerializer>()
|
||||
->HandlesType<AZStd::optional>();
|
||||
jsonContext->Serializer<JsonBitsetSerializer>()
|
||||
->HandlesType<AZStd::bitset>();
|
||||
|
||||
MathReflect(jsonContext);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace AZ
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonAnySerializer, SystemAllocator, 0);
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonVariantSerializer, SystemAllocator, 0);
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonOptionalSerializer, SystemAllocator, 0);
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonBitsetSerializer, SystemAllocator, 0);
|
||||
|
||||
JsonSerializationResult::Result JsonUnsupportedTypesSerializer::Load(void*, const Uuid&, const rapidjson::Value&,
|
||||
JsonDeserializerContext& context)
|
||||
@@ -49,4 +50,10 @@ namespace AZ
|
||||
return "The Json Serialization doesn't support AZStd::optional by design. No JSON format has yet been found that wasn't deemed too "
|
||||
"complex or overly verbose.";
|
||||
}
|
||||
|
||||
AZStd::string_view JsonBitsetSerializer::GetMessage() const
|
||||
{
|
||||
return "The Json Serialization doesn't support AZStd::bitset by design. No JSON format has yet been found that is content creator "
|
||||
"friendly i.e., easy to comprehend the intent.";
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -65,4 +65,14 @@ namespace AZ
|
||||
protected:
|
||||
AZStd::string_view GetMessage() const override;
|
||||
};
|
||||
|
||||
class JsonBitsetSerializer : public JsonUnsupportedTypesSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(JsonBitsetSerializer, "{10CE969D-D69E-4B3F-8593-069736F8F705}", JsonUnsupportedTypesSerializer);
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
|
||||
protected:
|
||||
AZStd::string_view GetMessage() const override;
|
||||
};
|
||||
} // namespace AZ
|
||||
|
||||
@@ -30,8 +30,13 @@ namespace AZ
|
||||
|
||||
if (Interface<TaskGraphActiveInterface>::Get() == nullptr)
|
||||
{
|
||||
#if (AZ_TRAIT_THREAD_NUM_TASK_GRAPH_WORKER_THREADS)
|
||||
const uint32_t numberOfWorkerThreads = AZ_TRAIT_THREAD_NUM_TASK_GRAPH_WORKER_THREADS;
|
||||
#else
|
||||
const uint32_t numberOfWorkerThreads = Threading::CalcNumWorkerThreads(cl_taskGraphThreadsConcurrencyRatio, cl_taskGraphThreadsMinNumber, cl_taskGraphThreadsNumReserved);
|
||||
#endif // (AZ_TRAIT_THREAD_NUM_TASK_GRAPH_WORKER_THREADS)
|
||||
Interface<TaskGraphActiveInterface>::Register(this); // small window that another thread can try to use taskgraph between this line and the set instance.
|
||||
m_taskExecutor = aznew TaskExecutor(Threading::CalcNumWorkerThreads(cl_taskGraphThreadsConcurrencyRatio, cl_taskGraphThreadsMinNumber, cl_taskGraphThreadsNumReserved));
|
||||
m_taskExecutor = aznew TaskExecutor(numberOfWorkerThreads);
|
||||
TaskExecutor::SetInstance(m_taskExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@
|
||||
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 0
|
||||
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
|
||||
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0
|
||||
#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0
|
||||
#define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0
|
||||
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
|
||||
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0
|
||||
|
||||
@@ -75,7 +75,6 @@
|
||||
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1
|
||||
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
|
||||
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0
|
||||
#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0
|
||||
#define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0
|
||||
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
|
||||
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0
|
||||
|
||||
@@ -75,7 +75,6 @@
|
||||
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1
|
||||
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
|
||||
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0
|
||||
#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0
|
||||
#define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0
|
||||
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
|
||||
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0
|
||||
|
||||
@@ -75,7 +75,6 @@
|
||||
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1
|
||||
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
|
||||
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 1
|
||||
#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0
|
||||
#define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 1
|
||||
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
|
||||
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1
|
||||
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
|
||||
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0
|
||||
#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0
|
||||
#define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0
|
||||
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
|
||||
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0
|
||||
|
||||
@@ -652,7 +652,7 @@ namespace UnitTest
|
||||
threads.emplace_back([this, &threadCount, &cv, assetUuid]() {
|
||||
bool checkLoaded = true;
|
||||
|
||||
for (int i = 0; i < 5000; i++)
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
Asset<AssetWithAssetReference> asset1 =
|
||||
m_testAssetManager->GetAsset(assetUuid, azrtti_typeid<AssetWithAssetReference>(), AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
@@ -678,7 +678,7 @@ namespace UnitTest
|
||||
while (threadCount > 0 && !timedOut)
|
||||
{
|
||||
AZStd::unique_lock<AZStd::mutex> lock(mutex);
|
||||
timedOut = (AZStd::cv_status::timeout == cv.wait_until(lock, AZStd::chrono::system_clock::now() + DefaultTimeoutSeconds * 20000));
|
||||
timedOut = (AZStd::cv_status::timeout == cv.wait_until(lock, AZStd::chrono::system_clock::now() + DefaultTimeoutSeconds));
|
||||
}
|
||||
|
||||
ASSERT_EQ(threadCount, 0) << "Thread count is non-zero, a thread has likely deadlocked. Test will not shut down cleanly.";
|
||||
@@ -1190,7 +1190,7 @@ namespace UnitTest
|
||||
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
|
||||
TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
|
||||
#else
|
||||
TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
|
||||
TEST_F(AssetJobsFloodTest, ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
|
||||
#endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
|
||||
{
|
||||
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect();
|
||||
|
||||
@@ -1241,6 +1241,10 @@ namespace AZ::IO
|
||||
|
||||
m_arrZips.insert(revItZip.base(), desc);
|
||||
|
||||
// This lock is for m_arrZips.
|
||||
// Unlock it now because the modification is complete, and events responding to this signal
|
||||
// will attempt to lock the same mutex, causing the application to lock up.
|
||||
lock.unlock();
|
||||
m_levelOpenEvent.Signal(levelDirs);
|
||||
}
|
||||
|
||||
|
||||
@@ -927,6 +927,9 @@ namespace AzToolsFramework
|
||||
/// Notify that the MainWindow has been fully initialized
|
||||
virtual void NotifyMainWindowInitialized(QMainWindow* /*mainWindow*/) {}
|
||||
|
||||
/// Notify that the Editor has been fully initialized
|
||||
virtual void NotifyEditorInitialized() {}
|
||||
|
||||
/// Signal that an asset should be highlighted / selected
|
||||
virtual void SelectAsset(const QString& /* assetPath */) {}
|
||||
};
|
||||
|
||||
@@ -214,12 +214,17 @@ namespace AzToolsFramework
|
||||
, public AZ::BehaviorEBusHandler
|
||||
{
|
||||
AZ_EBUS_BEHAVIOR_BINDER(EditorEventsBusHandler, "{352F80BB-469A-40B6-B322-FE57AB51E4DA}", AZ::SystemAllocator,
|
||||
NotifyRegisterViews);
|
||||
NotifyRegisterViews, NotifyEditorInitialized);
|
||||
|
||||
void NotifyRegisterViews() override
|
||||
{
|
||||
Call(FN_NotifyRegisterViews);
|
||||
}
|
||||
|
||||
void NotifyEditorInitialized() override
|
||||
{
|
||||
Call(FN_NotifyEditorInitialized);
|
||||
}
|
||||
};
|
||||
|
||||
} // Internal
|
||||
@@ -443,6 +448,7 @@ namespace AzToolsFramework
|
||||
->Attribute(AZ::Script::Attributes::Module, "editor")
|
||||
->Handler<Internal::EditorEventsBusHandler>()
|
||||
->Event("NotifyRegisterViews", &EditorEvents::NotifyRegisterViews)
|
||||
->Event("NotifyEditorInitialized", &EditorEvents::NotifyEditorInitialized)
|
||||
;
|
||||
|
||||
behaviorContext->EBus<ViewPaneCallbackBus>("ViewPaneCallbackBus")
|
||||
|
||||
-5
@@ -234,11 +234,6 @@ namespace AzToolsFramework
|
||||
return SourceFileDetails("Icons/AssetBrowser/Lua_16.svg");
|
||||
}
|
||||
|
||||
if (AzFramework::StringFunc::Equal(extension.c_str(), ".mtl"))
|
||||
{
|
||||
return SourceFileDetails("Icons/AssetBrowser/Material_16.svg");
|
||||
}
|
||||
|
||||
if (AzFramework::StringFunc::Equal(extension.c_str(), AzToolsFramework::SliceUtilities::GetSliceFileExtension().c_str()))
|
||||
{
|
||||
return SourceFileDetails("Icons/AssetBrowser/Slice_16.svg");
|
||||
|
||||
+5
-2
@@ -31,7 +31,10 @@ AZ_POP_DISABLE_WARNING
|
||||
AZ_CVAR(
|
||||
bool, ed_hideAssetPickerPathColumn, true, nullptr, AZ::ConsoleFunctorFlags::Null,
|
||||
"Hide AssetPicker path column for a clearer view.");
|
||||
AZ_CVAR_EXTERNED(bool, ed_useNewAssetBrowserTableView);
|
||||
|
||||
AZ_CVAR(
|
||||
bool, ed_useNewAssetPickerView, false, nullptr, AZ::ConsoleFunctorFlags::Null,
|
||||
"Uses the new Asset Picker View.");
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -106,7 +109,7 @@ namespace AzToolsFramework
|
||||
m_persistentState = AZ::UserSettings::CreateFind<AzToolsFramework::QWidgetSavedState>(AZ::Crc32(("AssetBrowserTreeView_Dialog_" + name).toUtf8().data()), AZ::UserSettings::CT_GLOBAL);
|
||||
|
||||
m_ui->m_assetBrowserTableViewWidget->setVisible(false);
|
||||
if (ed_useNewAssetBrowserTableView)
|
||||
if (ed_useNewAssetPickerView)
|
||||
{
|
||||
m_ui->m_assetBrowserTreeViewWidget->setVisible(false);
|
||||
m_ui->m_assetBrowserTableViewWidget->setVisible(true);
|
||||
|
||||
+2
@@ -597,11 +597,13 @@ namespace AzToolsFramework
|
||||
pte.SetVisibleEnforcement(true);
|
||||
}
|
||||
|
||||
ScopedUndoBatch undo("Modify Entity Property");
|
||||
PropertyOutcome result = pte.SetProperty(propertyPath, value);
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
PropertyEditorEntityChangeNotificationBus::Event(componentInstance.GetEntityId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, componentInstance.GetComponentId());
|
||||
}
|
||||
undo.MarkEntityDirty(componentInstance.GetEntityId());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+3
@@ -64,6 +64,9 @@ namespace AzToolsFramework::Prefab
|
||||
);
|
||||
|
||||
m_backButton->setToolTip("Up one level (-)");
|
||||
|
||||
// Currently hide this button until we can correctly disable/enable it based on context.
|
||||
m_backButton->hide();
|
||||
}
|
||||
|
||||
void PrefabViewportFocusPathHandler::OnPrefabFocusChanged()
|
||||
|
||||
+1
-18
@@ -4705,13 +4705,6 @@ namespace AzToolsFramework
|
||||
{
|
||||
if (mimeData->hasFormat(AssetBrowser::AssetBrowserEntry::GetMimeType()))
|
||||
{
|
||||
// extra special case: MTLs from FBX drags are ignored. are we dragging a FBX file?
|
||||
bool isDraggingFBXFile = false;
|
||||
AssetBrowser::AssetBrowserEntry::ForEachEntryInMimeData<AssetBrowser::SourceAssetBrowserEntry>(mimeData, [&](const AssetBrowser::SourceAssetBrowserEntry* source)
|
||||
{
|
||||
isDraggingFBXFile = isDraggingFBXFile || AzFramework::StringFunc::Equal(source->GetExtension().c_str(), ".fbx", false);
|
||||
});
|
||||
|
||||
// the usual case - we only allow asset browser drops of assets that have actually been associated with a kind of component.
|
||||
AssetBrowser::AssetBrowserEntry::ForEachEntryInMimeData<AssetBrowser::ProductAssetBrowserEntry>(mimeData, [&](const AssetBrowser::ProductAssetBrowserEntry* product)
|
||||
{
|
||||
@@ -4723,17 +4716,7 @@ namespace AzToolsFramework
|
||||
|
||||
if (canCreateComponent && !componentTypeId.IsNull())
|
||||
{
|
||||
// we have a component type that handles this asset.
|
||||
// but we disallow it if its a MTL file from a FBX and the FBX itself is being dragged. Its still allowed
|
||||
// to drag the actual MTL.
|
||||
EBusFindAssetTypeByName materialAssetTypeResult("Material");
|
||||
AZ::AssetTypeInfoBus::BroadcastResult(materialAssetTypeResult, &AZ::AssetTypeInfo::GetAssetType);
|
||||
AZ::Data::AssetType materialAssetType = materialAssetTypeResult.GetAssetType();
|
||||
|
||||
if ((!isDraggingFBXFile) || (product->GetAssetType() != materialAssetType))
|
||||
{
|
||||
callbackFunction(product);
|
||||
}
|
||||
callbackFunction(product);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -690,7 +690,6 @@ namespace AssetBuilderSDK
|
||||
static const char* textureExtensions = ".dds";
|
||||
static const char* staticMeshExtensions = ".cgf";
|
||||
static const char* skinnedMeshExtensions = ".skin";
|
||||
static const char* materialExtensions = ".mtl";
|
||||
|
||||
// MIPS
|
||||
static const int c_MaxMipsCount = 11; // 11 is for 8k textures non-compressed. When not compressed it is using one file per mip.
|
||||
@@ -805,11 +804,6 @@ namespace AssetBuilderSDK
|
||||
return textureAssetType;
|
||||
}
|
||||
|
||||
if (AzFramework::StringFunc::Find(materialExtensions, extension.c_str()) != AZStd::string::npos)
|
||||
{
|
||||
return materialAssetType;
|
||||
}
|
||||
|
||||
if (AzFramework::StringFunc::Find(staticMeshExtensions, extension.c_str()) != AZStd::string::npos)
|
||||
{
|
||||
return meshAssetType;
|
||||
|
||||
@@ -9,3 +9,4 @@
|
||||
#pragma once
|
||||
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT false
|
||||
|
||||
@@ -96,5 +96,10 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
return AZ::Utils::GetExecutableDirectory();
|
||||
}
|
||||
|
||||
AZ::Outcome<QString, QString> CreateDesktopShortcut([[maybe_unused]] const QString& filename, [[maybe_unused]] const QString& targetPath, [[maybe_unused]] const QStringList& arguments)
|
||||
{
|
||||
return AZ::Failure(QObject::tr("Creating desktop shortcuts functionality not implemented for this platform yet."));
|
||||
}
|
||||
} // namespace ProjectUtils
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -9,3 +9,4 @@
|
||||
#pragma once
|
||||
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT false
|
||||
|
||||
@@ -137,5 +137,10 @@ namespace O3DE::ProjectManager
|
||||
|
||||
return editorPath;
|
||||
}
|
||||
|
||||
AZ::Outcome<QString, QString> CreateDesktopShortcut([[maybe_unused]] const QString& filename, [[maybe_unused]] const QString& targetPath, [[maybe_unused]] const QStringList& arguments)
|
||||
{
|
||||
return AZ::Failure(QObject::tr("Creating desktop shortcuts functionality not implemented for this platform yet."));
|
||||
}
|
||||
} // namespace ProjectUtils
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -9,3 +9,4 @@
|
||||
#pragma once
|
||||
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR true
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT true
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
@@ -146,5 +147,26 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
return AZ::Utils::GetExecutableDirectory();
|
||||
}
|
||||
|
||||
AZ::Outcome<QString, QString> CreateDesktopShortcut(const QString& filename, const QString& targetPath, const QStringList& arguments)
|
||||
{
|
||||
const QString cmd{"powershell.exe"};
|
||||
const QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
const QString shortcutPath = QString("%1/%2.lnk").arg(desktopPath).arg(filename);
|
||||
const QString arg = QString("$s=(New-Object -COM WScript.Shell).CreateShortcut('%1');$s.TargetPath='%2';$s.Arguments='%3';$s.Save();")
|
||||
.arg(shortcutPath)
|
||||
.arg(targetPath)
|
||||
.arg(arguments.join(' '));
|
||||
auto createShortcutResult = ExecuteCommandResult(cmd, QStringList{"-Command", arg}, QProcessEnvironment::systemEnvironment());
|
||||
if (!createShortcutResult.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(QObject::tr("Failed to create desktop shortcut %1 <br><br>"
|
||||
"Please verify you have permission to create files at the specified location.<br><br> %2")
|
||||
.arg(shortcutPath)
|
||||
.arg(createShortcutResult.GetError()));
|
||||
}
|
||||
|
||||
return AZ::Success(QObject::tr("Desktop shortcut created at<br><a href=\"%1\">%2</a>").arg(desktopPath).arg(shortcutPath));
|
||||
}
|
||||
} // namespace ProjectUtils
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -126,7 +126,8 @@ namespace O3DE::ProjectManager
|
||||
// Select the first entry after everything got correctly sized
|
||||
QTimer::singleShot(200, [=]{
|
||||
QModelIndex firstModelIndex = m_gemModel->index(0, 0);
|
||||
m_gemModel->GetSelectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect);
|
||||
QModelIndex proxyIndex = m_proxyModel->mapFromSource(firstModelIndex);
|
||||
m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -209,7 +210,7 @@ namespace O3DE::ProjectManager
|
||||
const bool gemFound = gemInfoHash.contains(gemName);
|
||||
if (!gemFound && !m_gemModel->IsAdded(index) && !m_gemModel->IsAddedDependency(index))
|
||||
{
|
||||
m_gemModel->removeRow(i);
|
||||
m_gemModel->RemoveGem(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -239,7 +240,7 @@ namespace O3DE::ProjectManager
|
||||
m_filterWidget->ResetAllFilters();
|
||||
|
||||
// Reselect the same selection to proc UI updates
|
||||
m_proxyModel->GetSelectionModel()->select(m_proxyModel->GetSelectionModel()->selection(), QItemSelectionModel::Select);
|
||||
m_proxyModel->GetSelectionModel()->setCurrentIndex(m_proxyModel->GetSelectionModel()->currentIndex(), QItemSelectionModel::Select);
|
||||
}
|
||||
|
||||
void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies)
|
||||
@@ -268,7 +269,7 @@ namespace O3DE::ProjectManager
|
||||
if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded)
|
||||
{
|
||||
m_downloadController->AddGemDownload(GemModel::GetName(modelIndex));
|
||||
GemModel::SetDownloadStatus(*m_proxyModel, m_proxyModel->mapFromSource(modelIndex), GemInfo::DownloadStatus::Downloading);
|
||||
GemModel::SetDownloadStatus(*m_gemModel, modelIndex, GemInfo::DownloadStatus::Downloading);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +301,7 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
|
||||
QModelIndex proxyIndex = m_proxyModel->mapFromSource(modelIndex);
|
||||
m_proxyModel->GetSelectionModel()->select(proxyIndex, QItemSelectionModel::ClearAndSelect);
|
||||
m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
|
||||
m_gemListView->scrollTo(proxyIndex);
|
||||
}
|
||||
|
||||
@@ -362,6 +363,9 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
const QString selectedGemPath = m_gemModel->GetPath(modelIndex);
|
||||
|
||||
// Remove gem from gems to be added
|
||||
GemModel::SetIsAdded(*m_gemModel, modelIndex, false);
|
||||
|
||||
// Unregister the gem
|
||||
auto unregisterResult = PythonBindingsInterface::Get()->UnregisterGem(selectedGemPath);
|
||||
if (!unregisterResult)
|
||||
@@ -370,8 +374,10 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString selectedGemName = m_gemModel->GetName(modelIndex);
|
||||
|
||||
// Remove gem from model
|
||||
m_gemModel->removeRow(modelIndex.row());
|
||||
m_gemModel->RemoveGem(modelIndex);
|
||||
|
||||
// Delete uninstalled gem directory
|
||||
if (!ProjectUtils::DeleteProjectFiles(selectedGemPath, /*force*/true))
|
||||
@@ -382,6 +388,11 @@ namespace O3DE::ProjectManager
|
||||
|
||||
// Show undownloaded remote gem again
|
||||
Refresh();
|
||||
|
||||
// Select remote gem
|
||||
QModelIndex remoteGemIndex = m_gemModel->FindIndexByNameString(selectedGemName);
|
||||
QModelIndex proxyIndex = m_proxyModel->mapFromSource(remoteGemIndex);
|
||||
m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -564,7 +575,8 @@ namespace O3DE::ProjectManager
|
||||
if (succeeded)
|
||||
{
|
||||
// refresh the information for downloaded gems
|
||||
const AZ::Outcome<QVector<GemInfo>, AZStd::string>& allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath);
|
||||
const AZ::Outcome<QVector<GemInfo>, AZStd::string>& allGemInfosResult =
|
||||
PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath);
|
||||
if (allGemInfosResult.IsSuccess())
|
||||
{
|
||||
// we should find the gem name now in all gem infos
|
||||
@@ -572,15 +584,33 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
if (gemInfo.m_name == gemName)
|
||||
{
|
||||
QModelIndex index = m_gemModel->FindIndexByNameString(gemName);
|
||||
if (index.isValid())
|
||||
QModelIndex oldIndex = m_gemModel->FindIndexByNameString(gemName);
|
||||
if (oldIndex.isValid())
|
||||
{
|
||||
m_proxyModel->setData(m_proxyModel->mapFromSource(index), GemInfo::DownloadSuccessful, GemModel::RoleDownloadStatus);
|
||||
m_gemModel->setData(index, gemInfo.m_path, GemModel::RolePath);
|
||||
m_gemModel->setData(index, gemInfo.m_path, GemModel::RoleDirectoryLink);
|
||||
// Check if old gem is selected
|
||||
bool oldGemSelected = false;
|
||||
if (m_gemModel->GetSelectionModel()->currentIndex() == oldIndex)
|
||||
{
|
||||
oldGemSelected = true;
|
||||
}
|
||||
|
||||
// Remove old remote gem
|
||||
m_gemModel->RemoveGem(oldIndex);
|
||||
|
||||
// Add new downloaded version of gem
|
||||
QModelIndex newIndex = m_gemModel->AddGem(gemInfo);
|
||||
GemModel::SetDownloadStatus(*m_gemModel, newIndex, GemInfo::DownloadSuccessful);
|
||||
GemModel::SetIsAdded(*m_gemModel, newIndex, true);
|
||||
|
||||
// Select new version of gem if it was previously selected
|
||||
if (oldGemSelected)
|
||||
{
|
||||
QModelIndex proxyIndex = m_proxyModel->mapFromSource(newIndex);
|
||||
m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -590,7 +620,7 @@ namespace O3DE::ProjectManager
|
||||
QModelIndex index = m_gemModel->FindIndexByNameString(gemName);
|
||||
if (index.isValid())
|
||||
{
|
||||
m_proxyModel->setData(m_proxyModel->mapFromSource(index), GemInfo::DownloadFailed, GemModel::RoleDownloadStatus);
|
||||
GemModel::SetDownloadStatus(*m_gemModel, index, GemInfo::DownloadFailed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,14 +26,14 @@ namespace O3DE::ProjectManager
|
||||
return m_selectionModel;
|
||||
}
|
||||
|
||||
void GemModel::AddGem(const GemInfo& gemInfo)
|
||||
QModelIndex GemModel::AddGem(const GemInfo& gemInfo)
|
||||
{
|
||||
if (FindIndexByNameString(gemInfo.m_name).isValid())
|
||||
{
|
||||
// do not add gems with duplicate names
|
||||
// this can happen by mistake or when a gem repo has a gem with the same name as a local gem
|
||||
AZ_TracePrintf("GemModel", "Ignoring duplicate gem: %s", gemInfo.m_name.toUtf8().constData());
|
||||
return;
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QStandardItem* item = new QStandardItem();
|
||||
@@ -67,6 +67,22 @@ namespace O3DE::ProjectManager
|
||||
|
||||
const QModelIndex modelIndex = index(rowCount()-1, 0);
|
||||
m_nameToIndexMap[gemInfo.m_name] = modelIndex;
|
||||
|
||||
return modelIndex;
|
||||
}
|
||||
|
||||
void GemModel::RemoveGem(const QModelIndex& modelIndex)
|
||||
{
|
||||
removeRow(modelIndex.row());
|
||||
}
|
||||
|
||||
void GemModel::RemoveGem(const QString& gemName)
|
||||
{
|
||||
auto nameFind = m_nameToIndexMap.find(gemName);
|
||||
if (nameFind != m_nameToIndexMap.end())
|
||||
{
|
||||
removeRow(nameFind->row());
|
||||
}
|
||||
}
|
||||
|
||||
void GemModel::Clear()
|
||||
@@ -391,11 +407,11 @@ namespace O3DE::ProjectManager
|
||||
// Select a valid row if currently selected row was removed
|
||||
if (selectedRowRemoved)
|
||||
{
|
||||
for (const QModelIndex& index : m_nameToIndexMap)
|
||||
for (const QModelIndex& index : m_nameToIndexMap)
|
||||
{
|
||||
if (index.isValid())
|
||||
{
|
||||
GetSelectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
|
||||
GetSelectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,9 @@ namespace O3DE::ProjectManager
|
||||
RoleRepoUri
|
||||
};
|
||||
|
||||
void AddGem(const GemInfo& gemInfo);
|
||||
QModelIndex AddGem(const GemInfo& gemInfo);
|
||||
void RemoveGem(const QModelIndex& modelIndex);
|
||||
void RemoveGem(const QString& gemName);
|
||||
void Clear();
|
||||
void UpdateGemDependencies();
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace O3DE::ProjectManager
|
||||
// Select the first entry after everything got correctly sized
|
||||
QTimer::singleShot(200, [=]{
|
||||
QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0);
|
||||
m_gemRepoListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect);
|
||||
m_gemRepoListView->selectionModel()->setCurrentIndex(firstModelIndex, QItemSelectionModel::ClearAndSelect);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,11 @@
|
||||
|
||||
#include <ProjectButtonWidget.h>
|
||||
#include <ProjectManagerDefs.h>
|
||||
#include <ProjectUtils.h>
|
||||
#include <ProjectManager_Traits_Platform.h>
|
||||
#include <AzQtComponents/Utilities/DesktopUtilities.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
@@ -23,6 +27,7 @@
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -205,6 +210,29 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
AzQtComponents::ShowFileOnDesktop(m_projectInfo.m_path);
|
||||
});
|
||||
|
||||
#if AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT
|
||||
menu->addAction(tr("Create Editor desktop shortcut..."), this, [this]()
|
||||
{
|
||||
AZ::IO::FixedMaxPath executableDirectory = ProjectUtils::GetEditorDirectory();
|
||||
AZStd::string executableFilename = "Editor";
|
||||
AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
|
||||
|
||||
const QString shortcutName = QString("%1 Editor").arg(m_projectInfo.m_displayName);
|
||||
const QString arg = QString("--regset=\"/Amazon/AzCore/Bootstrap/project_path=%1\"").arg(m_projectInfo.m_path);
|
||||
|
||||
auto result = ProjectUtils::CreateDesktopShortcut(shortcutName, editorExecutablePath.c_str(), { arg });
|
||||
if(result.IsSuccess())
|
||||
{
|
||||
QMessageBox::information(this, tr("Desktop Shortcut Created"), result.GetValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), result.GetError());
|
||||
}
|
||||
});
|
||||
#endif // AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT
|
||||
|
||||
menu->addSeparator();
|
||||
menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo); });
|
||||
menu->addSeparator();
|
||||
|
||||
@@ -628,11 +628,11 @@ namespace O3DE::ProjectManager
|
||||
return AZ::Failure(QObject::tr("Process for command '%1' timed out at %2 seconds").arg(cmd).arg(commandTimeoutSeconds));
|
||||
}
|
||||
int resultCode = execProcess.exitCode();
|
||||
QString resultOutput = execProcess.readAllStandardOutput();
|
||||
if (resultCode != 0)
|
||||
{
|
||||
return AZ::Failure(QObject::tr("Process for command '%1' failed (result code %2").arg(cmd).arg(resultCode));
|
||||
return AZ::Failure(QObject::tr("Process for command '%1' failed (result code %2) %3").arg(cmd).arg(resultCode).arg(resultOutput));
|
||||
}
|
||||
QString resultOutput = execProcess.readAllStandardOutput();
|
||||
return AZ::Success(resultOutput);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,15 @@ namespace O3DE::ProjectManager
|
||||
AZ::Outcome<QString, QString> GetProjectBuildPath(const QString& projectPath);
|
||||
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath);
|
||||
AZ::Outcome<QString, QString> RunGetPythonScript(const QString& enginePath);
|
||||
|
||||
/**
|
||||
* Create a desktop shortcut.
|
||||
* @param filename the name of the desktop shorcut file
|
||||
* @param target the path to the target to run
|
||||
* @param arguments the argument list to provide to the target
|
||||
* @return AZ::Outcome with the command result on success
|
||||
*/
|
||||
AZ::Outcome<QString, QString> CreateDesktopShortcut(const QString& filename, const QString& targetPath, const QStringList& arguments);
|
||||
|
||||
AZ::IO::FixedMaxPath GetEditorDirectory();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user