Merge branch 'development' of https://github.com/o3de/o3de into jckand/EditorPrefabTests

Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com>
This commit is contained in:
jckand-amzn
2022-01-07 09:44:55 -06:00
95 changed files with 1061 additions and 2928 deletions
@@ -97,7 +97,13 @@ def AssetBrowser_SearchFiltering():
# 3) Type the name of an asset in the search bar and make sure it is filtered to and selectable
asset_browser = editor_window.findChild(QtWidgets.QDockWidget, "Asset Browser")
search_bar = asset_browser.findChild(QtWidgets.QLineEdit, "textSearch")
search_bar.setText("cedar.fbx")
# Add a small pause when typing in the search bar in order to check that the entries are updated properly
search_bar.setText("Cedar.f")
general.idle_wait(0.5)
search_bar.setText("Cedar.fbx")
general.idle_wait(0.5)
asset_browser_tree = asset_browser.findChild(QtWidgets.QTreeView, "m_assetBrowserTreeViewWidget")
asset_browser_table = asset_browser.findChild(QtWidgets.QTreeView, "m_assetBrowserTableViewWidget")
found = await pyside_utils.wait_for_condition(lambda: pyside_utils.find_child_by_pattern(asset_browser_table, "cedar.fbx"), 5.0)
-232
View File
@@ -1,232 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "BaseLibrary.h"
#include "BaseLibraryItem.h"
#include "Include/IBaseLibraryManager.h"
#include <Util/PathUtil.h>
#include <IFileUtil.h>
//////////////////////////////////////////////////////////////////////////
// CBaseLibrary implementation.
//////////////////////////////////////////////////////////////////////////
CBaseLibrary::CBaseLibrary(IBaseLibraryManager* pManager)
: m_pManager(pManager)
, m_bModified(false)
, m_bLevelLib(false)
, m_bNewLibrary(true)
{
}
//////////////////////////////////////////////////////////////////////////
CBaseLibrary::~CBaseLibrary()
{
m_items.clear();
}
//////////////////////////////////////////////////////////////////////////
IBaseLibraryManager* CBaseLibrary::GetManager()
{
return m_pManager;
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibrary::RemoveAllItems()
{
AddRef();
for (int i = 0; i < m_items.size(); i++)
{
// Unregister item in case it was registered. It is ok if it wasn't. This is still safe to call.
m_pManager->UnregisterItem(m_items[i]);
// Clear library item.
m_items[i]->m_library = nullptr;
}
m_items.clear();
Release();
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibrary::SetName(const QString& name)
{
//the fullname of the items in the library will be changed due to library's name change
//so we need unregistered them and register them after their name changed.
for (int i = 0; i < m_items.size(); i++)
{
m_pManager->UnregisterItem(m_items[i]);
}
m_name = name;
for (int i = 0; i < m_items.size(); i++)
{
m_pManager->RegisterItem(m_items[i]);
}
SetModified();
}
//////////////////////////////////////////////////////////////////////////
const QString& CBaseLibrary::GetName() const
{
return m_name;
}
//////////////////////////////////////////////////////////////////////////
bool CBaseLibrary::Save()
{
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CBaseLibrary::Load(const QString& filename)
{
m_filename = filename;
SetModified(false);
m_bNewLibrary = false;
return true;
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibrary::SetModified(bool bModified)
{
if (bModified != m_bModified)
{
m_bModified = bModified;
emit Modified(bModified);
}
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibrary::AddItem(IDataBaseItem* item, bool bRegister)
{
CBaseLibraryItem* pLibItem = (CBaseLibraryItem*)item;
// Check if item is already assigned to this library.
if (pLibItem->m_library != this)
{
pLibItem->m_library = this;
m_items.push_back(pLibItem);
SetModified();
if (bRegister)
{
m_pManager->RegisterItem(pLibItem);
}
}
}
//////////////////////////////////////////////////////////////////////////
IDataBaseItem* CBaseLibrary::GetItem(int index)
{
assert(index >= 0 && index < m_items.size());
return m_items[index];
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibrary::RemoveItem(IDataBaseItem* item)
{
for (int i = 0; i < m_items.size(); i++)
{
if (m_items[i] == item)
{
// Unregister item in case it was registered. It is ok if it wasn't. This is still safe to call.
m_pManager->UnregisterItem(m_items[i]);
m_items.erase(m_items.begin() + i);
SetModified();
break;
}
}
}
//////////////////////////////////////////////////////////////////////////
IDataBaseItem* CBaseLibrary::FindItem(const QString& name)
{
for (int i = 0; i < m_items.size(); i++)
{
if (QString::compare(m_items[i]->GetName(), name, Qt::CaseInsensitive) == 0)
{
return m_items[i];
}
}
return nullptr;
}
bool CBaseLibrary::AddLibraryToSourceControl(const QString& fullPathName) const
{
IEditor* pEditor = GetIEditor();
IFileUtil* pFileUtil = pEditor ? pEditor->GetFileUtil() : nullptr;
if (pFileUtil)
{
return pFileUtil->CheckoutFile(fullPathName.toUtf8().data(), nullptr);
}
return false;
}
bool CBaseLibrary::SaveLibrary(const char* name, bool saveEmptyLibrary)
{
assert(name != nullptr);
if (name == nullptr)
{
CryFatalError("The library you are attempting to save has no name specified.");
return false;
}
QString fileName(GetFilename());
if (fileName.isEmpty() && !saveEmptyLibrary)
{
return false;
}
fileName = Path::GamePathToFullPath(fileName);
XmlNodeRef root = GetIEditor()->GetSystem()->CreateXmlNode(name);
Serialize(root, false);
bool bRes = XmlHelpers::SaveXmlNode(GetIEditor()->GetFileUtil(), root, fileName.toUtf8().data());
if (m_bNewLibrary)
{
AddLibraryToSourceControl(fileName);
m_bNewLibrary = false;
}
if (!bRes)
{
QByteArray filenameUtf8 = fileName.toUtf8();
AZStd::string strMessage = AZStd::string::format("The file %s is read-only and the save of the library couldn't be performed. Try to remove the \"read-only\" flag or check-out the file and then try again.", filenameUtf8.data());
CryMessageBox(strMessage.c_str(), "Saving Error", MB_OK | MB_ICONWARNING);
}
return bRes;
}
//CONFETTI BEGIN
void CBaseLibrary::ChangeItemOrder(CBaseLibraryItem* item, unsigned int newLocation)
{
std::vector<_smart_ptr<CBaseLibraryItem> > temp;
for (unsigned int i = 0; i < m_items.size(); i++)
{
if (i == newLocation)
{
temp.push_back(_smart_ptr<CBaseLibraryItem>(item));
}
if (m_items[i] != item)
{
temp.push_back(m_items[i]);
}
}
// If newLocation is greater than the original size, append the item to end of the list
if (newLocation >= m_items.size())
{
temp.push_back(_smart_ptr<CBaseLibraryItem>(item));
}
m_items = temp;
}
//CONFETTI END
#include <moc_BaseLibrary.cpp>
-129
View File
@@ -1,129 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_BASELIBRARY_H
#define CRYINCLUDE_EDITOR_BASELIBRARY_H
#pragma once
#if !defined(Q_MOC_RUN)
#include "Include/IDataBaseLibrary.h"
#include "Include/IBaseLibraryManager.h"
#include "Include/EditorCoreAPI.h"
#include "Util/TRefCountBase.h"
#include <QObject>
#endif
// Ensure we don't try to dllimport when moc includes us
#if defined(Q_MOC_BUILD) && !defined(EDITOR_CORE)
#define EDITOR_CORE
#endif
/** This a base class for all Libraries used by Editor.
*/
class EDITOR_CORE_API CBaseLibrary
: public QObject
, public TRefCountBase<IDataBaseLibrary>
{
Q_OBJECT
public:
explicit CBaseLibrary(IBaseLibraryManager* pManager);
~CBaseLibrary();
//! Set library name.
virtual void SetName(const QString& name);
//! Get library name.
const QString& GetName() const override;
//! Set new filename for this library.
virtual bool SetFilename(const QString& filename, [[maybe_unused]] bool checkForUnique = true) { m_filename = filename.toLower(); return true; };
const QString& GetFilename() const override { return m_filename; };
bool Save() override = 0;
bool Load(const QString& filename) override = 0;
void Serialize(XmlNodeRef& node, bool bLoading) override = 0;
//! Mark library as modified.
void SetModified(bool bModified = true) override;
//! Check if library was modified.
bool IsModified() const override { return m_bModified; };
//////////////////////////////////////////////////////////////////////////
// Working with items.
//////////////////////////////////////////////////////////////////////////
//! Add a new prototype to library.
void AddItem(IDataBaseItem* item, bool bRegister = true) override;
//! Get number of known prototypes.
int GetItemCount() const override { return static_cast<int>(m_items.size()); }
//! Get prototype by index.
IDataBaseItem* GetItem(int index) override;
//! Delete item by pointer of item.
void RemoveItem(IDataBaseItem* item) override;
//! Delete all items from library.
void RemoveAllItems() override;
//! Find library item by name.
//! Using linear search.
IDataBaseItem* FindItem(const QString& name) override;
//! Check if this library is local level library.
bool IsLevelLibrary() const override { return m_bLevelLib; };
//! Set library to be level library.
void SetLevelLibrary(bool bEnable) override { m_bLevelLib = bEnable; };
//////////////////////////////////////////////////////////////////////////
//! Return manager for this library.
IBaseLibraryManager* GetManager() override;
// Saves the library with the main tag defined by the parameter name
bool SaveLibrary(const char* name, bool saveEmptyLibrary = false);
//CONFETTI BEGIN
// Used to change the library item order
void ChangeItemOrder(CBaseLibraryItem* item, unsigned int newLocation) override;
//CONFETTI END
signals:
void Modified(bool bModified);
private:
// Add the library to the source control
bool AddLibraryToSourceControl(const QString& fullPathName) const;
protected:
//! Name of the library.
QString m_name;
//! Filename of the library.
QString m_filename;
//! Flag set when library was modified.
bool m_bModified;
// Flag set when the library is just created and it's not yet saved for the first time.
bool m_bNewLibrary;
//! Level library is saved within the level .ly file and is local for this level.
bool m_bLevelLib;
//////////////////////////////////////////////////////////////////////////
// Manager.
IBaseLibraryManager* m_pManager;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
// Array of all our library items.
std::vector<_smart_ptr<CBaseLibraryItem> > m_items;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
#endif // CRYINCLUDE_EDITOR_BASELIBRARY_H
-261
View File
@@ -1,261 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "BaseLibraryItem.h"
#include "BaseLibrary.h"
#include "BaseLibraryManager.h"
#include "Undo/IUndoObject.h"
#include <AzCore/Math/Uuid.h>
//undo object for multi-changes inside library item. such as set all variables to default values.
//For example: change particle emitter shape will lead to multiple variable changes
class CUndoBaseLibraryItem
: public IUndoObject
{
public:
CUndoBaseLibraryItem(IBaseLibraryManager *libMgr, CBaseLibraryItem* libItem, bool ignoreChild)
: m_libMgr(libMgr)
{
assert(libItem);
assert(libMgr);
m_itemPath = libItem->GetFullName();
//serialize the lib item to undo
m_undoCtx.node = GetIEditor()->GetSystem()->CreateXmlNode("Undo");
m_undoCtx.bIgnoreChilds = ignoreChild;
m_undoCtx.bLoading = false; //saving
m_undoCtx.bUniqName = false; //don't generate new name
m_undoCtx.bCopyPaste = true; //so it won't override guid
m_undoCtx.bUndo = true;
libItem->Serialize(m_undoCtx);
//evaluate size
XmlString xmlStr = m_undoCtx.node->getXML();
m_size = sizeof(CUndoBaseLibraryItem);
m_size += static_cast<int>(xmlStr.GetAllocatedMemory());
m_size += m_itemPath.length();
}
protected:
int GetSize() override
{
return m_size;
}
void Undo(bool bUndo) override
{
//find the libItem
IDataBaseItem *libItem = m_libMgr->FindItemByName(m_itemPath);
if (libItem == nullptr)
{
//the undo stack is not reliable any more..
assert(false);
return;
}
//save for redo
if (bUndo)
{
m_redoCtx.node = GetIEditor()->GetSystem()->CreateXmlNode("Redo");
m_redoCtx.bIgnoreChilds = m_undoCtx.bIgnoreChilds;
m_redoCtx.bLoading = false; //saving
m_redoCtx.bUniqName = false;
m_redoCtx.bCopyPaste = true;
m_redoCtx.bUndo = true;
libItem->Serialize(m_redoCtx);
XmlString xmlStr = m_redoCtx.node->getXML();
m_size += static_cast<int>(xmlStr.GetAllocatedMemory());
}
//load previous saved data
m_undoCtx.bLoading = true;
libItem->Serialize(m_undoCtx);
}
void Redo() override
{
//find the libItem
IDataBaseItem *libItem = m_libMgr->FindItemByName(m_itemPath);
if (libItem == nullptr || m_redoCtx.node == nullptr)
{
//the undo stack is not reliable any more..
assert(false);
return;
}
m_redoCtx.bLoading = true;
libItem->Serialize(m_redoCtx);
}
private:
QString m_itemPath;
IDataBaseItem::SerializeContext m_undoCtx; //saved before operation
IDataBaseItem::SerializeContext m_redoCtx; //saved after operation so used for redo
IBaseLibraryManager* m_libMgr;
int m_size;
};
//////////////////////////////////////////////////////////////////////////
// CBaseLibraryItem implementation.
//////////////////////////////////////////////////////////////////////////
CBaseLibraryItem::CBaseLibraryItem()
{
m_library = nullptr;
GenerateId();
m_bModified = false;
}
CBaseLibraryItem::~CBaseLibraryItem()
{
}
//////////////////////////////////////////////////////////////////////////
QString CBaseLibraryItem::GetFullName() const
{
QString name;
if (m_library)
{
name = m_library->GetName() + ".";
}
name += m_name;
return name;
}
//////////////////////////////////////////////////////////////////////////
QString CBaseLibraryItem::GetGroupName()
{
QString str = GetName();
int p = str.lastIndexOf('.');
if (p >= 0)
{
return str.mid(0, p);
}
return "";
}
//////////////////////////////////////////////////////////////////////////
QString CBaseLibraryItem::GetShortName()
{
QString str = GetName();
int p = str.lastIndexOf('.');
if (p >= 0)
{
return str.mid(p + 1);
}
p = str.lastIndexOf('/');
if (p >= 0)
{
return str.mid(p + 1);
}
return str;
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryItem::SetName(const QString& name)
{
assert(m_library);
if (name == m_name)
{
return;
}
QString oldName = GetFullName();
m_name = name;
((CBaseLibraryManager*)m_library->GetManager())->OnRenameItem(this, oldName);
}
//////////////////////////////////////////////////////////////////////////
const QString& CBaseLibraryItem::GetName() const
{
return m_name;
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryItem::GenerateId()
{
GUID guid = AZ::Uuid::CreateRandom();
SetGUID(guid);
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryItem::SetGUID(REFGUID guid)
{
if (m_library)
{
((CBaseLibraryManager*)m_library->GetManager())->RegisterItem(this, guid);
}
m_guid = guid;
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryItem::Serialize(SerializeContext& ctx)
{
assert(m_library);
XmlNodeRef node = ctx.node;
if (ctx.bLoading)
{
QString name = m_name;
// Loading
node->getAttr("Name", name);
if (!ctx.bUniqName)
{
SetName(name);
}
else
{
SetName(GetLibrary()->GetManager()->MakeUniqueItemName(name));
}
if (!ctx.bCopyPaste)
{
GUID guid;
if (node->getAttr("Id", guid))
{
SetGUID(guid);
}
}
}
else
{
// Saving.
node->setAttr("Name", m_name.toUtf8().data());
node->setAttr("Id", m_guid);
node->setAttr("Library", GetLibrary()->GetName().toUtf8().data());
}
m_bModified = false;
}
//////////////////////////////////////////////////////////////////////////
IDataBaseLibrary* CBaseLibraryItem::GetLibrary() const
{
return m_library;
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryItem::SetLibrary(CBaseLibrary* pLibrary)
{
m_library = pLibrary;
}
//! Mark library as modified.
void CBaseLibraryItem::SetModified(bool bModified)
{
m_bModified = bModified;
if (m_bModified && m_library != nullptr)
{
m_library->SetModified(bModified);
}
}
-114
View File
@@ -1,114 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_BASELIBRARYITEM_H
#define CRYINCLUDE_EDITOR_BASELIBRARYITEM_H
#pragma once
#include "Include/IDataBaseItem.h"
#include "BaseLibrary.h"
#include <QMetaType>
class CBaseLibrary;
//////////////////////////////////////////////////////////////////////////
AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
/** Base class for all items contained in BaseLibraray.
*/
class EDITOR_CORE_API CBaseLibraryItem
: public TRefCountBase<IDataBaseItem>
{
AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
public:
CBaseLibraryItem();
~CBaseLibraryItem();
//! Set item name.
//! Its virtual, in case you want to override it in derrived item.
virtual void SetName(const QString& name);
//! Get item name.
const QString& GetName() const;
//! Get full item name, including name of library.
//! Name formed by adding dot after name of library
//! eg. library Pickup and item PickupRL form full item name: "Pickups.PickupRL".
QString GetFullName() const;
//! Get only nameof group from prototype.
QString GetGroupName();
//! Get short name of prototype without group.
QString GetShortName();
//! Return Library this item are contained in.
//! Item can only be at one library.
IDataBaseLibrary* GetLibrary() const;
void SetLibrary(CBaseLibrary* pLibrary);
//////////////////////////////////////////////////////////////////////////
//! Serialize library item to archive.
virtual void Serialize(SerializeContext& ctx);
//////////////////////////////////////////////////////////////////////////
//! Generate new unique id for this item.
void GenerateId();
//! Returns GUID of this material.
const GUID& GetGUID() const { return m_guid; }
//! Mark library as modified.
void SetModified(bool bModified = true);
//! Check if library was modified.
bool IsModified() const { return m_bModified; };
//! Returns true if the item is registered, otherwise false
bool IsRegistered() const { return m_bRegistered; };
//! Validate item for errors.
virtual void Validate() {};
//! Get number of sub childs.
virtual int GetChildCount() const { return 0; }
//! Get sub child by index.
virtual CBaseLibraryItem* GetChild([[maybe_unused]] int index) const { return nullptr; }
//////////////////////////////////////////////////////////////////////////
//! Gathers resources by this item.
virtual void GatherUsedResources([[maybe_unused]] CUsedResources& resources) {};
//! Get if stored item is enabled
virtual bool GetIsEnabled() { return true; };
int IsParticleItem = -1;
protected:
void SetGUID(REFGUID guid);
friend class CBaseLibrary;
friend class CBaseLibraryManager;
// Name of this prototype.
QString m_name;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
//! Reference to prototype library who contains this prototype.
_smart_ptr<CBaseLibrary> m_library;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
//! Every base library item have unique id.
GUID m_guid;
// True when item modified by editor.
bool m_bModified;
// True when item registered in manager.
bool m_bRegistered = false;
};
Q_DECLARE_METATYPE(CBaseLibraryItem*);
TYPEDEF_AUTOPTR(CBaseLibraryItem);
#endif // CRYINCLUDE_EDITOR_BASELIBRARYITEM_H
-822
View File
@@ -1,822 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "BaseLibraryManager.h"
// Editor
#include "BaseLibraryItem.h"
#include "ErrorReport.h"
#include "Undo/IUndoObject.h"
//////////////////////////////////////////////////////////////////////////
// CBaseLibraryManager implementation.
//////////////////////////////////////////////////////////////////////////
CBaseLibraryManager::CBaseLibraryManager()
{
m_bUniqNameMap = false;
m_bUniqGuidMap = true;
GetIEditor()->RegisterNotifyListener(this);
}
//////////////////////////////////////////////////////////////////////////
CBaseLibraryManager::~CBaseLibraryManager()
{
ClearAll();
GetIEditor()->UnregisterNotifyListener(this);
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::ClearAll()
{
// Delete all items from all libraries.
for (int i = 0; i < m_libs.size(); i++)
{
m_libs[i]->RemoveAllItems();
}
// if we will not copy maps locally then destructors of the elements of
// the map will operate on the already invalid map object
// see:
// CBaseLibraryManager::UnregisterItem()
// CBaseLibraryManager::DeleteItem()
// CMaterial::~CMaterial()
ItemsGUIDMap itemsGuidMap;
ItemsNameMap itemsNameMap;
{
AZStd::lock_guard<AZStd::mutex> lock(m_itemsNameMapMutex);
std::swap(itemsGuidMap, m_itemsGuidMap);
std::swap(itemsNameMap, m_itemsNameMap);
m_libs.clear();
}
}
//////////////////////////////////////////////////////////////////////////
IDataBaseLibrary* CBaseLibraryManager::FindLibrary(const QString& library)
{
const int index = FindLibraryIndex(library);
return index == -1 ? nullptr : m_libs[index];
}
//////////////////////////////////////////////////////////////////////////
int CBaseLibraryManager::FindLibraryIndex(const QString& library)
{
QString lib = library;
lib.replace('\\', '/');
for (int i = 0; i < m_libs.size(); i++)
{
QString _lib = m_libs[i]->GetFilename();
_lib.replace('\\', '/');
if (QString::compare(lib, m_libs[i]->GetName(), Qt::CaseInsensitive) == 0 || QString::compare(lib, _lib, Qt::CaseInsensitive) == 0)
{
return i;
}
}
return -1;
}
//////////////////////////////////////////////////////////////////////////
IDataBaseItem* CBaseLibraryManager::FindItem(REFGUID guid) const
{
CBaseLibraryItem* pMtl = stl::find_in_map(m_itemsGuidMap, guid, nullptr);
return pMtl;
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::SplitFullItemName(const QString& fullItemName, QString& libraryName, QString& itemName)
{
int p;
p = fullItemName.indexOf('.');
if (p < 0 || !QString::compare(fullItemName.mid(p + 1), "mtl", Qt::CaseInsensitive))
{
libraryName = "";
itemName = fullItemName;
return;
}
libraryName = fullItemName.mid(0, p);
itemName = fullItemName.mid(p + 1);
}
//////////////////////////////////////////////////////////////////////////
IDataBaseItem* CBaseLibraryManager::FindItemByName(const QString& fullItemName)
{
AZStd::lock_guard<AZStd::mutex> lock(m_itemsNameMapMutex);
return stl::find_in_map(m_itemsNameMap, fullItemName, nullptr);
}
//////////////////////////////////////////////////////////////////////////
IDataBaseItem* CBaseLibraryManager::LoadItemByName(const QString& fullItemName)
{
QString libraryName, itemName;
SplitFullItemName(fullItemName, libraryName, itemName);
if (!FindLibrary(libraryName))
{
LoadLibrary(MakeFilename(libraryName));
}
return FindItemByName(fullItemName);
}
//////////////////////////////////////////////////////////////////////////
IDataBaseItem* CBaseLibraryManager::FindItemByName(const char* fullItemName)
{
return FindItemByName(QString(fullItemName));
}
//////////////////////////////////////////////////////////////////////////
IDataBaseItem* CBaseLibraryManager::LoadItemByName(const char* fullItemName)
{
return LoadItemByName(QString(fullItemName));
}
//////////////////////////////////////////////////////////////////////////
IDataBaseItem* CBaseLibraryManager::CreateItem(IDataBaseLibrary* pLibrary)
{
assert(pLibrary);
// Add item to this library.
TSmartPtr<CBaseLibraryItem> pItem = MakeNewItem();
pLibrary->AddItem(pItem);
return pItem;
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::DeleteItem(IDataBaseItem* pItem)
{
assert(pItem);
UnregisterItem((CBaseLibraryItem*)pItem);
if (pItem->GetLibrary())
{
pItem->GetLibrary()->RemoveItem(pItem);
}
}
//////////////////////////////////////////////////////////////////////////
IDataBaseLibrary* CBaseLibraryManager::LoadLibrary(const QString& inFilename, [[maybe_unused]] bool bReload)
{
if (auto lib = FindLibrary(inFilename))
{
return lib;
}
TSmartPtr<CBaseLibrary> pLib = MakeNewLibrary();
if (!pLib->Load(MakeFilename(inFilename)))
{
Error(QObject::tr("Failed to Load Item Library: %1").arg(inFilename).toUtf8().data());
return nullptr;
}
m_libs.push_back(pLib);
return pLib;
}
//////////////////////////////////////////////////////////////////////////
int CBaseLibraryManager::GetModifiedLibraryCount() const
{
int count = 0;
for (int i = 0; i < m_libs.size(); i++)
{
if (m_libs[i]->IsModified())
{
count++;
}
}
return count;
}
//////////////////////////////////////////////////////////////////////////
IDataBaseLibrary* CBaseLibraryManager::AddLibrary(const QString& library, bool bIsLevelLibrary, bool bIsLoading)
{
// Make a filename from name of library.
QString filename = library;
if (filename.indexOf(".xml") == -1) // if its already a filename, we don't do anything
{
filename.replace(' ', '_');
if (!bIsLevelLibrary)
{
filename = MakeFilename(library);
}
else
{
// if its the level library it gets saved in the level and should not be concatenated with any other file name
filename = filename + ".xml";
}
}
IDataBaseLibrary* pBaseLib = FindLibrary(library); //library name
if (!pBaseLib)
{
pBaseLib = FindLibrary(filename); //library file name
}
if (pBaseLib)
{
return pBaseLib;
}
CBaseLibrary* lib = MakeNewLibrary();
lib->SetName(library);
lib->SetLevelLibrary(bIsLevelLibrary);
lib->SetFilename(filename, !bIsLoading);
// set modified to true, so even empty particle libraries get saved
lib->SetModified(true);
m_libs.push_back(lib);
return lib;
}
//////////////////////////////////////////////////////////////////////////
QString CBaseLibraryManager::MakeFilename(const QString& library)
{
QString filename = library;
filename.replace(' ', '_');
filename.replace(".xml", "");
// make it contain the canonical libs path:
Path::ConvertBackSlashToSlash(filename);
QString LibsPath(GetLibsPath());
Path::ConvertBackSlashToSlash(LibsPath);
if (filename.left(LibsPath.length()).compare(LibsPath, Qt::CaseInsensitive) == 0)
{
filename = filename.mid(LibsPath.length());
}
return LibsPath + filename + ".xml";
}
//////////////////////////////////////////////////////////////////////////
bool CBaseLibraryManager::IsUniqueFilename(const QString& library)
{
QString resultPath = MakeFilename(library);
CCryFile xmlFile;
// If we can find a file for the path
return !xmlFile.Open(resultPath.toUtf8().data(), "rb");
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::DeleteLibrary(const QString& library, bool forceDeleteLevel)
{
for (int i = 0; i < m_libs.size(); i++)
{
if (QString::compare(library, m_libs[i]->GetName(), Qt::CaseInsensitive) == 0)
{
CBaseLibrary* pLibrary = m_libs[i];
// Check if not level library, they cannot be deleted.
if (!pLibrary->IsLevelLibrary() || forceDeleteLevel)
{
for (int j = 0; j < pLibrary->GetItemCount(); j++)
{
UnregisterItem((CBaseLibraryItem*)pLibrary->GetItem(j));
}
pLibrary->RemoveAllItems();
if (pLibrary->IsLevelLibrary())
{
m_pLevelLibrary = nullptr;
}
m_libs.erase(m_libs.begin() + i);
}
break;
}
}
}
//////////////////////////////////////////////////////////////////////////
IDataBaseLibrary* CBaseLibraryManager::GetLibrary(int index) const
{
assert(index >= 0 && index < m_libs.size());
return m_libs[index];
};
//////////////////////////////////////////////////////////////////////////
IDataBaseLibrary* CBaseLibraryManager::GetLevelLibrary() const
{
IDataBaseLibrary* pLevelLib = nullptr;
for (int i = 0; i < GetLibraryCount(); i++)
{
if (GetLibrary(i)->IsLevelLibrary())
{
pLevelLib = GetLibrary(i);
break;
}
}
return pLevelLib;
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::SaveAllLibs()
{
for (int i = 0; i < GetLibraryCount(); i++)
{
// Check if library is modified.
IDataBaseLibrary* pLibrary = GetLibrary(i);
//Level library is saved when the level is saved
if (pLibrary->IsLevelLibrary())
{
continue;
}
if (pLibrary->IsModified())
{
if (pLibrary->Save())
{
pLibrary->SetModified(false);
}
}
}
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::Serialize(XmlNodeRef& node, bool bLoading)
{
static const char* const LEVEL_LIBRARY_TAG = "LevelLibrary";
QString rootNodeName = GetRootNodeName();
if (bLoading)
{
XmlNodeRef libs = node->findChild(rootNodeName.toUtf8().data());
if (libs)
{
for (int i = 0; i < libs->getChildCount(); i++)
{
// Load only library name.
XmlNodeRef libNode = libs->getChild(i);
if (strcmp(libNode->getTag(), LEVEL_LIBRARY_TAG) == 0)
{
if (!m_pLevelLibrary)
{
QString libName;
libNode->getAttr("Name", libName);
m_pLevelLibrary = static_cast<CBaseLibrary*>(AddLibrary(libName, true));
}
m_pLevelLibrary->Serialize(libNode, bLoading);
}
else
{
QString libName;
if (libNode->getAttr("Name", libName))
{
// Load this library.
if (!FindLibrary(libName))
{
LoadLibrary(MakeFilename(libName));
}
}
}
}
}
}
else
{
// Save all libraries.
XmlNodeRef libs = node->newChild(rootNodeName.toUtf8().data());
for (int i = 0; i < GetLibraryCount(); i++)
{
IDataBaseLibrary* pLib = GetLibrary(i);
if (pLib->IsLevelLibrary())
{
// Level libraries are saved in in level.
XmlNodeRef libNode = libs->newChild(LEVEL_LIBRARY_TAG);
pLib->Serialize(libNode, bLoading);
}
else
{
// Save only library name.
XmlNodeRef libNode = libs->newChild("Library");
libNode->setAttr("Name", pLib->GetName().toUtf8().data());
}
}
SaveAllLibs();
}
}
//////////////////////////////////////////////////////////////////////////
QString CBaseLibraryManager::MakeUniqueItemName(const QString& srcName, const QString& libName)
{
// unlikely we'll ever encounter more than 16
std::vector<AZStd::string> possibleDuplicates;
possibleDuplicates.reserve(16);
// search for strings in the database that might have a similar name (ignore case)
IDataBaseItemEnumerator* pEnum = GetItemEnumerator();
for (IDataBaseItem* pItem = pEnum->GetFirst(); pItem != nullptr; pItem = pEnum->GetNext())
{
//Check if the item is in the target library first.
IDataBaseLibrary* itemLibrary = pItem->GetLibrary();
QString itemLibraryName;
if (itemLibrary)
{
itemLibraryName = itemLibrary->GetName();
}
// Item is not in the library so there cannot be a naming conflict.
if (!libName.isEmpty() && !itemLibraryName.isEmpty() && itemLibraryName != libName)
{
continue;
}
const QString& name = pItem->GetName();
if (name.startsWith(srcName, Qt::CaseInsensitive))
{
possibleDuplicates.push_back(AZStd::string(name.toUtf8().data()));
}
}
pEnum->Release();
if (possibleDuplicates.empty())
{
return srcName;
}
std::sort(possibleDuplicates.begin(), possibleDuplicates.end(), [](const AZStd::string& strOne, const AZStd::string& strTwo)
{
// I can assume size sorting since if the length is different, either one of the two strings doesn't
// closely match the string we are trying to duplicate, or it's a bigger number (X1 vs X10)
if (strOne.size() != strTwo.size())
{
return strOne.size() < strTwo.size();
}
else
{
return azstricmp(strOne.c_str(), strTwo.c_str()) < 0;
}
}
);
int num = 0;
QString returnValue = srcName;
while (num < possibleDuplicates.size() && QString::compare(possibleDuplicates[num].c_str(), returnValue, Qt::CaseInsensitive) == 0)
{
returnValue = QStringLiteral("%1%2%3").arg(srcName).arg("_").arg(num);
++num;
}
return returnValue;
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::Validate()
{
IDataBaseItemEnumerator* pEnum = GetItemEnumerator();
for (IDataBaseItem* pItem = pEnum->GetFirst(); pItem != nullptr; pItem = pEnum->GetNext())
{
pItem->Validate();
}
pEnum->Release();
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::RegisterItem(CBaseLibraryItem* pItem, REFGUID newGuid)
{
assert(pItem);
bool bNotify = false;
if (m_bUniqGuidMap)
{
REFGUID oldGuid = pItem->GetGUID();
if (!GuidUtil::IsEmpty(oldGuid))
{
m_itemsGuidMap.erase(oldGuid);
}
if (GuidUtil::IsEmpty(newGuid))
{
return;
}
CBaseLibraryItem* pOldItem = stl::find_in_map(m_itemsGuidMap, newGuid, nullptr);
if (!pOldItem)
{
pItem->m_guid = newGuid;
m_itemsGuidMap[newGuid] = pItem;
pItem->m_bRegistered = true;
bNotify = true;
}
else
{
if (pOldItem != pItem)
{
ReportDuplicateItem(pItem, pOldItem);
}
}
}
if (m_bUniqNameMap)
{
QString fullName = pItem->GetFullName();
if (!pItem->GetName().isEmpty())
{
CBaseLibraryItem* pOldItem = static_cast<CBaseLibraryItem*>(FindItemByName(fullName));
if (!pOldItem)
{
AZStd::lock_guard<AZStd::mutex> lock(m_itemsNameMapMutex);
m_itemsNameMap[fullName] = pItem;
pItem->m_bRegistered = true;
bNotify = true;
}
else
{
if (pOldItem != pItem)
{
ReportDuplicateItem(pItem, pOldItem);
}
}
}
}
// Notify listeners.
if (bNotify)
{
NotifyItemEvent(pItem, EDB_ITEM_EVENT_ADD);
}
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::RegisterItem(CBaseLibraryItem* pItem)
{
assert(pItem);
bool bNotify = false;
if (m_bUniqGuidMap)
{
if (GuidUtil::IsEmpty(pItem->GetGUID()))
{
return;
}
CBaseLibraryItem* pOldItem = stl::find_in_map(m_itemsGuidMap, pItem->GetGUID(), nullptr);
if (!pOldItem)
{
m_itemsGuidMap[pItem->GetGUID()] = pItem;
pItem->m_bRegistered = true;
bNotify = true;
}
else
{
if (pOldItem != pItem)
{
ReportDuplicateItem(pItem, pOldItem);
}
}
}
if (m_bUniqNameMap)
{
QString fullName = pItem->GetFullName();
if (!fullName.isEmpty())
{
CBaseLibraryItem* pOldItem = static_cast<CBaseLibraryItem*>(FindItemByName(fullName));
if (!pOldItem)
{
AZStd::lock_guard<AZStd::mutex> lock(m_itemsNameMapMutex);
m_itemsNameMap[fullName] = pItem;
pItem->m_bRegistered = true;
bNotify = true;
}
else
{
if (pOldItem != pItem)
{
ReportDuplicateItem(pItem, pOldItem);
}
}
}
}
// Notify listeners.
if (bNotify)
{
NotifyItemEvent(pItem, EDB_ITEM_EVENT_ADD);
}
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::SetRegisteredFlag(CBaseLibraryItem* pItem, bool bFlag)
{
pItem->m_bRegistered = bFlag;
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::ReportDuplicateItem(CBaseLibraryItem* pItem, CBaseLibraryItem* pOldItem)
{
QString sLibName;
if (pOldItem->GetLibrary())
{
sLibName = pOldItem->GetLibrary()->GetName();
}
CErrorRecord err;
err.pItem = pItem;
err.error = QStringLiteral("Item %1 with duplicate GUID to loaded item %2 ignored").arg(pItem->GetFullName(), pOldItem->GetFullName());
GetIEditor()->GetErrorReport()->ReportError(err);
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::UnregisterItem(CBaseLibraryItem* pItem)
{
// Notify listeners.
NotifyItemEvent(pItem, EDB_ITEM_EVENT_DELETE);
if (!pItem)
{
return;
}
if (m_bUniqGuidMap)
{
m_itemsGuidMap.erase(pItem->GetGUID());
}
if (m_bUniqNameMap && !pItem->GetFullName().isEmpty())
{
AZStd::lock_guard<AZStd::mutex> lock(m_itemsNameMapMutex);
auto findIter = m_itemsNameMap.find(pItem->GetFullName());
if (findIter != m_itemsNameMap.end())
{
_smart_ptr<CBaseLibraryItem> item = findIter->second;
m_itemsNameMap.erase(findIter);
}
}
pItem->m_bRegistered = false;
}
//////////////////////////////////////////////////////////////////////////
QString CBaseLibraryManager::MakeFullItemName(IDataBaseLibrary* pLibrary, const QString& group, const QString& itemName)
{
assert(pLibrary);
QString name = pLibrary->GetName() + ".";
if (!group.isEmpty())
{
name += group + ".";
}
name += itemName;
return name;
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::GatherUsedResources(CUsedResources& resources)
{
IDataBaseItemEnumerator* pEnum = GetItemEnumerator();
for (IDataBaseItem* pItem = pEnum->GetFirst(); pItem != nullptr; pItem = pEnum->GetNext())
{
pItem->GatherUsedResources(resources);
}
pEnum->Release();
}
//////////////////////////////////////////////////////////////////////////
IDataBaseItemEnumerator* CBaseLibraryManager::GetItemEnumerator()
{
if (m_bUniqNameMap)
{
return new CDataBaseItemEnumerator<ItemsNameMap>(&m_itemsNameMap);
}
else
{
return new CDataBaseItemEnumerator<ItemsGUIDMap>(&m_itemsGuidMap);
}
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::OnEditorNotifyEvent(EEditorNotifyEvent event)
{
switch (event)
{
case eNotify_OnBeginNewScene:
SetSelectedItem(nullptr);
ClearAll();
break;
case eNotify_OnBeginSceneOpen:
SetSelectedItem(nullptr);
ClearAll();
break;
case eNotify_OnCloseScene:
SetSelectedItem(nullptr);
ClearAll();
break;
}
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::OnRenameItem(CBaseLibraryItem* pItem, const QString& oldName)
{
m_itemsNameMapMutex.lock();
if (!oldName.isEmpty())
{
m_itemsNameMap.erase(oldName);
}
if (!pItem->GetFullName().isEmpty())
{
m_itemsNameMap[pItem->GetFullName()] = pItem;
}
m_itemsNameMapMutex.unlock();
OnItemChanged(pItem);
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::AddListener(IDataBaseManagerListener* pListener)
{
stl::push_back_unique(m_listeners, pListener);
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::RemoveListener(IDataBaseManagerListener* pListener)
{
stl::find_and_erase(m_listeners, pListener);
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::NotifyItemEvent(IDataBaseItem* pItem, EDataBaseItemEvent event)
{
// Notify listeners.
if (!m_listeners.empty())
{
for (int i = 0; i < m_listeners.size(); i++)
{
m_listeners[i]->OnDataBaseItemEvent(pItem, event);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::OnItemChanged(IDataBaseItem* pItem)
{
NotifyItemEvent(pItem, EDB_ITEM_EVENT_CHANGED);
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::OnUpdateProperties(IDataBaseItem* pItem, bool bRefresh)
{
NotifyItemEvent(pItem, bRefresh ? EDB_ITEM_EVENT_UPDATE_PROPERTIES
: EDB_ITEM_EVENT_UPDATE_PROPERTIES_NO_EDITOR_REFRESH);
}
//////////////////////////////////////////////////////////////////////////
void CBaseLibraryManager::SetSelectedItem(IDataBaseItem* pItem)
{
if (m_pSelectedItem == pItem)
{
return;
}
m_pSelectedItem = (CBaseLibraryItem*)pItem;
NotifyItemEvent(m_pSelectedItem, EDB_ITEM_EVENT_SELECTED);
}
//////////////////////////////////////////////////////////////////////////
IDataBaseItem* CBaseLibraryManager::GetSelectedItem() const
{
return m_pSelectedItem;
}
//////////////////////////////////////////////////////////////////////////
IDataBaseItem* CBaseLibraryManager::GetSelectedParentItem() const
{
return m_pSelectedParent;
}
void CBaseLibraryManager::ChangeLibraryOrder(IDataBaseLibrary* lib, unsigned int newLocation)
{
if (!lib || newLocation >= m_libs.size() || lib == m_libs[newLocation])
{
return;
}
for (int i = 0; i < m_libs.size(); i++)
{
if (lib == m_libs[i])
{
_smart_ptr<CBaseLibrary> curLib = m_libs[i];
m_libs.erase(m_libs.begin() + i);
m_libs.insert(m_libs.begin() + newLocation, curLib);
return;
}
}
}
bool CBaseLibraryManager::SetLibraryName(CBaseLibrary* lib, const QString& name)
{
// SetFilename will validate if the name is duplicate with exist libraries.
if (lib->SetFilename(MakeFilename(name)))
{
lib->SetName(name);
return true;
}
return false;
}
-226
View File
@@ -1,226 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_BASELIBRARYMANAGER_H
#define CRYINCLUDE_EDITOR_BASELIBRARYMANAGER_H
#pragma once
#include "Include/IBaseLibraryManager.h"
#include "Include/IDataBaseItem.h"
#include "Include/IDataBaseLibrary.h"
#include "Include/IDataBaseManager.h"
#include "Util/TRefCountBase.h"
#include "Util/GuidUtil.h"
#include "BaseLibrary.h"
#include "Util/smartptr.h"
#include <EditorDefs.h>
#include <QtUtil.h>
AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
/** Manages all Libraries and Items.
*/
class SANDBOX_API CBaseLibraryManager
: public IBaseLibraryManager
{
AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
public:
CBaseLibraryManager();
~CBaseLibraryManager();
//! Clear all libraries.
void ClearAll() override;
//////////////////////////////////////////////////////////////////////////
// IDocListener implementation.
//////////////////////////////////////////////////////////////////////////
void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
//////////////////////////////////////////////////////////////////////////
// Library items.
//////////////////////////////////////////////////////////////////////////
//! Make a new item in specified library.
IDataBaseItem* CreateItem(IDataBaseLibrary* pLibrary) override;
//! Delete item from library and manager.
void DeleteItem(IDataBaseItem* pItem) override;
//! Find Item by its GUID.
IDataBaseItem* FindItem(REFGUID guid) const override;
IDataBaseItem* FindItemByName(const QString& fullItemName) override;
IDataBaseItem* LoadItemByName(const QString& fullItemName) override;
virtual IDataBaseItem* FindItemByName(const char* fullItemName);
virtual IDataBaseItem* LoadItemByName(const char* fullItemName);
IDataBaseItemEnumerator* GetItemEnumerator() override;
//////////////////////////////////////////////////////////////////////////
// Set item currently selected.
void SetSelectedItem(IDataBaseItem* pItem) override;
// Get currently selected item.
IDataBaseItem* GetSelectedItem() const override;
IDataBaseItem* GetSelectedParentItem() const override;
//////////////////////////////////////////////////////////////////////////
// Libraries.
//////////////////////////////////////////////////////////////////////////
//! Add Item library.
IDataBaseLibrary* AddLibrary(const QString& library, bool bIsLevelLibrary = false, bool bIsLoading = true) override;
void DeleteLibrary(const QString& library, bool forceDeleteLevel = false) override;
//! Get number of libraries.
int GetLibraryCount() const override { return static_cast<int>(m_libs.size()); };
//! Get number of modified libraries.
int GetModifiedLibraryCount() const override;
//! Get Item library by index.
IDataBaseLibrary* GetLibrary(int index) const override;
//! Get Level Item library.
IDataBaseLibrary* GetLevelLibrary() const override;
//! Find Items Library by name.
IDataBaseLibrary* FindLibrary(const QString& library) override;
//! Find Items Library's index by name.
int FindLibraryIndex(const QString& library) override;
//! Load Items library.
IDataBaseLibrary* LoadLibrary(const QString& filename, bool bReload = false) override;
//! Save all modified libraries.
void SaveAllLibs() override;
//! Serialize property manager.
void Serialize(XmlNodeRef& node, bool bLoading) override;
//! Export items to game.
void Export([[maybe_unused]] XmlNodeRef& node) override {};
//! Returns unique name base on input name.
QString MakeUniqueItemName(const QString& name, const QString& libName = "") override;
QString MakeFullItemName(IDataBaseLibrary* pLibrary, const QString& group, const QString& itemName) override;
//! Root node where this library will be saved.
QString GetRootNodeName() override = 0;
//! Path to libraries in this manager.
QString GetLibsPath() override = 0;
//////////////////////////////////////////////////////////////////////////
//! Validate library items for errors.
void Validate() override;
//////////////////////////////////////////////////////////////////////////
void GatherUsedResources(CUsedResources& resources) override;
void AddListener(IDataBaseManagerListener* pListener) override;
void RemoveListener(IDataBaseManagerListener* pListener) override;
//////////////////////////////////////////////////////////////////////////
void RegisterItem(CBaseLibraryItem* pItem, REFGUID newGuid) override;
void RegisterItem(CBaseLibraryItem* pItem) override;
void UnregisterItem(CBaseLibraryItem* pItem) override;
// Only Used internally.
void OnRenameItem(CBaseLibraryItem* pItem, const QString& oldName) override;
// Called by items to indicated that they have been modified.
// Sends item changed event to listeners.
void OnItemChanged(IDataBaseItem* pItem) override;
void OnUpdateProperties(IDataBaseItem* pItem, bool bRefresh) override;
QString MakeFilename(const QString& library);
bool IsUniqueFilename(const QString& library) override;
//CONFETTI BEGIN
// Used to change the library item order
void ChangeLibraryOrder(IDataBaseLibrary* lib, unsigned int newLocation) override;
bool SetLibraryName(CBaseLibrary* lib, const QString& name) override;
protected:
void SplitFullItemName(const QString& fullItemName, QString& libraryName, QString& itemName);
void NotifyItemEvent(IDataBaseItem* pItem, EDataBaseItemEvent event);
void SetRegisteredFlag(CBaseLibraryItem* pItem, bool bFlag);
//////////////////////////////////////////////////////////////////////////
// Must be overriden.
//! Makes a new Item.
virtual CBaseLibraryItem* MakeNewItem() = 0;
virtual CBaseLibrary* MakeNewLibrary() = 0;
//////////////////////////////////////////////////////////////////////////
virtual void ReportDuplicateItem(CBaseLibraryItem* pItem, CBaseLibraryItem* pOldItem);
protected:
bool m_bUniqGuidMap;
bool m_bUniqNameMap;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
//! Array of all loaded entity items libraries.
std::vector<_smart_ptr<CBaseLibrary> > m_libs;
// There is always one current level library.
TSmartPtr<CBaseLibrary> m_pLevelLibrary;
// GUID to item map.
typedef std::map<GUID, _smart_ptr<CBaseLibraryItem>, guid_less_predicate> ItemsGUIDMap;
ItemsGUIDMap m_itemsGuidMap;
// Case insensitive name to items map.
typedef std::map<QString, _smart_ptr<CBaseLibraryItem>, stl::less_stricmp<QString>> ItemsNameMap;
ItemsNameMap m_itemsNameMap;
AZStd::mutex m_itemsNameMapMutex;
std::vector<IDataBaseManagerListener*> m_listeners;
// Currently selected item.
_smart_ptr<CBaseLibraryItem> m_pSelectedItem;
_smart_ptr<CBaseLibraryItem> m_pSelectedParent;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
//////////////////////////////////////////////////////////////////////////
template <class TMap>
class CDataBaseItemEnumerator
: public IDataBaseItemEnumerator
{
TMap* m_pMap;
typename TMap::iterator m_iterator;
public:
CDataBaseItemEnumerator(TMap* pMap)
{
assert(pMap);
m_pMap = pMap;
m_iterator = m_pMap->begin();
}
void Release() override { delete this; };
IDataBaseItem* GetFirst() override
{
m_iterator = m_pMap->begin();
if (m_iterator == m_pMap->end())
{
return 0;
}
return m_iterator->second;
}
IDataBaseItem* GetNext() override
{
if (m_iterator != m_pMap->end())
{
m_iterator++;
}
if (m_iterator == m_pMap->end())
{
return 0;
}
return m_iterator->second;
}
};
#endif // CRYINCLUDE_EDITOR_BASELIBRARYMANAGER_H
+1 -1
View File
@@ -28,7 +28,7 @@ void CEditorPreferencesPage_AWS::Reflect(AZ::SerializeContext& serialize)
if (editContext)
{
editContext->Class<UsageOptions>("Options", "")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &UsageOptions::m_awsAttributionEnabled, "Allow O3DE to send information about your use of AWS Core Gem to AWS",
->DataElement(AZ::Edit::UIHandlers::CheckBox, &UsageOptions::m_awsAttributionEnabled, "Allow <a href=\"https://aws.amazon.com/privacy/\">O3DE</a> to send information about your use of AWS Core Gem to AWS",
"");
editContext->Class<CEditorPreferencesPage_AWS>("AWS Preferences", "AWS Preferences")
-1
View File
@@ -7,7 +7,6 @@
*/
#include "EditorDefs.h"
#include "ErrorRecorder.h"
#include "BaseLibraryItem.h"
#include "Include/IErrorReport.h"
+2
View File
@@ -14,6 +14,8 @@
#define CRYINCLUDE_EDITOR_CORE_ERRORRECORDER_H
#pragma once
#include "Include/EditorCoreAPI.h"
//////////////////////////////////////////////////////////////////////////
//! Automatic class to record and display error.
class EDITOR_CORE_API CErrorsRecorder
-29
View File
@@ -67,24 +67,6 @@ QString CErrorRecord::GetErrorText() const
{
str += QString("\t ");
}
if (pItem)
{
switch (pItem->GetType())
{
case EDB_TYPE_MATERIAL:
str += QString("\t Material=\"");
break;
case EDB_TYPE_PARTICLE:
str += QString("\t Particle=\"");
break;
case EDB_TYPE_MUSIC:
str += QString("\t Music=\"");
break;
default:
str += QString("\t Item=\"");
}
str += pItem->GetFullName() + "\"";
}
if (pObject)
{
str += QString("\t Object=\"") + pObject->GetName() + "\"";
@@ -101,7 +83,6 @@ CErrorReport::CErrorReport()
m_bImmediateMode = true;
m_bShowErrors = true;
m_pObject = nullptr;
m_pItem = nullptr;
m_pParticle = nullptr;
}
@@ -140,10 +121,6 @@ void CErrorReport::ReportError(CErrorRecord& err)
{
err.pObject = m_pObject;
}
else if (err.pItem == nullptr && m_pItem != nullptr)
{
err.pItem = m_pItem;
}
m_errors.push_back(err);
}
bNoRecurse = false;
@@ -255,12 +232,6 @@ void CErrorReport::SetCurrentValidatorObject(CBaseObject* pObject)
m_pObject = pObject;
}
//////////////////////////////////////////////////////////////////////////
void CErrorReport::SetCurrentValidatorItem(CBaseLibraryItem* pItem)
{
m_pItem = pItem;
}
//////////////////////////////////////////////////////////////////////////
void CErrorReport::SetCurrentFile(const QString& file)
{
+5 -9
View File
@@ -17,8 +17,11 @@
// forward declarations.
class CParticleItem;
#include "BaseLibraryItem.h"
#include <CryCommon/IValidator.h>
#include <CryCommon/smartptr.h>
#include "Objects/BaseObject.h"
#include "Include/EditorCoreAPI.h"
#include "Include/IErrorReport.h"
#include "ErrorRecorder.h"
@@ -56,16 +59,13 @@ public:
int count;
//! Object that caused this error.
_smart_ptr<CBaseObject> pObject;
//! Library Item that caused this error.
_smart_ptr<CBaseLibraryItem> pItem;
int flags;
CErrorRecord(CBaseObject* object, ESeverity _severity, const QString& _error, int _flags = 0, int _count = 0,
CBaseLibraryItem* item = 0, EValidatorModule _module = VALIDATOR_MODULE_EDITOR)
EValidatorModule _module = VALIDATOR_MODULE_EDITOR)
: severity(_severity)
, module(_module)
, pObject(object)
, pItem(item)
, flags(_flags)
, count(_count)
, error(_error)
@@ -77,7 +77,6 @@ public:
severity = ESEVERITY_WARNING;
module = VALIDATOR_MODULE_EDITOR;
pObject = 0;
pItem = 0;
flags = 0;
count = 0;
}
@@ -116,8 +115,6 @@ public:
//! Assign current Object to which new reported warnings are assigned.
void SetCurrentValidatorObject(CBaseObject* pObject);
//! Assign current Item to which new reported warnings are assigned.
void SetCurrentValidatorItem(CBaseLibraryItem* pItem);
//! Assign current filename.
void SetCurrentFile(const QString& file);
@@ -127,7 +124,6 @@ private:
bool m_bImmediateMode;
bool m_bShowErrors;
_smart_ptr<CBaseObject> m_pObject;
_smart_ptr<CBaseLibraryItem> m_pItem;
CParticleItem* m_pParticle;
QString m_currentFilename;
};
-4
View File
@@ -362,10 +362,6 @@ void CErrorReportDialog::CopyToClipboard()
{
str += QString::fromLatin1(" [Object: %1]").arg(pRecord->pObject->GetName());
}
if (pRecord->pItem)
{
str += QString::fromLatin1(" [Material: %1]").arg(pRecord->pItem->GetName());
}
str += QString::fromLatin1("\r\n");
}
}
+1 -5
View File
@@ -149,11 +149,7 @@ QVariant CErrorReportTableModel::data(const CErrorRecord& record, int column, in
case ColumnFile:
return record.file;
case ColumnObject:
if (record.pItem)
{
return record.pItem->GetFullName();
}
else if (record.pObject)
if (record.pObject)
{
return record.pObject->GetName();
}
-9
View File
@@ -44,7 +44,6 @@ class CMusicManager;
struct IEditorParticleManager;
class CEAXPresetManager;
class CErrorReport;
class CBaseLibraryItem;
class ICommandManager;
class CEditorCommandManager;
class CHyperGraphManager;
@@ -52,9 +51,7 @@ class CConsoleSynchronization;
class CUIEnumsDatabase;
struct ISourceControl;
struct IEditorClassFactory;
struct IDataBaseItem;
struct ITransformManipulator;
struct IDataBaseManager;
class IFacialEditor;
class CDialog;
#if defined(AZ_PLATFORM_WINDOWS)
@@ -82,8 +79,6 @@ struct IEventLoopHook;
struct IErrorReport; // Vladimir@conffx
struct IFileUtil; // Vladimir@conffx
struct IEditorLog; // Vladimir@conffx
struct IEditorMaterialManager; // Vladimir@conffx
struct IBaseLibraryManager; // Vladimir@conffx
struct IImageUtil; // Vladimir@conffx
struct IEditorParticleUtils; // Leroy@conffx
struct ILogFile; // Vladimir@conffx
@@ -519,10 +514,6 @@ struct IEditor
//! Get access to object manager.
virtual struct IObjectManager* GetObjectManager() = 0;
virtual CSettingsManager* GetSettingsManager() = 0;
//! Get DB manager that own items of specified type.
virtual IDataBaseManager* GetDBItemManager(EDataBaseItemType itemType) = 0;
virtual IBaseLibraryManager* GetMaterialManagerLibrary() = 0; // Vladimir@conffx
virtual IEditorMaterialManager* GetIEditorMaterialManager() = 0; // Vladimir@Conffx
//! Returns IconManager.
virtual IIconManager* GetIconManager() = 0;
//! Get Music Manager.
-17
View File
@@ -892,11 +892,6 @@ void CEditorImpl::CloseView(const GUID& classId)
}
}
IDataBaseManager* CEditorImpl::GetDBItemManager([[maybe_unused]] EDataBaseItemType itemType)
{
return nullptr;
}
bool CEditorImpl::SelectColor(QColor& color, QWidget* parent)
{
const AZ::Color c = AzQtComponents::fromQColor(color);
@@ -1624,18 +1619,6 @@ SEditorSettings* CEditorImpl::GetEditorSettings()
return &gSettings;
}
// Vladimir@Conffx
IBaseLibraryManager* CEditorImpl::GetMaterialManagerLibrary()
{
return nullptr;
}
// Vladimir@Conffx
IEditorMaterialManager* CEditorImpl::GetIEditorMaterialManager()
{
return nullptr;
}
IImageUtil* CEditorImpl::GetImageUtil()
{
return m_pImageUtil;
-3
View File
@@ -157,7 +157,6 @@ public:
void LockSelection(bool bLock) override;
bool IsSelectionLocked() override;
IDataBaseManager* GetDBItemManager(EDataBaseItemType itemType) override;
CMusicManager* GetMusicManager() override { return m_pMusicManager; };
IEditorFileMonitor* GetFileMonitor() override;
@@ -294,8 +293,6 @@ public:
void RegisterObjectContextMenuExtension(TContextMenuExtensionFunc func) override;
SSystemGlobalEnvironment* GetEnv() override;
IBaseLibraryManager* GetMaterialManagerLibrary() override; // Vladimir@Conffx
IEditorMaterialManager* GetIEditorMaterialManager() override; // Vladimir@Conffx
IImageUtil* GetImageUtil() override; // Vladimir@conffx
SEditorSettings* GetEditorSettings() override;
ILogFile* GetLogFile() override { return m_pLogFile; }
-143
View File
@@ -1,143 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_INCLUDE_IBASELIBRARYMANAGER_H
#define CRYINCLUDE_EDITOR_INCLUDE_IBASELIBRARYMANAGER_H
#pragma once
#include <IEditor.h>
#include "Include/IDataBaseItem.h"
#include "Include/IDataBaseLibrary.h"
#include "Include/IDataBaseManager.h"
#include "Util/TRefCountBase.h"
class CBaseLibraryItem;
class CBaseLibrary;
struct IBaseLibraryManager
: public TRefCountBase<IDataBaseManager>
, public IEditorNotifyListener
{
//! Clear all libraries.
virtual void ClearAll() = 0;
//////////////////////////////////////////////////////////////////////////
// IDocListener implementation.
//////////////////////////////////////////////////////////////////////////
virtual void OnEditorNotifyEvent(EEditorNotifyEvent event) = 0;
//////////////////////////////////////////////////////////////////////////
// Library items.
//////////////////////////////////////////////////////////////////////////
//! Make a new item in specified library.
virtual IDataBaseItem* CreateItem(IDataBaseLibrary* pLibrary) = 0;
//! Delete item from library and manager.
virtual void DeleteItem(IDataBaseItem* pItem) = 0;
//! Find Item by its GUID.
virtual IDataBaseItem* FindItem(REFGUID guid) const = 0;
virtual IDataBaseItem* FindItemByName(const QString& fullItemName) = 0;
virtual IDataBaseItem* LoadItemByName(const QString& fullItemName) = 0;
virtual IDataBaseItemEnumerator* GetItemEnumerator() = 0;
//////////////////////////////////////////////////////////////////////////
// Set item currently selected.
virtual void SetSelectedItem(IDataBaseItem* pItem) = 0;
// Get currently selected item.
virtual IDataBaseItem* GetSelectedItem() const = 0;
virtual IDataBaseItem* GetSelectedParentItem() const = 0;
//////////////////////////////////////////////////////////////////////////
// Libraries.
//////////////////////////////////////////////////////////////////////////
//! Add Item library.
virtual IDataBaseLibrary* AddLibrary(const QString& library, bool isLevelLibrary = false, bool bIsLoading = true) = 0;
virtual void DeleteLibrary(const QString& library, bool forceDeleteLevel = false) = 0;
//! Get number of libraries.
virtual int GetLibraryCount() const = 0;
//! Get number of modified libraries.
virtual int GetModifiedLibraryCount() const = 0;
//! Get Item library by index.
virtual IDataBaseLibrary* GetLibrary(int index) const = 0;
//! Get Level Item library.
virtual IDataBaseLibrary* GetLevelLibrary() const = 0;
//! Find Items Library by name.
virtual IDataBaseLibrary* FindLibrary(const QString& library) = 0;
//! Find the Library's index by name.
virtual int FindLibraryIndex(const QString& library) = 0;
//! Load Items library.
#ifdef LoadLibrary
#undef LoadLibrary
#endif
virtual IDataBaseLibrary* LoadLibrary(const QString& filename, bool bReload = false) = 0;
//! Save all modified libraries.
virtual void SaveAllLibs() = 0;
//! Serialize property manager.
virtual void Serialize(XmlNodeRef& node, bool bLoading) = 0;
//! Export items to game.
virtual void Export(XmlNodeRef& node) = 0;
//! Returns unique name base on input name.
// Vera@conffx, add LibName parameter so we could make an unique name depends on input library.
// Arguments:
// - name: name of the item
// - libName: The library of the item. Given the library name, the function will return a unique name in the library
// Default value "": The function will ignore the library name and return a unique name in the manager
virtual QString MakeUniqueItemName(const QString& name, const QString& libName = "") = 0;
virtual QString MakeFullItemName(IDataBaseLibrary* pLibrary, const QString& group, const QString& itemName) = 0;
//! Root node where this library will be saved.
virtual QString GetRootNodeName() = 0;
//! Path to libraries in this manager.
virtual QString GetLibsPath() = 0;
//////////////////////////////////////////////////////////////////////////
//! Validate library items for errors.
virtual void Validate() = 0;
//////////////////////////////////////////////////////////////////////////
virtual void GatherUsedResources(CUsedResources& resources) = 0;
virtual void AddListener(IDataBaseManagerListener* pListener) = 0;
virtual void RemoveListener(IDataBaseManagerListener* pListener) = 0;
//////////////////////////////////////////////////////////////////////////
virtual void RegisterItem(CBaseLibraryItem* pItem, REFGUID newGuid) = 0;
virtual void RegisterItem(CBaseLibraryItem* pItem) = 0;
virtual void UnregisterItem(CBaseLibraryItem* pItem) = 0;
// Only Used internally.
virtual void OnRenameItem(CBaseLibraryItem* pItem, const QString& oldName) = 0;
// Called by items to indicated that they have been modified.
// Sends item changed event to listeners.
virtual void OnItemChanged(IDataBaseItem* pItem) = 0;
virtual void OnUpdateProperties(IDataBaseItem* pItem, bool bRefresh) = 0;
//CONFETTI BEGIN
// Used to change the library item order
virtual void ChangeLibraryOrder(IDataBaseLibrary* lib, unsigned int newLocation) = 0;
// simplifies the library renaming process
virtual bool SetLibraryName(CBaseLibrary* lib, const QString& name) = 0;
//Check if the file name is unique.
//Params: library: library name. NOT the file path.
virtual bool IsUniqueFilename(const QString& library) = 0;
//CONFETTI END
};
#endif // CRYINCLUDE_EDITOR_INCLUDE_IBASELIBRARYMANAGER_H
-92
View File
@@ -1,92 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_INCLUDE_IDATABASEITEM_H
#define CRYINCLUDE_EDITOR_INCLUDE_IDATABASEITEM_H
#pragma once
#include <qwindowdefs.h>
#include <IEditor.h>
struct IDataBaseLibrary;
class CUsedResources;
//////////////////////////////////////////////////////////////////////////
/** Base class for all items contained in BaseLibraray.
*/
struct IDataBaseItem
{
struct SerializeContext
{
XmlNodeRef node;
bool bUndo;
bool bLoading;
bool bCopyPaste;
bool bIgnoreChilds;
bool bUniqName;
SerializeContext()
: node(0)
, bLoading(false)
, bCopyPaste(false)
, bIgnoreChilds(false)
, bUniqName(false)
, bUndo(false) {};
SerializeContext(XmlNodeRef _node, bool bLoad)
: node(_node)
, bLoading(bLoad)
, bCopyPaste(false)
, bIgnoreChilds(false)
, bUniqName(false)
, bUndo(false) {};
SerializeContext(const SerializeContext& ctx)
: node(ctx.node)
, bLoading(ctx.bLoading)
, bCopyPaste(ctx.bCopyPaste)
, bIgnoreChilds(ctx.bIgnoreChilds)
, bUniqName(ctx.bUniqName)
, bUndo(ctx.bUndo) {};
};
virtual EDataBaseItemType GetType() const = 0;
//! Return Library this item are contained in.
//! Item can only be at one library.
virtual IDataBaseLibrary* GetLibrary() const = 0;
//! Change item name.
virtual void SetName(const QString& name) = 0;
//! Get item name.
virtual const QString& GetName() const = 0;
//! Get full item name, including name of library.
//! Name formed by adding dot after name of library
//! eg. library Pickup and item PickupRL form full item name: "Pickups.PickupRL".
virtual QString GetFullName() const = 0;
//! Get only nameof group from prototype.
virtual QString GetGroupName() = 0;
//! Get short name of prototype without group.
virtual QString GetShortName() = 0;
//! Serialize library item to archive.
virtual void Serialize(SerializeContext& ctx) = 0;
//! Generate new unique id for this item.
virtual void GenerateId() = 0;
//! Returns GUID of this material.
virtual const GUID& GetGUID() const = 0;
//! Validate item for errors.
virtual void Validate() {};
//! Gathers resources by this item.
virtual void GatherUsedResources([[maybe_unused]] CUsedResources& resources) {};
};
#endif // CRYINCLUDE_EDITOR_INCLUDE_IDATABASEITEM_H
-118
View File
@@ -1,118 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_INCLUDE_IDATABASELIBRARY_H
#define CRYINCLUDE_EDITOR_INCLUDE_IDATABASELIBRARY_H
#pragma once
struct IDataBaseManager;
struct IDataBaseItem;
class QString;
class XmlNodeRef;
//////////////////////////////////////////////////////////////////////////
// Description:
// Interface to access specific library of editor data base.
// Ex. Archetype library, Material Library.
// See Also:
// IDataBaseItem,IDataBaseManager
//////////////////////////////////////////////////////////////////////////
struct IDataBaseLibrary
{
// Description:
// Return IDataBaseManager interface to the manager for items stored in this library.
virtual IDataBaseManager* GetManager() = 0;
// Description:
// Return library name.
virtual const QString& GetName() const = 0;
// Description:
// Return filename where this library is stored.
virtual const QString& GetFilename() const = 0;
// Description:
// Save contents of library to file.
virtual bool Save() = 0;
// Description:
// Load library from file.
// Arguments:
// filename - Full specified library filename (relative to root game folder).
virtual bool Load(const QString& filename) = 0;
// Description:
// Serialize library parameters and items to/from XML node.
virtual void Serialize(XmlNodeRef& node, bool bLoading) = 0;
// Description:
// Marks library as modified, indicates that some item in library was modified.
virtual void SetModified(bool bModified = true) = 0;
// Description:
// Check if library parameters or any items where modified.
// If any item was modified library may need saving before closing editor.
virtual bool IsModified() const = 0;
// Description:
// Check if this library is not shared and internal to current level.
virtual bool IsLevelLibrary() const = 0;
// Description:
// Make this library accessible only from current Level. (not shared)
virtual void SetLevelLibrary(bool bEnable) = 0;
// Description:
// Associate a new item with the library.
// Watch out if item was already in another library.
virtual void AddItem(IDataBaseItem* pItem, bool bRegister = true) = 0;
// Description:
// Return number of items in library.
virtual int GetItemCount() const = 0;
// Description:
// Get item by index.
// See Also:
// GetItemCount
// Arguments:
// index - Index from 0 to GetItemCount()
virtual IDataBaseItem* GetItem(int index) = 0;
// Description:
// Remove item from library, does not destroy item,
// only unliks it from this library, to delete item use IDataBaseManager.
// See Also:
// AddItem
virtual void RemoveItem(IDataBaseItem* item) = 0;
// Description:
// Remove all items from library, does not destroy items,
// only unliks them from this library, to delete item use IDataBaseManager.
// See Also:
// RemoveItem,AddItem
virtual void RemoveAllItems() = 0;
// Description:
// Find item in library by name.
// This function usually uses linear search so it is not particularry fast.
// See Also:
// GetItem
virtual IDataBaseItem* FindItem(const QString& name) = 0;
//CONFETTI BEGIN
// Used to change the library item order
virtual void ChangeItemOrder(CBaseLibraryItem* item, unsigned int newLocation) = 0;
//CONFETTI END
};
#endif // CRYINCLUDE_EDITOR_INCLUDE_IDATABASELIBRARY_H
-134
View File
@@ -1,134 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_INCLUDE_IDATABASEMANAGER_H
#define CRYINCLUDE_EDITOR_INCLUDE_IDATABASEMANAGER_H
#pragma once
#include <QString>
struct IDataBaseItem;
struct IDataBaseLibrary;
class CUsedResources;
enum EDataBaseItemEvent
{
EDB_ITEM_EVENT_ADD,
EDB_ITEM_EVENT_DELETE,
EDB_ITEM_EVENT_CHANGED,
EDB_ITEM_EVENT_SELECTED,
EDB_ITEM_EVENT_UPDATE_PROPERTIES,
EDB_ITEM_EVENT_UPDATE_PROPERTIES_NO_EDITOR_REFRESH
};
//////////////////////////////////////////////////////////////////////////
// Description:
// Callback class to intercept item creation and deletion events.
//////////////////////////////////////////////////////////////////////////
struct IDataBaseManagerListener
{
virtual void OnDataBaseItemEvent(IDataBaseItem* pItem, EDataBaseItemEvent event) = 0;
};
//////////////////////////////////////////////////////////////////////////
// Description:
// his interface is used to enumerate al items registered to the database manager.
//////////////////////////////////////////////////////////////////////////
struct IDataBaseItemEnumerator
{
virtual ~IDataBaseItemEnumerator() = default;
virtual void Release() = 0;
virtual IDataBaseItem* GetFirst() = 0;
virtual IDataBaseItem* GetNext() = 0;
};
//////////////////////////////////////////////////////////////////////////
//
// Interface to the collection of all items or specific type
// in data base libraries.
//
//////////////////////////////////////////////////////////////////////////
struct IDataBaseManager
{
//! Clear all libraries.
virtual void ClearAll() = 0;
//////////////////////////////////////////////////////////////////////////
// Library items.
//////////////////////////////////////////////////////////////////////////
//! Make a new item in specified library.
virtual IDataBaseItem* CreateItem(IDataBaseLibrary* pLibrary) = 0;
//! Delete item from library and manager.
virtual void DeleteItem(IDataBaseItem* pItem) = 0;
//! Find Item by its GUID.
virtual IDataBaseItem* FindItem(REFGUID guid) const = 0;
virtual IDataBaseItem* FindItemByName(const QString& fullItemName) = 0;
virtual IDataBaseItemEnumerator* GetItemEnumerator() = 0;
// Select one item in DB.
virtual void SetSelectedItem(IDataBaseItem* pItem) = 0;
//////////////////////////////////////////////////////////////////////////
// Libraries.
//////////////////////////////////////////////////////////////////////////
//! Add Item library. Set isLevelLibrary to true if its the "level" library which gets saved inside the level
virtual IDataBaseLibrary* AddLibrary(const QString& library, bool isLevelLibrary = false, bool bIsLoading = true) = 0;
virtual void DeleteLibrary(const QString& library, bool forceDeleteLibrary = false) = 0;
//! Get number of libraries.
virtual int GetLibraryCount() const = 0;
//! Get Item library by index.
virtual IDataBaseLibrary* GetLibrary(int index) const = 0;
//! Find Items Library by name.
virtual IDataBaseLibrary* FindLibrary(const QString& library) = 0;
//! Load Items library.
#ifdef LoadLibrary
#undef LoadLibrary
#endif
virtual IDataBaseLibrary* LoadLibrary(const QString& filename, bool bReload = false) = 0;
//! Save all modified libraries.
virtual void SaveAllLibs() = 0;
//! Serialize property manager.
virtual void Serialize(XmlNodeRef& node, bool bLoading) = 0;
//! Export items to game.
virtual void Export([[maybe_unused]] XmlNodeRef& node) {};
//! Returns unique name base on input name.
virtual QString MakeUniqueItemName(const QString& name, const QString& libName = "") = 0;
virtual QString MakeFullItemName(IDataBaseLibrary* pLibrary, const QString& group, const QString& itemName) = 0;
//! Root node where this library will be saved.
virtual QString GetRootNodeName() = 0;
//! Path to libraries in this manager.
virtual QString GetLibsPath() = 0;
//////////////////////////////////////////////////////////////////////////
//! Validate library items for errors.
virtual void Validate() = 0;
// Description:
// Collects names of all resource files used by managed items.
// Arguments:
// resources - Structure where all filenames are collected.
virtual void GatherUsedResources(CUsedResources& resources) = 0;
//////////////////////////////////////////////////////////////////////////
// Register listeners.
virtual void AddListener(IDataBaseManagerListener* pListener) = 0;
virtual void RemoveListener(IDataBaseManagerListener* pListener) = 0;
};
#endif // CRYINCLUDE_EDITOR_INCLUDE_IDATABASEMANAGER_H
-20
View File
@@ -1,20 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include "BaseLibraryItem.h"
#include <IMaterial.h>
struct IEditorMaterial
: public CBaseLibraryItem
{
virtual int GetFlags() const = 0;
virtual IMaterial* GetMatInfo(bool bUseExistingEngineMaterial = false) = 0;
virtual void DisableHighlightForFrame() = 0;
};
@@ -1,21 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef CRYINCLUDE_EDITOR_MATERIAL_IEDITORMATERIALMANAGER_H
#define CRYINCLUDE_EDITOR_MATERIAL_IEDITORMATERIALMANAGER_H
#pragma once
#include <Include/IBaseLibraryManager.h>
#include <IMaterial.h>
struct IEditorMaterialManager
{
virtual void GotoMaterial(IMaterial* pMaterial) = 0;
};
#endif // CRYINCLUDE_EDITOR_MATERIAL_MATERIALMANAGER_H
-4
View File
@@ -14,7 +14,6 @@
// forward declarations.
class CParticleItem;
class CBaseObject;
class CBaseLibraryItem;
class CErrorRecord;
class QString;
@@ -52,9 +51,6 @@ struct IErrorReport
//! Assign current Object to which new reported warnings are assigned.
virtual void SetCurrentValidatorObject(CBaseObject* pObject) = 0;
//! Assign current Item to which new reported warnings are assigned.
virtual void SetCurrentValidatorItem(CBaseLibraryItem* pItem) = 0;
//! Assign current filename.
virtual void SetCurrentFile(const QString& file) = 0;
};
-3
View File
@@ -85,9 +85,6 @@ public:
MOCK_METHOD0(IsSelectionLocked, bool());
MOCK_METHOD0(GetObjectManager, struct IObjectManager* ());
MOCK_METHOD0(GetSettingsManager, CSettingsManager* ());
MOCK_METHOD1(GetDBItemManager, IDataBaseManager* (EDataBaseItemType));
MOCK_METHOD0(GetMaterialManagerLibrary, IBaseLibraryManager* ());
MOCK_METHOD0(GetIEditorMaterialManager, IEditorMaterialManager* ());
MOCK_METHOD0(GetIconManager, IIconManager* ());
MOCK_METHOD0(GetMusicManager, CMusicManager* ());
MOCK_METHOD2(GetTerrainElevation, float(float , float ));
+1
View File
@@ -27,6 +27,7 @@
#define CLASS_ENVIRONMENT_LIGHT "EnvironmentLight"
class CEntityObject;
class CSelectionGroup;
class QMenu;
/*!
+2
View File
@@ -13,6 +13,8 @@
#include "ErrorReport.h"
#include <AzCore/std/containers/set.h>
#include <CryCommon/IXml.h>
class CErrorRecord;
struct IObjectManager;
@@ -11,6 +11,7 @@
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWSEQUENCE_H
#pragma once
#include <IEditor.h>
#include "IMovieSystem.h"
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
@@ -408,20 +408,6 @@ void CTrackViewSequenceManager::OnSequenceRemoved(CTrackViewSequence* sequence)
}
}
////////////////////////////////////////////////////////////////////////////
void CTrackViewSequenceManager::OnDataBaseItemEvent([[maybe_unused]] IDataBaseItem* pItem, EDataBaseItemEvent event)
{
if (event != EDataBaseItemEvent::EDB_ITEM_EVENT_ADD)
{
const size_t numSequences = m_sequences.size();
for (size_t i = 0; i < numSequences; ++i)
{
m_sequences[i]->UpdateDynamicParams();
}
}
}
////////////////////////////////////////////////////////////////////////////
CTrackViewAnimNodeBundle CTrackViewSequenceManager::GetAllRelatedAnimNodes(const AZ::EntityId entityId) const
{
@@ -13,13 +13,11 @@
#include "TrackViewSequence.h"
#include "IDataBaseManager.h"
#include <AzCore/Component/EntityBus.h>
class CTrackViewSequenceManager
: public IEditorNotifyListener
, public IDataBaseManagerListener
, public ITrackViewSequenceManager
, public AZ::EntitySystemBus::Handler
{
@@ -65,8 +63,6 @@ private:
void OnSequenceAdded(CTrackViewSequence* pSequence);
void OnSequenceRemoved(CTrackViewSequence* pSequence);
void OnDataBaseItemEvent(IDataBaseItem* pItem, EDataBaseItemEvent event) override;
// AZ::EntitySystemBus
void OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name) override;
void OnEntityDestruction(const AZ::EntityId& entityId) override;
-3
View File
@@ -46,7 +46,6 @@ struct HitContext;
struct IRenderListener;
class CImageEx;
class QMenu;
struct IDataBaseItem;
/** Type of viewport.
*/
@@ -230,8 +229,6 @@ public:
// Drag and drop support on viewports.
// To be overrided in derived classes.
//////////////////////////////////////////////////////////////////////////
virtual bool CanDrop([[maybe_unused]] const QPoint& point, [[maybe_unused]] IDataBaseItem* pItem) { return false; };
virtual void Drop([[maybe_unused]] const QPoint& point, [[maybe_unused]] IDataBaseItem* pItem) {};
virtual void SetGlobalDropCallback(DropCallback dropCallback, void* dropCallbackCustom)
{
m_dropCallback = dropCallback;
-7
View File
@@ -7,17 +7,12 @@
#
set(FILES
BaseLibrary.h
BaseLibraryItem.h
UsedResources.h
UIEnumsDatabase.h
Include/EditorCoreAPI.cpp
Include/IErrorReport.h
Include/IBaseLibraryManager.h
Include/IFileUtil.h
Include/EditorCoreAPI.h
Include/IEditorMaterial.h
Include/IEditorMaterialManager.h
Include/IImageUtil.h
Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.qrc
Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp
@@ -35,8 +30,6 @@ set(FILES
Controls/QBitmapPreviewDialogImp.h
Controls/QToolTipWidget.h
Controls/QToolTipWidget.cpp
BaseLibraryItem.cpp
BaseLibrary.cpp
UsedResources.cpp
UIEnumsDatabase.cpp
LyViewPaneNames.h
-6
View File
@@ -271,9 +271,6 @@ set(FILES
Include/HitContext.h
Include/ICommandManager.h
Include/IConsoleConnectivity.h
Include/IDataBaseItem.h
Include/IDataBaseLibrary.h
Include/IDataBaseManager.h
Include/IDisplayViewport.h
Include/IEditorClassFactory.h
Include/IEventLoopHook.h
@@ -369,9 +366,6 @@ set(FILES
ActionManager.h
ShortcutDispatcher.cpp
ShortcutDispatcher.h
BaseLibraryManager.cpp
BaseLibraryItem.h
BaseLibraryManager.h
CheckOutDialog.cpp
CheckOutDialog.h
CheckOutDialog.ui
@@ -10,6 +10,7 @@
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/TypeSafeIntegral.h>
#include <AzCore/std/functional.h>
#include <AzFramework/Spawnable/Spawnable.h>
@@ -164,6 +165,8 @@ namespace AzFramework
public:
friend class SpawnableEntitiesDefinition;
AZ_CLASS_ALLOCATOR(AzFramework::EntitySpawnTicket, AZ::SystemAllocator, 0);
using Id = uint32_t;
EntitySpawnTicket() = default;
@@ -499,12 +499,8 @@ namespace AzFramework
for (auto it = newEntitiesBegin; it != newEntitiesEnd; ++it)
{
AZ::Entity* clone = (*it);
// The entity component framework doesn't handle entities without TransformComponent safely.
if (!clone->GetComponents().empty())
{
clone->SetSpawnTicketId(request.m_ticketId);
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, *it);
}
clone->SetSpawnTicketId(request.m_ticketId);
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, clone);
}
// Let other systems know about newly spawned entities for any post-processing after adding to the scene/game context.
@@ -636,12 +632,8 @@ namespace AzFramework
for (auto it = ticket.m_spawnedEntities.begin() + spawnedEntitiesInitialCount; it != ticket.m_spawnedEntities.end(); ++it)
{
AZ::Entity* clone = (*it);
// The entity component framework doesn't handle entities without TransformComponent safely.
if (!clone->GetComponents().empty())
{
clone->SetSpawnTicketId(request.m_ticketId);
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, *it);
}
clone->SetSpawnTicketId(request.m_ticketId);
GameEntityContextRequestBus::Broadcast(&GameEntityContextRequestBus::Events::AddGameEntity, *it);
}
if (request.m_completionCallback)
@@ -668,7 +660,7 @@ namespace AzFramework
{
if (entity != nullptr)
{
// Setting it to 0 is needed to avoid the infite loop between GameEntityContext and SpawnableEntitiesManager.
// Setting it to 0 is needed to avoid the infinite loop between GameEntityContext and SpawnableEntitiesManager.
entity->SetSpawnTicketId(0);
GameEntityContextRequestBus::Broadcast(
&GameEntityContextRequestBus::Events::DestroyGameEntity, entity->GetId());
@@ -702,7 +694,7 @@ namespace AzFramework
{
if (*entityIterator != nullptr && (*entityIterator)->GetId() == request.m_entityId)
{
// Setting it to 0 is needed to avoid the infite loop between GameEntityContext and SpawnableEntitiesManager.
// Setting it to 0 is needed to avoid the infinite loop between GameEntityContext and SpawnableEntitiesManager.
(*entityIterator)->SetSpawnTicketId(0);
GameEntityContextRequestBus::Broadcast(
&GameEntityContextRequestBus::Events::DestroyGameEntity, (*entityIterator)->GetId());
@@ -949,11 +941,6 @@ namespace AzFramework
GameEntityContextRequestBus::Broadcast(
&GameEntityContextRequestBus::Events::DestroyGameEntity, entity->GetId());
}
else
{
// Entities without components wouldn't have been send to the GameEntityContext.
delete entity;
}
}
delete request.m_ticket;
@@ -77,6 +77,12 @@ namespace UnitTest
public:
AZ_COMPONENT(TargetSpawnableComponent, "{B4041561-63A7-4E1E-80F1-78C08D497960}");
TargetSpawnableComponent() = default;
explicit TargetSpawnableComponent(AZ::EntityId parent)
: m_parent(parent)
{
}
void Activate() override {}
void Deactivate() override {}
@@ -84,14 +90,19 @@ namespace UnitTest
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serializeContext->Class<TargetSpawnableComponent, AZ::Component>();
serializeContext->Class<TargetSpawnableComponent, AZ::Component>()
->Field("Parent", &TargetSpawnableComponent::m_parent);
}
}
AZ::EntityId m_parent;
};
class SpawnableEntitiesManagerTest : public AllocatorsFixture
{
public:
constexpr static AZ::u64 EntityIdStartId = 40;
void SetUp() override
{
AllocatorsFixture::SetUp();
@@ -111,7 +122,7 @@ namespace UnitTest
m_spawnable = aznew AzFramework::Spawnable(
AZ::Data::AssetId::CreateString("{EB2E8A2B-F253-4A90-BBF4-55F2EED786B8}:0"), AZ::Data::AssetData::AssetStatus::Ready);
m_spawnableAsset = new AZ::Data::Asset<AzFramework::Spawnable>(m_spawnable, AZ::Data::AssetLoadBehavior::Default);
m_ticket = new AzFramework::EntitySpawnTicket(*m_spawnableAsset);
m_ticket = aznew AzFramework::EntitySpawnTicket(*m_spawnableAsset);
auto managerInterface = AzFramework::SpawnableEntitiesInterface::Get();
m_manager = azrtti_cast<AzFramework::SpawnableEntitiesManager*>(managerInterface);
@@ -147,22 +158,43 @@ namespace UnitTest
{
auto entry = AZStd::make_unique<AZ::Entity>();
entry->AddComponent(aznew SourceSpawnableComponent());
entry->SetId(AZ::EntityId(EntityIdStartId + i));
entities.push_back(AZStd::move(entry));
}
}
AZ::Data::Asset<AzFramework::Spawnable> CreateTargetSpawnable(size_t numElements)
AZ::Data::Asset<AzFramework::Spawnable> CreateTargetSpawnable(size_t numElements, bool requiresMatchingEntityIds)
{
auto target = aznew AzFramework::Spawnable(
AZ::Data::AssetId(AZ::Uuid("{716CD8C3-0BA8-4F32-B579-0EC7C967796F}")), AZ::Data::AssetData::AssetStatus::Ready);
AzFramework::Spawnable::EntityList& entities = target->GetEntities();
entities.reserve(numElements);
for (size_t i = 0; i < numElements; ++i)
if (requiresMatchingEntityIds)
{
auto entry = AZStd::make_unique<AZ::Entity>();
entry->AddComponent(aznew TargetSpawnableComponent());
entities.push_back(AZStd::move(entry));
for (size_t i = 0; i < numElements; ++i)
{
auto entry = AZStd::make_unique<AZ::Entity>();
if (i != 0)
{
entry->AddComponent(aznew TargetSpawnableComponent(AZ::EntityId(EntityIdStartId + i - 1)));
}
else
{
entry->AddComponent(aznew TargetSpawnableComponent());
}
entry->SetId(AZ::EntityId(EntityIdStartId + i));
entities.push_back(AZStd::move(entry));
}
}
else
{
for (size_t i = 0; i < numElements; ++i)
{
auto entry = AZStd::make_unique<AZ::Entity>();
entry->AddComponent(aznew TargetSpawnableComponent());
entities.push_back(AZStd::move(entry));
}
}
return AZ::Data::Asset<AzFramework::Spawnable>(target, AZ::Data::AssetLoadBehavior::NoLoad);
@@ -212,6 +244,38 @@ namespace UnitTest
return true;
}
static bool DoParentEntityIdsMatch(AzFramework::SpawnableConstEntityContainerView entities)
{
if (entities.empty())
{
return false;
}
const AZ::Entity* previous = nullptr;
for (const AZ::Entity* entity : entities)
{
if (entity)
{
if (previous)
{
if (TargetSpawnableComponent* link = entity->FindComponent<TargetSpawnableComponent>(); link != nullptr)
{
if (link->m_parent != previous->GetId())
{
return false;
}
}
previous = entity;
}
}
else
{
return false;
}
}
return true;
}
static bool IsEveryOtherEntityAReplacement(AzFramework::SpawnableConstEntityContainerView entities)
{
bool onAlternative = true;
@@ -516,7 +580,7 @@ namespace UnitTest
// Make sure we start with a fresh ticket each time, or else each iteration through this loop would continue to build up
// more and more entities.
delete m_ticket;
m_ticket = new AzFramework::EntitySpawnTicket(*m_spawnableAsset);
m_ticket = aznew AzFramework::EntitySpawnTicket(*m_spawnableAsset);
constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
@@ -599,7 +663,8 @@ namespace UnitTest
using namespace AzFramework;
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4);
constexpr bool requiresMatchingEntityIds = true;
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4, requiresMatchingEntityIds);
InsertEntityAliases<4>(
{ 0, 1, 2, 3 }, { 0, 1, 2, 3 },
{ Spawnable::EntityAliasType::Replace, Spawnable::EntityAliasType::Replace, Spawnable::EntityAliasType::Replace,
@@ -608,11 +673,13 @@ namespace UnitTest
size_t spawnedEntitiesCount = 0;
bool allReplaced = false;
auto callback = [&spawnedEntitiesCount, &allReplaced](
bool allEntityIdsPatched = false;
auto callback = [&spawnedEntitiesCount, &allReplaced, &allEntityIdsPatched](
AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
spawnedEntitiesCount += entities.size();
allReplaced = AreAllEntitiesReplaced(entities);
allEntityIdsPatched = DoParentEntityIdsMatch(entities);
};
AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
@@ -621,6 +688,7 @@ namespace UnitTest
EXPECT_EQ(4, spawnedEntitiesCount);
EXPECT_TRUE(allReplaced);
EXPECT_TRUE(allEntityIdsPatched);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnAllEntities_AllAliasesWithAdditional_SourceAndTargetComponentsMerged)
@@ -628,7 +696,8 @@ namespace UnitTest
using namespace AzFramework;
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4);
constexpr bool requiresMatchingEntityIds = false;
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4, requiresMatchingEntityIds);
InsertEntityAliases<4>(
{ 0, 1, 2, 3 }, { 0, 1, 2, 3 },
{ Spawnable::EntityAliasType::Additional, Spawnable::EntityAliasType::Additional, Spawnable::EntityAliasType::Additional,
@@ -637,11 +706,13 @@ namespace UnitTest
size_t spawnedEntitiesCount = 0;
bool allAdded = false;
auto callback = [&spawnedEntitiesCount, &allAdded](
bool allEntityIdsPatched = false;
auto callback = [&spawnedEntitiesCount, &allAdded, &allEntityIdsPatched](
AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
spawnedEntitiesCount += entities.size();
allAdded = IsEveryOtherEntityAReplacement(entities);
allEntityIdsPatched = DoParentEntityIdsMatch(entities);
};
AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
@@ -650,6 +721,7 @@ namespace UnitTest
EXPECT_EQ(8, spawnedEntitiesCount);
EXPECT_TRUE(allAdded);
EXPECT_TRUE(allEntityIdsPatched);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnAllEntities_AllAliasesWithMerge_SourceAndTargetComponentsMerged)
@@ -657,7 +729,8 @@ namespace UnitTest
using namespace AzFramework;
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4);
constexpr bool requiresMatchingEntityIds = true;
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4, requiresMatchingEntityIds);
InsertEntityAliases<4>(
{ 0, 1, 2, 3 }, { 0, 1, 2, 3 },
{ Spawnable::EntityAliasType::Merge, Spawnable::EntityAliasType::Merge, Spawnable::EntityAliasType::Merge,
@@ -666,11 +739,13 @@ namespace UnitTest
size_t spawnedEntitiesCount = 0;
bool allMerged = false;
auto callback = [&spawnedEntitiesCount, &allMerged](
bool allEntityIdsPatched = false;
auto callback = [&spawnedEntitiesCount, &allMerged, &allEntityIdsPatched](
AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
spawnedEntitiesCount += entities.size();
allMerged = AreAllMerged(entities);
allEntityIdsPatched = DoParentEntityIdsMatch(entities);
};
AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
@@ -679,6 +754,7 @@ namespace UnitTest
EXPECT_EQ(4, spawnedEntitiesCount);
EXPECT_TRUE(allMerged);
EXPECT_TRUE(allEntityIdsPatched);
}
//
@@ -1095,7 +1171,8 @@ namespace UnitTest
using namespace AzFramework;
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4);
constexpr bool requiresMatchingEntityIds = true;
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4, requiresMatchingEntityIds);
InsertEntityAliases<4>(
{ 0, 1, 2, 3 }, { 0, 1, 2, 3 },
{ Spawnable::EntityAliasType::Replace, Spawnable::EntityAliasType::Replace, Spawnable::EntityAliasType::Replace,
@@ -1106,11 +1183,13 @@ namespace UnitTest
size_t spawnedEntitiesCount = 0;
bool allReplaced = false;
auto callback = [&spawnedEntitiesCount, &allReplaced](
bool allEntityIdsPatched = false;
auto callback = [&spawnedEntitiesCount, &allReplaced, &allEntityIdsPatched](
AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
spawnedEntitiesCount += entities.size();
allReplaced = AreAllEntitiesReplaced(entities);
allEntityIdsPatched = DoParentEntityIdsMatch(entities);
};
AzFramework::SpawnEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
@@ -1119,6 +1198,7 @@ namespace UnitTest
EXPECT_EQ(4, spawnedEntitiesCount);
EXPECT_TRUE(allReplaced);
EXPECT_TRUE(allEntityIdsPatched);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_AllAliasesWithAdditional_SourceAndTargetComponentsMerged)
@@ -1126,7 +1206,8 @@ namespace UnitTest
using namespace AzFramework;
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4);
constexpr bool requiresMatchingEntityIds = false;
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4, requiresMatchingEntityIds);
InsertEntityAliases<4>(
{ 0, 1, 2, 3 }, { 0, 1, 2, 3 },
{ Spawnable::EntityAliasType::Additional, Spawnable::EntityAliasType::Additional, Spawnable::EntityAliasType::Additional,
@@ -1137,12 +1218,14 @@ namespace UnitTest
size_t spawnedEntitiesCount = 0;
bool allAdded = false;
bool allEntityIdsPatched = false;
auto callback =
[&spawnedEntitiesCount, &allAdded](
[&spawnedEntitiesCount, &allAdded, &allEntityIdsPatched](
AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
spawnedEntitiesCount += entities.size();
allAdded = IsEveryOtherEntityAReplacement(entities);
allEntityIdsPatched = DoParentEntityIdsMatch(entities);
};
AzFramework::SpawnEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
@@ -1151,6 +1234,7 @@ namespace UnitTest
EXPECT_EQ(8, spawnedEntitiesCount);
EXPECT_TRUE(allAdded);
EXPECT_TRUE(allEntityIdsPatched);
}
TEST_F(SpawnableEntitiesManagerTest, SpawnEntities_AllAliasesWithMerge_SourceAndTargetComponentsMerged)
@@ -1158,7 +1242,8 @@ namespace UnitTest
using namespace AzFramework;
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4);
constexpr bool requiresMatchingEntityIds = true;
AZ::Data::Asset<Spawnable> target = CreateTargetSpawnable(4, requiresMatchingEntityIds);
InsertEntityAliases<4>(
{ 0, 1, 2, 3 }, { 0, 1, 2, 3 },
{ Spawnable::EntityAliasType::Merge, Spawnable::EntityAliasType::Merge, Spawnable::EntityAliasType::Merge,
@@ -1169,11 +1254,13 @@ namespace UnitTest
size_t spawnedEntitiesCount = 0;
bool allMerged = false;
auto callback = [&spawnedEntitiesCount, &allMerged](
bool allEntityIdsPatched = false;
auto callback = [&spawnedEntitiesCount, &allMerged, &allEntityIdsPatched](
AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableConstEntityContainerView entities)
{
spawnedEntitiesCount += entities.size();
allMerged = AreAllMerged(entities);
allEntityIdsPatched = DoParentEntityIdsMatch(entities);
};
AzFramework::SpawnEntitiesOptionalArgs optionalArgs;
optionalArgs.m_completionCallback = AZStd::move(callback);
@@ -1182,6 +1269,7 @@ namespace UnitTest
EXPECT_EQ(4, spawnedEntitiesCount);
EXPECT_TRUE(allMerged);
EXPECT_TRUE(allEntityIdsPatched);
}
//
@@ -1302,6 +1390,36 @@ namespace UnitTest
// ClaimEntities
//
TEST_F(SpawnableEntitiesManagerTest, ClaimEntities_Call_AllEntitiesWereClaimedAndNotDeleted)
{
static constexpr size_t NumEntities = 4;
FillSpawnable(NumEntities);
AZStd::vector<AZ::Entity*> claimedEntities;
auto callback = [&claimedEntities](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableEntityContainerView container)
{
for (AZ::Entity* entity : container)
{
claimedEntities.push_back(entity);
}
};
{
AzFramework::EntitySpawnTicket ticket(*m_spawnableAsset);
m_manager->SpawnAllEntities(ticket);
m_manager->ClaimEntities(ticket, AZStd::move(callback));
m_manager->ProcessQueue(AzFramework::SpawnableEntitiesManager::CommandQueuePriority::Regular);
}
EXPECT_EQ(NumEntities, claimedEntities.size());
// If these calls fail it means that the ticket has still deleted the entities, so they weren't properly claimed.
for (AZ::Entity* entity : claimedEntities)
{
delete entity;
}
}
TEST_F(SpawnableEntitiesManagerTest, ClaimEntities_DeleteTicketBeforeCall_NoCrash)
{
auto callback = [](AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableEntityContainerView) {};
@@ -12,6 +12,8 @@
#include <QLabel>
#include <QPainter>
#include <QStyle>
#include <QTextCursor>
#include <QTextDocument>
namespace AzQtComponents
{
@@ -35,6 +37,7 @@ namespace AzQtComponents
m_text = text;
m_metricsLabel->setText(m_text);
m_elidedText.clear();
elide();
updateGeometry();
@@ -65,7 +68,62 @@ namespace AzQtComponents
void ElidingLabel::elide()
{
ensurePolished();
m_elidedText = fontMetrics().elidedText(m_text, m_elideMode, TextRect().width());
if (Qt::mightBeRichText(m_text))
{
// If RichText tags are elided using fontMetrics.elidedText(), they will break.
// A TextDocument is used to produce elided text that takes this into account.
const QString ellipsis("...");
const int maxLineWidth = TextRect().width();
QTextDocument doc;
doc.setHtml(m_text);
doc.setDefaultFont(font());
doc.setDocumentMargin(0.0);
// Turn off wrapping so the document uses a single line.
QTextOption option = doc.defaultTextOption();
option.setWrapMode(QTextOption::WrapMode::NoWrap);
doc.setDefaultTextOption(option);
doc.adjustSize();
if (doc.size().width() <= maxLineWidth)
{
m_elidedText = m_text;
}
else
{
QTextCursor textCursor(&doc);
textCursor.movePosition(QTextCursor::End);
int ellipsisWidth = 0;
// At the moment only ElideRight and ElideNone are ever used. This will need expanding if other elision modes are used.
if (m_elideMode == Qt::ElideRight)
{
ellipsisWidth = fontMetrics().horizontalAdvance(ellipsis);
}
// Move the cursor back until the text fits or the start of the text is reached.
while (doc.size().width() + ellipsisWidth > maxLineWidth && !textCursor.atStart())
{
textCursor.deletePreviousChar();
doc.adjustSize();
}
if (m_elideMode == Qt::ElideRight)
{
textCursor.insertText(ellipsis);
}
m_elidedText = doc.toHtml();
}
}
else
{
m_elidedText = fontMetrics().elidedText(m_text, m_elideMode, TextRect().width());
}
QLabel::setText(m_elidedText);
if (m_elidedText != m_text)
@@ -16,9 +16,12 @@
#define AZ_TRAIT_DISABLE_ASSET_JOB_PARALLEL_TESTS true
#define AZ_TRAIT_DISABLE_ASSET_MANAGER_FLOOD_TEST true
#define AZ_TRAIT_DISABLE_ASSETCONTAINERDISABLETEST true
#define AZ_TRAIT_DISABLE_FAILED_DLL_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_MODULE_TESTS true
#define AZ_TRAIT_DISABLE_FAILED_EMOTION_FX_TESTS true
// Golden perline gradiant values for random seed 7878 for this platform
#define AZ_TRAIT_UNIT_TEST_PERLINE_GRADIANT_GOLDEN_VALUES_7878 0.5000f, 0.5456f, 0.5138f, 0.4801f, \
0.4174f, 0.4942f, 0.5493f, 0.5431f, \
0.4984f, 0.5204f, 0.5526f, 0.5840f, \
0.5251f, 0.5029f, 0.6153f, 0.5802f,
#define AZ_TRAIT_UNIT_TEST_PERLINE_GRADIANT_GOLDEN_VALUES_7878 0.5000f, 0.5276f, 0.5341f, 0.4801f, \
0.5220f, 0.5162f, 0.4828f, 0.5431f, \
0.4799f, 0.4486f, 0.5054f, 0.4129f, \
0.6023f, 0.5029f, 0.4529f, 0.4428f,
@@ -415,8 +415,8 @@ namespace AzToolsFramework
{
// Construct the runtime entities and products
bool readyToCreateRootSpawnable = m_playInEditorData.m_assetsCache.IsActivated();
if (!readyToCreateRootSpawnable &&
!m_playInEditorData.m_assetsCache.Activate(Prefab::PrefabConversionUtils::PlayInEditor))
if (!readyToCreateRootSpawnable && !m_playInEditorData.m_assetsCache.Activate(Prefab::PrefabConversionUtils::PlayInEditor))
{
AZ_Error("Prefab", false, "Failed to create a prefab processing stack from key '%.*s'.", AZ_STRING_ARG(Prefab::PrefabConversionUtils::PlayInEditor));
return;
@@ -184,6 +184,10 @@ namespace AzToolsFramework
const float halfGridSquareCount = float(gridSquareCount) * 0.5f;
const float halfGridSize = halfGridSquareCount * squareSize;
const float fadeLineLength = cl_viewportFadeLineDistanceScale * squareSize;
// ensure AuxGeomDraw::OpacityType::Translucent render state is set
debugDisplay.SetAlpha(0.5f);
for (size_t lineIndex = 0; lineIndex <= gridSquareCount; ++lineIndex)
{
const float lineOffset = -halfGridSize + (lineIndex * squareSize);
@@ -142,14 +142,14 @@ namespace AzToolsFramework
return m_templateSourcePath;
}
void Instance::SetTemplateSourcePath(AZ::IO::PathView sourcePath)
void Instance::SetTemplateSourcePath(AZ::IO::Path sourcePath)
{
m_templateSourcePath = sourcePath;
m_templateSourcePath = AZStd::move(sourcePath);
}
void Instance::SetContainerEntityName(AZStd::string_view containerName)
void Instance::SetContainerEntityName(AZStd::string containerName)
{
m_containerEntity->SetName(containerName);
m_containerEntity->SetName(AZStd::move(containerName));
}
bool Instance::AddEntity(AZ::Entity& entity)
@@ -608,6 +608,31 @@ namespace AzToolsFramework
}
AZ::EntityId Instance::GetEntityIdFromAliasPath(AliasPathView relativeAliasPath) const
{
return GetInstanceAndEntityIdFromAliasPath(relativeAliasPath).second;
}
AZStd::pair<Instance*, AZ::EntityId> Instance::GetInstanceAndEntityIdFromAliasPath(AliasPathView relativeAliasPath)
{
Instance* instance = this;
AliasPathView path = relativeAliasPath.ParentPath();
for (auto it : path)
{
InstanceOptionalReference child = instance->FindNestedInstance(it.Native());
if (child.has_value())
{
instance = &(child->get());
}
else
{
return AZStd::pair<Instance*, AZ::EntityId>(nullptr, AZ::EntityId());
}
}
return AZStd::pair<Instance*, AZ::EntityId>(instance, instance->GetEntityId(relativeAliasPath.Filename().Native()));
}
AZStd::pair<const Instance*, AZ::EntityId> Instance::GetInstanceAndEntityIdFromAliasPath(AliasPathView relativeAliasPath) const
{
const Instance* instance = this;
AliasPathView path = relativeAliasPath.ParentPath();
@@ -620,11 +645,11 @@ namespace AzToolsFramework
}
else
{
return AZ::EntityId();
return AZStd::pair<const Instance*, AZ::EntityId>(nullptr, AZ::EntityId());
}
}
return instance->GetEntityId(relativeAliasPath.Filename().Native());
return AZStd::pair<const Instance*, AZ::EntityId>(instance, instance->GetEntityId(relativeAliasPath.Filename().Native()));
}
AZStd::vector<InstanceAlias> Instance::GetNestedInstanceAliases(TemplateId templateId) const
@@ -80,8 +80,8 @@ namespace AzToolsFramework
void SetTemplateId(TemplateId templateId);
const AZ::IO::Path& GetTemplateSourcePath() const;
void SetTemplateSourcePath(AZ::IO::PathView sourcePath);
void SetContainerEntityName(AZStd::string_view containerName);
void SetTemplateSourcePath(AZ::IO::Path sourcePath);
void SetContainerEntityName(AZStd::string containerName);
bool AddEntity(AZ::Entity& entity);
bool AddEntity(AZStd::unique_ptr<AZ::Entity>&& entity);
@@ -169,6 +169,13 @@ namespace AzToolsFramework
* @return entityId, invalid ID if not found
*/
AZ::EntityId GetEntityIdFromAliasPath(AliasPathView relativeAliasPath) const;
/**
* Retrieves the instance pointer and entity id from an alias path that's relative to this instance.
*
* @return A pair with the Instance and entity id. The Instance is set to null and entityId is set to invalid if not found.
*/
AZStd::pair<Instance*, AZ::EntityId> GetInstanceAndEntityIdFromAliasPath(AliasPathView relativeAliasPath);
AZStd::pair<const Instance*, AZ::EntityId> GetInstanceAndEntityIdFromAliasPath(AliasPathView relativeAliasPath) const;
/**
@@ -37,13 +37,13 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
}
prefabProcessorContext.ListPrefabs(
[this, &serializeContext, &prefabProcessorContext]([[maybe_unused]] AZStd::string_view prefabName, PrefabDom& prefab)
[this, &serializeContext, &prefabProcessorContext](PrefabDocument& prefab)
{
auto result = RemoveEditorInfo(prefab, serializeContext, prefabProcessorContext);
if (!result)
{
AZ_Error(
"Prefab", false, "Converting to runtime Prefab '%.*s' failed, Error: %s .", AZ_STRING_ARG(prefabName),
"Prefab", false, "Converting to runtime Prefab '%s' failed, Error: %s .", prefab.GetName().c_str(),
result.GetError().c_str());
return;
}
@@ -58,10 +58,9 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
}
}
void EditorInfoRemover::GetEntitiesFromInstance(
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance>& instance, EntityList& hierarchyEntities)
void EditorInfoRemover::GetEntitiesFromInstance(AzToolsFramework::Prefab::Instance& instance, EntityList& hierarchyEntities)
{
instance->GetAllEntitiesInHierarchy(
instance.GetAllEntitiesInHierarchy(
[&hierarchyEntities](const AZStd::unique_ptr<AZ::Entity>& entity)
{
hierarchyEntities.emplace_back(entity.get());
@@ -498,7 +497,7 @@ exportComponent, prefabProcessorContext);
}
EditorInfoRemover::RemoveEditorInfoResult EditorInfoRemover::RemoveEditorInfo(
PrefabDom& prefab,
PrefabDocument& prefab,
AZ::SerializeContext* serializeContext,
PrefabProcessorContext& prefabProcessorContext)
{
@@ -510,28 +509,10 @@ exportComponent, prefabProcessorContext);
m_componentRequirementsValidator.SetPlatformTags(prefabProcessorContext.GetPlatformTags());
// convert Prefab DOM into Prefab Instance.
AZStd::unique_ptr<Instance> instance(aznew Instance());
if (!Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(*instance, prefab,
Prefab::PrefabDomUtils::LoadFlags::AssignRandomEntityId))
{
PrefabDomValueReference sourceReference = PrefabDomUtils::FindPrefabDomValue(prefab, PrefabDomUtils::SourceName);
AZStd::string errorMessage("Failed to Load Prefab Instance from given Prefab Dom during Removal of Editor Info.");
if (sourceReference.has_value() &&
sourceReference->get().IsString() &&
sourceReference->get().GetStringLength() != 0)
{
AZStd::string_view source(sourceReference->get().GetString(), sourceReference->get().GetStringLength());
errorMessage += AZStd::string::format("Prefab Source: %.*s", AZ_STRING_ARG(source));
}
return AZ::Failure(errorMessage);
}
// grab all nested entities from the Instance as source entities.
Instance& sourceInstance = prefab.GetInstance();
EntityList sourceEntities;
GetEntitiesFromInstance(instance, sourceEntities);
GetEntitiesFromInstance(sourceInstance, sourceEntities);
EntityList exportEntities;
@@ -597,7 +578,7 @@ exportComponent, prefabProcessorContext);
exportEntitiesMap.emplace(entity->GetId(), entity);
}
);
instance->RemoveNestedEntities(
sourceInstance.RemoveNestedEntities(
[&exportEntitiesMap](const AZStd::unique_ptr<AZ::Entity>& entity)
{
return exportEntitiesMap.find(entity->GetId()) == exportEntitiesMap.end();
@@ -605,7 +586,7 @@ exportComponent, prefabProcessorContext);
);
// replace entities of instance with exported ones.
instance->GetAllEntitiesInHierarchy(
sourceInstance.GetAllEntitiesInHierarchy(
[&exportEntitiesMap](AZStd::unique_ptr<AZ::Entity>& entity)
{
auto entityId = entity->GetId();
@@ -614,16 +595,6 @@ exportComponent, prefabProcessorContext);
}
);
// save the final result in the target Prefab DOM.
PrefabDom filteredPrefab;
if (!PrefabDomUtils::StoreInstanceInPrefabDom(*instance, filteredPrefab))
{
return AZ::Failure(AZStd::string::format(
"Saving exported Prefab Instance within a Prefab Dom failed.")
);
}
prefab.Swap(filteredPrefab);
return AZ::Success();
}
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
@@ -43,7 +43,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
using RemoveEditorInfoResult = AZ::Outcome<void, AZStd::string>;
RemoveEditorInfoResult RemoveEditorInfo(
PrefabDom& prefab,
PrefabDocument& prefab,
AZ::SerializeContext* serializeContext,
PrefabProcessorContext& prefabProcessorContext);
@@ -51,8 +51,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
protected:
using EntityList = AZStd::vector<AZ::Entity*>;
static void GetEntitiesFromInstance(
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance>& instance, EntityList& hierarchyEntities);
static void GetEntitiesFromInstance(AzToolsFramework::Prefab::Instance& instance, EntityList& hierarchyEntities);
static bool ReadComponentAttribute(
AZ::Component* component,
@@ -0,0 +1,69 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/base.h>
#include <AzCore/Component/EntityId.h>
#include <AzCore/std/containers/variant.h>
#include <AzCore/std/string/string.h>
#include <AzFramework/Spawnable/Spawnable.h>
#include <AzToolsFramework/Prefab/Instance/Instance.h>
namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
enum class EntityAliasType : uint8_t
{
Disable, //!< No alias is added.
OptionalReplace, //!< At runtime the entity might be replaced. If the alias is disabled the original entity will be spawned.
//!< The original entity will be left in the spawnable and a copy is returned.
Replace, //!< At runtime the entity will be replaced. If the alias is disabled nothing will be spawned. The original
//!< entity is returned and a blank entity is left.
Additional, //!< At runtime the alias entity will be added as an additional but unrelated entity with a new entity id.
//!< An empty entity will be returned.
Merge //!< At runtime the components in both entities will be merged. An empty entity will be returned. The added
//!< components may no conflict with the entities already in the root entity.
};
enum class EntityAliasSpawnableLoadBehavior : uint8_t
{
NoLoad, //!< Don't load the spawnable referenced in the entity alias. Loading will be up to the caller.
QueueLoad, //!< Queue the spawnable referenced in the entity alias for loading. This will be an async load because asset
//!< handlers aren't allowed to start a blocking load as this can lead to deadlocks. This option will allow
//!< to disable loading the referenced spawnable through the event fired from the spawnables asset handler.
DependentLoad //!< The spawnable referenced in the entity alias is made a dependency of the spawnable that holds the entity
//!< alias. This will cause the spawnable to be automatically loaded along with the owning spawnable.
};
struct EntityAliasSpawnableLink
{
EntityAliasSpawnableLink(AzFramework::Spawnable& spawnable, AZ::EntityId index);
AzFramework::Spawnable& m_spawnable;
AZ::EntityId m_index;
};
struct EntityAliasPrefabLink
{
EntityAliasPrefabLink(AZStd::string prefabName, AzToolsFramework::Prefab::AliasPath alias);
AZStd::string m_prefabName;
AzToolsFramework::Prefab::AliasPath m_alias;
};
struct EntityAliasStore
{
using LinkStore = AZStd::variant<AZStd::monostate, EntityAliasSpawnableLink, EntityAliasPrefabLink>;
LinkStore m_source;
LinkStore m_target;
uint32_t m_tag;
AzFramework::Spawnable::EntityAliasType m_aliasType;
EntityAliasSpawnableLoadBehavior m_loadBehavior;
};
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
@@ -112,9 +112,9 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
// Use a random uuid as this is only a temporary source.
PrefabConversionUtils::PrefabProcessorContext context(AZ::Uuid::CreateRandom());
PrefabDom copy;
copy.CopyFrom(templateReference->get().GetPrefabDom(), copy.GetAllocator(), false);
context.AddPrefab(spawnableName, AZStd::move(copy));
PrefabDocument document(spawnableName);
document.SetPrefabDom(templateReference->get().GetPrefabDom());
context.AddPrefab(AZStd::move(document));
m_converter.ProcessPrefab(context);
if (!context.HasCompletedSuccessfully() || context.GetProcessedObjects().empty())
@@ -25,9 +25,9 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
AZ::DataStream::StreamType serializationFormat = m_serializationFormat == SerializationFormats::Binary ?
AZ::DataStream::StreamType::ST_BINARY : AZ::DataStream::StreamType::ST_XML;
context.ListPrefabs([&context, serializationFormat](AZStd::string_view prefabName, PrefabDom& prefab)
context.ListPrefabs([&context, serializationFormat](PrefabDocument& prefab)
{
ProcessPrefab(context, prefabName, prefab, serializationFormat);
ProcessPrefab(context, prefab, serializationFormat);
});
}
@@ -45,12 +45,12 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
}
}
void PrefabCatchmentProcessor::ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab,
void PrefabCatchmentProcessor::ProcessPrefab(PrefabProcessorContext& context, PrefabDocument& prefab,
AZ::DataStream::StreamType serializationFormat)
{
using namespace AzToolsFramework::Prefab::SpawnableUtils;
AZStd::string uniqueName = prefabName;
AZStd::string uniqueName = prefab.GetName();
uniqueName += AzFramework::Spawnable::DotFileExtension;
auto serializer = [serializationFormat](AZStd::vector<uint8_t>& output, const ProcessedObjectStore& object) -> bool
@@ -64,45 +64,34 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
AZStd::move(uniqueName), context.GetSourceUuid(), AZStd::move(serializer));
AZ_Assert(spawnable, "Failed to create a new spawnable.");
Instance instance;
if (Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(
instance, prefab, object.GetReferencedAssets(),
Prefab::PrefabDomUtils::LoadFlags::AssignRandomEntityId)) // Always assign random entity ids because the spawnable is
// going to be used to create clones of the entities.
{
// Resolve entity aliases that store PrefabDOM information to use the spawnable instead. This is done before the entities are
// moved from the instance as they'd otherwise can't be found.
context.ResolveSpawnableEntityAliases(prefabName, *spawnable, instance);
Instance& instance = prefab.GetInstance();
// Resolve entity aliases that store PrefabDOM information to use the spawnable instead. This is done before the entities are
// moved from the instance as they'd otherwise can't be found.
context.ResolveSpawnableEntityAliases(prefab.GetName(), *spawnable, instance);
AzFramework::Spawnable::EntityList& entities = spawnable->GetEntities();
instance.DetachAllEntitiesInHierarchy(
[&entities, &context](AZStd::unique_ptr<AZ::Entity> entity)
AzFramework::Spawnable::EntityList& entities = spawnable->GetEntities();
instance.DetachAllEntitiesInHierarchy(
[&entities, &context](AZStd::unique_ptr<AZ::Entity> entity)
{
if (entity)
{
if (entity)
entity->InvalidateDependencies();
AZ::Entity::DependencySortOutcome evaluation = entity->EvaluateDependenciesGetDetails();
if (evaluation.IsSuccess())
{
entity->InvalidateDependencies();
AZ::Entity::DependencySortOutcome evaluation = entity->EvaluateDependenciesGetDetails();
if (evaluation.IsSuccess())
{
entities.emplace_back(AZStd::move(entity));
}
else
{
AZ_Error(
"Prefabs", false, "Entity '%s' %s cannot be activated for the following reason: %s",
entity->GetName().c_str(), entity->GetId().ToString().c_str(), evaluation.GetError().m_message.c_str());
context.ErrorEncountered();
}
entities.emplace_back(AZStd::move(entity));
}
});
else
{
AZ_Error(
"Prefabs", false, "Entity '%s' %s cannot be activated for the following reason: %s",
entity->GetName().c_str(), entity->GetId().ToString().c_str(), evaluation.GetError().m_message.c_str());
context.ErrorEncountered();
}
}
});
SpawnableUtils::SortEntitiesByTransformHierarchy(*spawnable);
context.GetProcessedObjects().push_back(AZStd::move(object));
}
else
{
AZ_Error("Prefabs", false, "Failed to convert prefab '%.*s' to a spawnable.", AZ_STRING_ARG(prefabName));
context.ErrorEncountered();
}
SpawnableUtils::SortEntitiesByTransformHierarchy(*spawnable);
context.GetProcessedObjects().push_back(AZStd::move(object));
}
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
@@ -40,8 +40,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
static void Reflect(AZ::ReflectContext* context);
protected:
static void ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab,
AZ::DataStream::StreamType serializationFormat);
static void ProcessPrefab(PrefabProcessorContext& context, PrefabDocument& prefab, AZ::DataStream::StreamType serializationFormat);
SerializationFormats m_serializationFormat{ SerializationFormats::Binary };
};
@@ -0,0 +1,151 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
#include <AzToolsFramework/Prefab/Spawnable/PrefabDocument.h>
#include <AzToolsFramework/Prefab/Spawnable/PrefabProcessorContext.h>
namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
PrefabDocument::PrefabDocument(AZStd::string name)
: m_name(AZStd::move(name))
, m_instance(AZStd::make_unique<AzToolsFramework::Prefab::Instance>())
{
m_instance->SetTemplateSourcePath(AZ::IO::Path("InMemory") / m_name);
}
bool PrefabDocument::SetPrefabDom(const PrefabDom& prefab)
{
if (ConstructInstanceFromPrefabDom(prefab))
{
constexpr bool copyConstStrings = true;
m_dom.CopyFrom(prefab, m_dom.GetAllocator(), copyConstStrings);
return true;
}
else
{
return false;
}
}
bool PrefabDocument::SetPrefabDom(PrefabDom&& prefab)
{
if (ConstructInstanceFromPrefabDom(prefab))
{
m_dom = AZStd::move(prefab);
return true;
}
else
{
return false;
}
}
const AZStd::string& PrefabDocument::GetName() const
{
return m_name;
}
const PrefabDom& PrefabDocument::GetDom() const
{
if (m_isDirty)
{
m_isDirty = !PrefabDomUtils::StoreInstanceInPrefabDom(*m_instance, m_dom);
}
return m_dom;
}
PrefabDom&& PrefabDocument::TakeDom()
{
if (m_isDirty)
{
[[maybe_unused]] bool storedSuccessfully = PrefabDomUtils::StoreInstanceInPrefabDom(*m_instance, m_dom);
AZ_Assert(storedSuccessfully, "Failed to store Instance '%s' to PrefabDom.", m_name.c_str());
m_isDirty = false;
}
// After the PrefabDom is moved an empty PrefabDom is left behind. This should be reflected in the Instance,
// so reset it so it's empty as well.
m_instance->Reset();
m_instance->SetTemplateSourcePath(AZ::IO::Path("InMemory") / m_name);
return AZStd::move(m_dom);
}
void PrefabDocument::ListEntitiesWithComponentType(
AZ::TypeId componentType, const AZStd::function<bool(AzToolsFramework::Prefab::AliasPath&&)>& callback) const
{
m_instance->GetAllEntitiesInHierarchyConst(
[this, &componentType, &callback](const AZ::Entity& entity) -> bool
{
if (entity.FindComponent(componentType))
{
return callback(m_instance->GetAliasPathRelativeToInstance(entity.GetId()));
}
else
{
return true;
}
});
}
AZ::Entity* PrefabDocument::CreateEntityAlias(
PrefabDocument& source,
AzToolsFramework::Prefab::AliasPathView entity,
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType,
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasSpawnableLoadBehavior loadBehavior,
uint32_t tag,
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context)
{
auto&& [sourceInstance, entityId] = source.m_instance->GetInstanceAndEntityIdFromAliasPath(entity);
if (sourceInstance != nullptr && entityId.IsValid())
{
return SpawnableUtils::CreateEntityAlias(
source.m_name, *sourceInstance, m_name, *m_instance, entityId, aliasType, loadBehavior, tag, context);
}
else
{
return nullptr;
}
}
AzToolsFramework::Prefab::Instance& PrefabDocument::GetInstance()
{
// Assume that changes will be made to the instance.
m_isDirty = true;
return *m_instance;
}
const AzToolsFramework::Prefab::Instance& PrefabDocument::GetInstance() const
{
return *m_instance;
}
bool PrefabDocument::ConstructInstanceFromPrefabDom(const PrefabDom& prefab)
{
using namespace AzToolsFramework::Prefab;
m_instance->Reset();
if (PrefabDomUtils::LoadInstanceFromPrefabDom(*m_instance, prefab, PrefabDomUtils::LoadFlags::AssignRandomEntityId))
{
return true;
}
else
{
#ifdef AZ_ENABLE_TRACING
AZStd::string_view sourceName = m_name;
PrefabDomValueConstReference sourceReference = PrefabDomUtils::FindPrefabDomValue(prefab, PrefabDomUtils::SourceName);
if (sourceReference.has_value() && sourceReference->get().IsString() && sourceReference->get().GetStringLength() != 0)
{
sourceName = AZStd::string_view(sourceReference->get().GetString(), sourceReference->get().GetStringLength());
}
AZ_Error(
"PrefabDocument", false, "Failed to construct Prefab instance from given PrefabDOM '%.*s'.", AZ_STRING_ARG(sourceName));
#endif
return false;
}
}
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
@@ -0,0 +1,66 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/RTTI/TypeInfo.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/string/string.h>
#include <AzToolsFramework/Prefab/Instance/Instance.h>
#include <AzToolsFramework/Prefab/PrefabDomTypes.h>
#include <AzToolsFramework/Prefab/Spawnable/EntityAliasTypes.h>
#include <AzToolsFramework/Prefab/Spawnable/SpawnableUtils.h>
namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
class PrefabProcessorContext;
class PrefabDocument final
{
public:
explicit PrefabDocument(AZStd::string name);
PrefabDocument(const PrefabDocument&) = delete;
PrefabDocument(PrefabDocument&&) = default;
PrefabDocument& operator=(const PrefabDocument&) = delete;
PrefabDocument& operator=(PrefabDocument&&) = default;
bool SetPrefabDom(const PrefabDom& prefab);
bool SetPrefabDom(PrefabDom&& prefab);
const AZStd::string& GetName() const;
const PrefabDom& GetDom() const;
PrefabDom&& TakeDom();
template<typename Component>
void ListEntitiesWithComponentType(const AZStd::function<bool(AzToolsFramework::Prefab::AliasPath&&)>& callback) const;
void ListEntitiesWithComponentType(
AZ::TypeId componentType, const AZStd::function<bool(AzToolsFramework::Prefab::AliasPath&&)>& callback) const;
AZ::Entity* CreateEntityAlias(
PrefabDocument& source,
AzToolsFramework::Prefab::AliasPathView entity,
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType,
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasSpawnableLoadBehavior loadBehavior,
uint32_t tag,
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context);
// Where possible, prefer functions directly on the PrefabDocument Instead of using the Instance.
AzToolsFramework::Prefab::Instance& GetInstance();
const AzToolsFramework::Prefab::Instance& GetInstance() const;
private:
bool ConstructInstanceFromPrefabDom(const PrefabDom& prefab);
mutable PrefabDom m_dom;
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> m_instance;
AZStd::string m_name;
mutable bool m_isDirty{ false };
};
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
#include <AzToolsFramework/Prefab/Spawnable/PrefabDocument.inl>
@@ -0,0 +1,16 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
template<typename Component>
void PrefabDocument::ListEntitiesWithComponentType(const AZStd::function<bool(AzToolsFramework::Prefab::AliasPath&&)>& callback) const
{
ListEntitiesWithComponentType(azrtti_typeid<Component>(), callback);
}
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
@@ -7,8 +7,10 @@
*/
#include <AzCore/Interface/Interface.h>
#include <AzCore/Component/EntityUtils.h>
#include <AzFramework/Spawnable/Spawnable.h>
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
#include <AzToolsFramework/Prefab/Spawnable/PrefabDocument.h>
#include <AzToolsFramework/Prefab/Spawnable/PrefabProcessorContext.h>
#include <AzToolsFramework/Prefab/Spawnable/SpawnableUtils.h>
@@ -30,27 +32,42 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
: m_sourceUuid(sourceUuid)
{}
bool PrefabProcessorContext::AddPrefab(AZStd::string prefabName, PrefabDom prefab)
bool PrefabProcessorContext::AddPrefab(PrefabDocument&& document)
{
auto result = m_prefabs.emplace(AZStd::move(prefabName), AZStd::move(prefab));
return result.second;
}
void PrefabProcessorContext::ListPrefabs(const AZStd::function<void(AZStd::string_view, PrefabDom&)>& callback)
{
m_isIterating = true;
for (auto& it : m_prefabs)
AZStd::string name = document.GetName();
if (!m_prefabNames.contains(name))
{
callback(it.first, it.second);
m_prefabNames.emplace(AZStd::move(name));
// If currently iterating add to pending queue to avoid invalidating the container that's being iterated over.
PrefabContainer& container = m_isIterating ? m_pendingPrefabAdditions : m_prefabs;
container.push_back(AZStd::move(document));
return true;
}
m_isIterating = false;
return false;
}
void PrefabProcessorContext::ListPrefabs(const AZStd::function<void(AZStd::string_view, const PrefabDom&)>& callback) const
void PrefabProcessorContext::ListPrefabs(const AZStd::function<void(PrefabDocument&)>& callback)
{
for (const auto& it : m_prefabs)
// Enable iterating state so the prefab container doesn't get invalided. Enabling this flag will cause new prefabs
// to be stored in a temporary buffer that can be moved into the regular prefab container after iterating.
m_isIterating = true;
for (PrefabDocument& document : m_prefabs)
{
callback(it.first, it.second);
callback(document);
}
m_isIterating = false;
m_prefabs.insert(
m_prefabs.end(), AZStd::make_move_iterator(m_pendingPrefabAdditions.begin()),
AZStd::make_move_iterator(m_pendingPrefabAdditions.end()));
m_pendingPrefabAdditions.clear();
}
void PrefabProcessorContext::ListPrefabs(const AZStd::function<void(const PrefabDocument&)>& callback) const
{
for (const PrefabDocument& document : m_prefabs)
{
callback(document);
}
}
@@ -132,6 +149,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
using namespace AzToolsFramework::Prefab;
// Resolve prefab links into spawnable links for the provided spawnable.
for (EntityAliasStore& entityAlias : m_entityAliases)
{
auto sourcePrefab = AZStd::get_if<EntityAliasPrefabLink>(&entityAlias.m_source);
@@ -224,11 +242,35 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
it = aliasVisitors.emplace(source->m_spawnable.GetId(), AZStd::move(visitor)).first;
}
it->second.AddAlias(
AZ::Data::Asset<AzFramework::Spawnable>(&target->m_spawnable, loadBehavior), alias.m_tag, sourceIndex, targetIndex,
AZ::Data::Asset<AzFramework::Spawnable>(target->m_spawnable.GetId(), azrtti_typeid<AzFramework::Spawnable>()), alias.m_tag,
sourceIndex, targetIndex,
alias.m_aliasType, alias.m_loadBehavior == EntityAliasSpawnableLoadBehavior::QueueLoad);
// Register the dependency between the two spawnables.
RegisterProductAssetDependency(source->m_spawnable.GetId(), target->m_spawnable.GetId(), loadBehavior);
// Patch up all entity ids so the alias points to the same entity id if needed.
switch (alias.m_aliasType)
{
case AzFramework::Spawnable::EntityAliasType::Original:
continue;
case AzFramework::Spawnable::EntityAliasType::Disable:
continue;
case AzFramework::Spawnable::EntityAliasType::Replace:
break; // Requires entity id for alias in source and target spawnable matches.
case AzFramework::Spawnable::EntityAliasType::Additional:
continue;
case AzFramework::Spawnable::EntityAliasType::Merge:
break; // Requires entity id for alias in source and target spawnable matches.
default:
continue;
}
auto entityIdMapper = [source, target](const AZ::EntityId& originalId, bool /*isEntityId*/) -> AZ::EntityId
{
return originalId == target->m_index ? source->m_index : originalId;
};
AZ::EntityUtils::ReplaceEntityIdsAndEntityRefs(&target->m_spawnable, entityIdMapper);
}
}
@@ -21,60 +21,12 @@
#include <AzFramework/Spawnable/Spawnable.h>
#include <AzToolsFramework/Prefab/Instance/Instance.h>
#include <AzToolsFramework/Prefab/PrefabDomTypes.h>
#include <AzToolsFramework/Prefab/Spawnable/EntityAliasTypes.h>
#include <AzToolsFramework/Prefab/Spawnable/PrefabDocument.h>
#include <AzToolsFramework/Prefab/Spawnable/ProcesedObjectStore.h>
namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
enum class EntityAliasType : uint8_t
{
Disable, //!< No alias is added.
OptionalReplace, //!< At runtime the entity might be replaced. If the alias is disabled the original entity will be spawned.
//!< The original entity will be left in the spawnable and a copy is returned.
Replace, //!< At runtime the entity will be replaced. If the alias is disabled nothing will be spawned. The original
//!< entity is returned and a blank entity is left.
Additional, //!< At runtime the alias entity will be added as an additional but unrelated entity with a new entity id.
//!< An empty entity will be returned.
Merge //!< At runtime the components in both entities will be merged. An empty entity will be returned. The added
//!< components may no conflict with the entities already in the root entity.
};
enum class EntityAliasSpawnableLoadBehavior : uint8_t
{
NoLoad, //!< Don't load the spawnable referenced in the entity alias. Loading will be up to the caller.
QueueLoad, //!< Queue the spawnable referenced in the entity alias for loading. This will be an async load because asset
//!< handlers aren't allowed to start a blocking load as this can lead to deadlocks. This option will allow
//!< to disable loading the referenced spawnable through the event fired from the spawnables asset handler.
DependentLoad //!< The spawnable referenced in the entity alias is made a dependency of the spawnable that holds the entity
//!< alias. This will cause the spawnable to be automatically loaded along with the owning spawnable.
};
struct EntityAliasSpawnableLink
{
EntityAliasSpawnableLink(AzFramework::Spawnable& spawnable, AZ::EntityId index);
AzFramework::Spawnable& m_spawnable;
AZ::EntityId m_index;
};
struct EntityAliasPrefabLink
{
EntityAliasPrefabLink(AZStd::string prefabName, AzToolsFramework::Prefab::AliasPath alias);
AZStd::string m_prefabName;
AzToolsFramework::Prefab::AliasPath m_alias;
};
struct EntityAliasStore
{
using LinkStore = AZStd::variant<AZStd::monostate, EntityAliasSpawnableLink, EntityAliasPrefabLink>;
LinkStore m_source;
LinkStore m_target;
uint32_t m_tag;
AzFramework::Spawnable::EntityAliasType m_aliasType;
EntityAliasSpawnableLoadBehavior m_loadBehavior;
};
struct AssetDependencyInfo
{
AZ::Data::AssetId m_assetId;
@@ -93,9 +45,9 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
explicit PrefabProcessorContext(const AZ::Uuid& sourceUuid);
virtual ~PrefabProcessorContext() = default;
virtual bool AddPrefab(AZStd::string prefabName, PrefabDom prefab);
virtual void ListPrefabs(const AZStd::function<void(AZStd::string_view, PrefabDom&)>& callback);
virtual void ListPrefabs(const AZStd::function<void(AZStd::string_view, const PrefabDom&)>& callback) const;
virtual bool AddPrefab(PrefabDocument&& document);
virtual void ListPrefabs(const AZStd::function<void(PrefabDocument&)>& callback);
virtual void ListPrefabs(const AZStd::function<void(const PrefabDocument&)>& callback) const;
virtual bool HasPrefabs() const;
virtual bool RegisterSpawnableProductAssetDependency(
@@ -128,12 +80,15 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
virtual void ErrorEncountered();
protected:
using NamedPrefabContainer = AZStd::unordered_map<AZStd::string, PrefabDom>;
using PrefabNames = AZStd::unordered_set<AZStd::string>;
using PrefabContainer = AZStd::vector<PrefabDocument>;
using SpawnableEntityAliasStore = AZStd::vector<EntityAliasStore>;
AZ::Data::AssetLoadBehavior ToAssetLoadBehavior(EntityAliasSpawnableLoadBehavior loadBehavior) const;
NamedPrefabContainer m_prefabs;
PrefabContainer m_prefabs;
PrefabContainer m_pendingPrefabAdditions;
PrefabNames m_prefabNames;
SpawnableEntityAliasStore m_entityAliases;
ProcessedObjectStoreContainer m_products;
ProductAssetDependencyContainer m_registeredProductAssetDependencies;
@@ -16,10 +16,12 @@
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzFramework/Components/TransformComponent.h>
#include <AzFramework/Spawnable/Spawnable.h>
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
#include <AzToolsFramework/Prefab/Instance/Instance.h>
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
#include <AzToolsFramework/Prefab/Spawnable/PrefabProcessorContext.h>
namespace AzToolsFramework::Prefab::SpawnableUtils
{
@@ -52,14 +54,32 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
return result;
}
const AZ::Entity* FindEntity(AZ::EntityId entityId, const AzToolsFramework::Prefab::Instance& source)
{
const AZ::Entity* result = nullptr;
source.GetConstEntities(
[&result, entityId](const AZ::Entity& entity)
{
if (entity.GetId() != entityId)
{
return true;
}
else
{
result = &entity;
return false;
}
});
return result;
}
AZ::Entity* FindEntity(AZ::EntityId entityId, AzFramework::Spawnable& source)
{
uint32_t index = AzToolsFramework::Prefab::SpawnableUtils::FindEntityIndex(entityId, source);
return index != InvalidEntityIndex ? source.GetEntities()[index].get() : nullptr;
}
template<typename T>
AZStd::unique_ptr<AZ::Entity> CloneEntity(AZ::EntityId entityId, T& source)
AZStd::unique_ptr<AZ::Entity> CloneEntity(AZ::EntityId entityId, AzToolsFramework::Prefab::Instance& source)
{
AZ::Entity* target = Internal::FindEntity(entityId, source);
AZ_Assert(
@@ -74,41 +94,30 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
return clone;
}
AZStd::unique_ptr<AZ::Entity> ReplaceEntityWithPlaceholder(AZ::EntityId entityId, AzToolsFramework::Prefab::Instance& source)
AZStd::unique_ptr<AZ::Entity> ReplaceEntityWithPlaceholder(
AZ::EntityId entityId,
[[maybe_unused]] AZStd::string_view sourcePrefabName,
AzToolsFramework::Prefab::Instance& source)
{
auto&& [instance, alias] = source.FindInstanceAndAlias(entityId);
AZ_Assert(
instance, "SpawnbleUtils were unable to locate entity alias with id %zu in Instance '%s' for replacing.",
aznumeric_cast<AZ::u64>(entityId), source.GetTemplateSourcePath().c_str());
instance, "SpawnbleUtils were unable to locate entity alias with id %zu in Instance '%.*s' for replacing.",
aznumeric_cast<AZ::u64>(entityId), AZ_STRING_ARG(sourcePrefabName));
EntityOptionalReference entityData = instance->GetEntity(alias);
AZ_Assert(
entityData.has_value(), "SpawnbleUtils were unable to locate entity '%.*s' in Instance '%s' for replacing.",
AZ_STRING_ARG(alias), source.GetTemplateSourcePath().c_str());
auto placeholder = AZStd::make_unique<AZ::Entity>(entityData->get().GetId(), entityData->get().GetName());
entityData.has_value(), "SpawnbleUtils were unable to locate entity '%.*s' in Instance '%.*s' for replacing.",
AZ_STRING_ARG(alias), AZ_STRING_ARG(sourcePrefabName));
// A new entity id can be used for the placeholder as `ReplaceEntity` will swap the entity ids.
auto placeholder = AZStd::make_unique<AZ::Entity>(AZ::Entity::MakeId(), entityData->get().GetName());
return instance->ReplaceEntity(AZStd::move(placeholder), alias);
}
AZStd::unique_ptr<AZ::Entity> ReplaceEntityWithPlaceholder(AZ::EntityId entityId, AzFramework::Spawnable& source)
{
uint32_t index = AzToolsFramework::Prefab::SpawnableUtils::FindEntityIndex(entityId, source);
AZ_Assert(
index != InvalidEntityIndex, "SpawnbleUtils were unable to locate entity alias with id %zu in Spawnable for replacing.",
aznumeric_cast<AZ::u64>(entityId));
AZStd::unique_ptr<AZ::Entity> original = AZStd::move(source.GetEntities()[index]);
AZ_Assert(
original, "SpawnbleUtils were unable to locate entity with id %zu in Spawnable for replacing.",
aznumeric_cast<AZ::u64>(entityId));
source.GetEntities()[index] = AZStd::make_unique<AZ::Entity>(original->GetId(), original->GetName());
return original;
}
template<typename Source>
AZStd::pair<AZStd::unique_ptr<AZ::Entity>, AzFramework::Spawnable::EntityAliasType> ApplyAlias(
Source& source, AZ::EntityId entityId, AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType)
AZStd::string_view sourcePrefabName,
AzToolsFramework::Prefab::Instance& source,
AZ::EntityId entityId,
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType)
{
namespace PCU = AzToolsFramework::Prefab::PrefabConversionUtils;
using ResultPair = AZStd::pair<AZStd::unique_ptr<AZ::Entity>, AzFramework::Spawnable::EntityAliasType>;
@@ -121,12 +130,13 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
case PCU::EntityAliasType::OptionalReplace:
return ResultPair(CloneEntity(entityId, source), AzFramework::Spawnable::EntityAliasType::Replace);
case PCU::EntityAliasType::Replace:
return ResultPair(ReplaceEntityWithPlaceholder(entityId, source), AzFramework::Spawnable::EntityAliasType::Replace);
return ResultPair(
ReplaceEntityWithPlaceholder(entityId, sourcePrefabName, source),
AzFramework::Spawnable::EntityAliasType::Replace);
case PCU::EntityAliasType::Additional:
ResultPair(AZStd::make_unique<AZ::Entity>(AZ::Entity::MakeId()), AzFramework::Spawnable::EntityAliasType::Additional);
return ResultPair(AZStd::make_unique<AZ::Entity>(), AzFramework::Spawnable::EntityAliasType::Additional);
case PCU::EntityAliasType::Merge:
// Use the same entity id as the original entity so at runtime the entity ids can be verified to match.
ResultPair(AZStd::make_unique<AZ::Entity>(entityId), AzFramework::Spawnable::EntityAliasType::Merge);
return ResultPair(AZStd::make_unique<AZ::Entity>(), AzFramework::Spawnable::EntityAliasType::Merge);
default:
AZ_Assert(
false, "Invalid PrefabProcessorContext::EntityAliasType type (%i) provided.", aznumeric_cast<uint64_t>(aliasType));
@@ -182,7 +192,8 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
AliasPath alias = source.GetAliasPathRelativeToInstance(entityId);
if (!alias.empty())
{
auto&& [replacement, storedAliasType] = Internal::ApplyAlias(source, entityId, aliasType);
auto&& [replacement, storedAliasType] =
Internal::ApplyAlias(sourcePrefabName, source, entityId, aliasType);
if (replacement)
{
AZ::Entity* result = replacement.get();
@@ -212,84 +223,6 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
}
}
AZ::Entity* CreateEntityAlias(
AZStd::string sourcePrefabName,
AzToolsFramework::Prefab::Instance& source,
AzFramework::Spawnable& target,
AZ::EntityId entityId,
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType,
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasSpawnableLoadBehavior loadBehavior,
uint32_t tag,
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context)
{
using namespace AzToolsFramework::Prefab::PrefabConversionUtils;
AliasPath alias = source.GetAliasPathRelativeToInstance(entityId);
if (!alias.empty())
{
auto&& [replacement, storedAliasType] = Internal::ApplyAlias(source, entityId, aliasType);
if (replacement)
{
AZ::Entity* result = replacement.get();
target.GetEntities().push_back(AZStd::move(replacement));
EntityAliasStore store;
store.m_aliasType = storedAliasType;
store.m_source.emplace<EntityAliasPrefabLink>(AZStd::move(sourcePrefabName), AZStd::move(alias));
store.m_target.emplace<EntityAliasSpawnableLink>(target, result->GetId());
store.m_tag = tag;
store.m_loadBehavior = loadBehavior;
context.RegisterSpawnableEntityAlias(AZStd::move(store));
return result;
}
else
{
AZ_Assert(false, "A replacement for entity with id %zu could not be created.", static_cast<AZ::u64>(entityId));
return nullptr;
}
}
else
{
AZ_Assert(false, "Entity with id %llu was not found in the source prefab.", static_cast<AZ::u64>(entityId));
return nullptr;
}
}
AZ::Entity* CreateEntityAlias(
AzFramework::Spawnable& source,
AzFramework::Spawnable& target,
AZ::EntityId entityId,
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType,
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasSpawnableLoadBehavior loadBehavior,
uint32_t tag,
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context)
{
using namespace AzToolsFramework::Prefab::PrefabConversionUtils;
auto&& [replacement, storedAliasType] = Internal::ApplyAlias(source, entityId, aliasType);
if (replacement)
{
AZ::Entity* result = replacement.get();
target.GetEntities().push_back(AZStd::move(replacement));
EntityAliasStore store;
store.m_aliasType = storedAliasType;
store.m_source.emplace<EntityAliasSpawnableLink>(source, entityId);
store.m_target.emplace<EntityAliasSpawnableLink>(target, result->GetId());
store.m_tag = tag;
store.m_loadBehavior = loadBehavior;
context.RegisterSpawnableEntityAlias(AZStd::move(store));
return result;
}
else
{
AZ_Assert(false, "A replacement for entity with id %zu could not be created.", static_cast<AZ::u64>(entityId));
return nullptr;
}
}
uint32_t FindEntityIndex(AZ::EntityId entity, const AzFramework::Spawnable& spawnable)
{
auto begin = spawnable.GetEntities().begin();
@@ -12,7 +12,7 @@
#include <AzCore/std/limits.h>
#include <AzFramework/Spawnable/Spawnable.h>
#include <AzToolsFramework/Prefab/PrefabDomTypes.h>
#include <AzToolsFramework/Prefab/Spawnable/PrefabProcessorContext.h>
#include <AzToolsFramework/Prefab/Spawnable/EntityAliasTypes.h>
namespace AZ
{
@@ -24,6 +24,11 @@ namespace AzToolsFramework::Prefab
class Instance;
}
namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
class PrefabProcessorContext;
}
namespace AzToolsFramework::Prefab::SpawnableUtils
{
static constexpr uint32_t InvalidEntityIndex = AZStd::numeric_limits<uint32_t>::max();
@@ -41,24 +46,7 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasSpawnableLoadBehavior loadBehavior,
uint32_t tag,
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context);
AZ::Entity* CreateEntityAlias(
AZStd::string sourcePrefabName,
AzToolsFramework::Prefab::Instance& source,
AzFramework::Spawnable& target,
AZ::EntityId entityId,
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType,
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasSpawnableLoadBehavior loadBehavior,
uint32_t tag,
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context);
AZ::Entity* CreateEntityAlias(
AzFramework::Spawnable& source,
AzFramework::Spawnable& target,
AZ::EntityId entityId,
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType,
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasSpawnableLoadBehavior loadBehavior,
uint32_t tag,
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context);
uint32_t FindEntityIndex(AZ::EntityId entity, const AzFramework::Spawnable& spawnable);
void SortEntitiesByTransformHierarchy(AzFramework::Spawnable& spawnable);
@@ -421,6 +421,7 @@ namespace AzToolsFramework
{
QString label{ text };
m_nameLabel->setText(label);
m_nameLabel->setOpenExternalLinks(true);
m_nameLabel->setVisible(!label.isEmpty());
// setting the stretches to 0 in case of an empty label really hides the label (i.e. even the reserved space)
m_mainLayout->setStretch(0, label.isEmpty() ? 0 : LabelColumnStretch);
@@ -30,8 +30,7 @@ namespace UnitTest
void MousePressAndMove(
QWidget* widget, const QPoint& initialPositionWidget, const QPoint& mouseDelta, const Qt::MouseButton mouseButton)
{
QPoint position = widget->mapToGlobal(initialPositionWidget);
QTest::mousePress(widget, mouseButton, Qt::NoModifier, position);
QTest::mousePress(widget, mouseButton, Qt::NoModifier, initialPositionWidget);
MouseMove(widget, initialPositionWidget, mouseDelta, mouseButton);
}
@@ -45,14 +44,15 @@ namespace UnitTest
// - https://lists.qt-project.org/pipermail/development/2019-July/036873.html
void MouseMove(QWidget* widget, const QPoint& initialPositionWidget, const QPoint& mouseDelta, const Qt::MouseButton mouseButton)
{
QPoint nextPosition = widget->mapToGlobal(initialPositionWidget + mouseDelta);
const QPoint nextLocalPosition = initialPositionWidget + mouseDelta;
const QPoint nextGlobalPosition = widget->mapToGlobal(nextLocalPosition);
// ^1 To ensure a mouse move event is fired we must call the test mouse move function
// and also send a mouse move event that matches. Each on their own do not appear to
// work - please see the links above for more context.
QTest::mouseMove(widget, nextPosition);
QTest::mouseMove(widget, nextLocalPosition);
QMouseEvent mouseMoveEvent(
QEvent::MouseMove, QPointF(nextPosition), QPointF(nextPosition), Qt::NoButton, mouseButton, Qt::NoModifier);
QEvent::MouseMove, QPointF(nextLocalPosition), QPointF(nextGlobalPosition), Qt::NoButton, mouseButton, Qt::NoModifier);
QApplication::sendEvent(widget, &mouseMoveEvent);
}
@@ -157,6 +157,23 @@ namespace UnitTest
return QWidget::event(event);
}
MouseMoveDetector::MouseMoveDetector(QWidget* parent)
: QObject(parent)
{
}
bool MouseMoveDetector::eventFilter(QObject* watched, QEvent* event)
{
if (const auto eventType = event->type(); eventType == QEvent::Type::MouseMove)
{
auto mouseEvent = static_cast<QMouseEvent*>(event);
m_mouseGlobalPosition = mouseEvent->globalPos();
m_mouseLocalPosition = mouseEvent->pos();
}
return QObject::eventFilter(watched, event);
}
void TestEditorActions::Connect()
{
using AzToolsFramework::GetEntityContextId;
@@ -571,3 +588,5 @@ namespace UnitTest
sliceAssets.clear();
}
} // namespace UnitTest
#include <moc_AzToolsFrameworkTestHelpers.cpp>
@@ -111,10 +111,29 @@ namespace UnitTest
{
Q_OBJECT
public:
FocusInteractionWidget(QWidget* parent = nullptr) : QWidget(parent) {}
FocusInteractionWidget(QWidget* parent = nullptr)
: QWidget(parent)
{
}
bool event(QEvent* event) override;
};
/// Records mouse move events and stores the local and global position of the cursor.
/// @note To use, install as an event filter for the widget being interacted with
/// e.g. m_testWidget->installEventFilter(&m_mouseMoveDetector);
class MouseMoveDetector : public QObject
{
Q_OBJECT
public:
MouseMoveDetector(QWidget* parent = nullptr);
bool eventFilter([[maybe_unused]] QObject* watched, QEvent* event) override;
QPoint m_mouseGlobalPosition;
QPoint m_mouseLocalPosition;
};
/// Stores actions registered for either normal mode (regular viewport) editing and
/// component mode editing.
class TestEditorActions
@@ -723,6 +723,7 @@ set(FILES
Prefab/Spawnable/EditorOnlyEntityHandler/UiEditorOnlyEntityHandler.cpp
Prefab/Spawnable/EditorOnlyEntityHandler/WorldEditorOnlyEntityHandler.h
Prefab/Spawnable/EditorOnlyEntityHandler/WorldEditorOnlyEntityHandler.cpp
Prefab/Spawnable/EntityAliasTypes.h
Prefab/Spawnable/InMemorySpawnableAssetContainer.h
Prefab/Spawnable/InMemorySpawnableAssetContainer.cpp
Prefab/Spawnable/PrefabCatchmentProcessor.h
@@ -730,6 +731,9 @@ set(FILES
Prefab/Spawnable/PrefabConversionPipeline.h
Prefab/Spawnable/PrefabConversionPipeline.cpp
Prefab/Spawnable/PrefabConverterStackProfileNames.h
Prefab/Spawnable/PrefabDocument.h
Prefab/Spawnable/PrefabDocument.inl
Prefab/Spawnable/PrefabDocument.cpp
Prefab/Spawnable/ProcesedObjectStore.h
Prefab/Spawnable/ProcesedObjectStore.cpp
Prefab/Spawnable/PrefabProcessor.h
@@ -0,0 +1,88 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <QObject>
#include <QWidget>
namespace UnitTest
{
class AzToolsFrameworkTestHelpersFixture : public AllocatorsTestFixture
{
public:
void SetUp() override
{
AllocatorsTestFixture::SetUp();
m_rootWidget = AZStd::make_unique<QWidget>();
m_rootWidget->setFixedSize(0, 0);
m_rootWidget->setMouseTracking(true);
m_rootWidget->move(0, 0); // explicitly set the widget to be in the upper left corner
m_mouseMoveDetector = AZStd::make_unique<MouseMoveDetector>();
m_rootWidget->installEventFilter(m_mouseMoveDetector.get());
}
void TearDown() override
{
m_rootWidget->removeEventFilter(m_mouseMoveDetector.get());
m_rootWidget.reset();
m_mouseMoveDetector.reset();
AllocatorsTestFixture::TearDown();
}
AZStd::unique_ptr<QWidget> m_rootWidget;
AZStd::unique_ptr<MouseMoveDetector> m_mouseMoveDetector;
};
struct MouseMoveParams
{
QSize m_widgetSize;
QPoint m_widgetPosition;
QPoint m_localCursorPosition;
QPoint m_cursorDelta;
};
class MouseMoveAzToolsFrameworkTestHelperFixture
: public AzToolsFrameworkTestHelpersFixture
, public ::testing::WithParamInterface<MouseMoveParams>
{
};
TEST_P(MouseMoveAzToolsFrameworkTestHelperFixture, MouseMoveCorrectlyTransformsCursorPositionInGlobalAndLocalSpace)
{
// given
const MouseMoveParams mouseMoveParams = GetParam();
m_rootWidget->move(mouseMoveParams.m_widgetPosition);
m_rootWidget->setFixedSize(mouseMoveParams.m_widgetSize);
// when
MouseMove(m_rootWidget.get(), mouseMoveParams.m_localCursorPosition, mouseMoveParams.m_cursorDelta);
// then
const QPoint mouseLocalPosition = m_mouseMoveDetector->m_mouseLocalPosition;
const QPoint mouseLocalPositionFromGlobal = m_rootWidget->mapFromGlobal(m_mouseMoveDetector->m_mouseGlobalPosition);
const QPoint expectedPosition = mouseMoveParams.m_localCursorPosition + mouseMoveParams.m_cursorDelta;
using ::testing::Eq;
EXPECT_THAT(mouseLocalPosition.x(), Eq(expectedPosition.x()));
EXPECT_THAT(mouseLocalPosition.y(), Eq(expectedPosition.y()));
EXPECT_THAT(mouseLocalPositionFromGlobal.x(), Eq(expectedPosition.x()));
EXPECT_THAT(mouseLocalPositionFromGlobal.y(), Eq(expectedPosition.y()));
}
INSTANTIATE_TEST_CASE_P(
All,
MouseMoveAzToolsFrameworkTestHelperFixture,
testing::Values(
MouseMoveParams{ QSize(100, 100), QPoint(0, 0), QPoint(0, 0), QPoint(10, 10) },
MouseMoveParams{ QSize(100, 100), QPoint(100, 100), QPoint(0, 0), QPoint(10, 10) },
MouseMoveParams{ QSize(100, 100), QPoint(20, 20), QPoint(50, 50), QPoint(20, 20) }));
} // namespace UnitTest
@@ -25,7 +25,7 @@ namespace Benchmark
for (auto _ : state)
{
state.PauseTiming();
m_spawnTicket = new AzFramework::EntitySpawnTicket(m_spawnableAsset);
m_spawnTicket = aznew AzFramework::EntitySpawnTicket(m_spawnableAsset);
state.ResumeTiming();
for (uint64_t spwanableCounter = 0; spwanableCounter < spawnAllEntitiesCallCount; spwanableCounter++)
@@ -62,7 +62,7 @@ namespace Benchmark
for (auto _ : state)
{
state.PauseTiming();
m_spawnTicket = new AzFramework::EntitySpawnTicket(m_spawnableAsset);
m_spawnTicket = aznew AzFramework::EntitySpawnTicket(m_spawnableAsset);
state.ResumeTiming();
AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(*m_spawnTicket);
@@ -93,15 +93,16 @@ namespace Benchmark
SetUpSpawnableAsset(entityCountInSpawnable);
auto spawner = AzFramework::SpawnableEntitiesInterface::Get();
for (auto _ : state)
{
state.PauseTiming();
m_spawnTicket = new AzFramework::EntitySpawnTicket(m_spawnableAsset);
m_spawnTicket = aznew AzFramework::EntitySpawnTicket(m_spawnableAsset);
state.ResumeTiming();
for (uint64_t spawnCallCounter = 0; spawnCallCounter < spawnCallCount; spawnCallCounter++)
{
AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(*m_spawnTicket);
spawner->SpawnAllEntities(*m_spawnTicket);
}
m_rootSpawnableInterface->ProcessSpawnableQueue();
@@ -9,6 +9,7 @@
#include <Prefab/SpawnableRemoveEditorInfoTestFixture.h>
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
#include <AzToolsFramework/Prefab/Spawnable/PrefabDocument.h>
#include <AzToolsFramework/ToolsComponents/EditorOnlyEntityComponent.h>
#include <AzToolsFramework/ToolsComponents/EditorOnlyEntityComponentBus.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
@@ -201,15 +202,14 @@ namespace UnitTest
{
ConvertSourceEntitiesToPrefab();
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabDocument prefab("Test");
prefab.SetPrefabDom(m_prefabDom);
const bool actualResult =
m_editorInfoRemover.RemoveEditorInfo(m_prefabDom, m_serializeContext, m_prefabProcessorContext).IsSuccess();
m_editorInfoRemover.RemoveEditorInfo(prefab, m_serializeContext, m_prefabProcessorContext).IsSuccess();
EXPECT_EQ(expectedResult, actualResult);
AZStd::unique_ptr<Instance> convertedInstance(aznew Instance());
ASSERT_TRUE(AzToolsFramework::Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(*convertedInstance, m_prefabDom));
convertedInstance->DetachAllEntitiesInHierarchy(
prefab.GetInstance().DetachAllEntitiesInHierarchy(
[this](AZStd::unique_ptr<AZ::Entity> entity)
{
m_runtimeEntities.emplace_back(entity.release());
@@ -12,6 +12,7 @@ set(FILES
AssetFileInfoListComparison.cpp
AssetSeedManager.cpp
AssetSystemMocks.h
AzToolsFrameworkTestHelpersTest.cpp
BoundsTestComponent.cpp
BoundsTestComponent.h
ComponentAdapterTests.cpp
@@ -8,4 +8,4 @@
#pragma once
#define AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS false
#define AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS true
@@ -7,4 +7,4 @@
*/
#pragma once
#define AWSCORE_BACKWARD_INCOMPATIBLE_CHANGE 0
#define AWSCORE_BACKWARD_INCOMPATIBLE_CHANGE 1
@@ -17,7 +17,7 @@ struct VSInput
struct VSDepthOutput
{
float4 m_position : SV_Position;
precise float4 m_position : SV_Position;
};
VSDepthOutput DepthPassVS(VSInput IN)
@@ -150,7 +150,7 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex)
float4 encodedNormal = PassSrg::m_normal.Load(screenCoords, sampleIndex);
float3 normal = DecodeNormalSignedOctahedron(encodedNormal.rgb);
float4 albedo = PassSrg::m_albedo.Load(screenCoords, sampleIndex);
float probeIrradianceBlendWeight = PassSrg::m_downsampledProbeIrradiance.Load(probeIrradianceCoords, sampleIndex).a;
float probeIrradianceBlendWeight = saturate(PassSrg::m_downsampledProbeIrradiance.Load(probeIrradianceCoords, sampleIndex).a);
float3 diffuse = float3(0.0f, 0.0f, 0.0f);
if (probeIrradianceBlendWeight > 0.0f)
@@ -102,8 +102,17 @@ namespace AZ
void DiffuseProbeGrid::SetProbeSpacing(const AZ::Vector3& probeSpacing)
{
// remove previous spacing from the render extents
m_renderExtents -= m_probeSpacing;
// update probe spacing
m_probeSpacing = probeSpacing;
// expand the extents by one probe spacing unit in order to blend properly around the edges of the volume
m_renderExtents += m_probeSpacing;
m_obbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_renderExtents / 2.0f);
// recompute the number of probes since the spacing changed
UpdateProbeCount();
@@ -128,7 +137,8 @@ namespace AZ
void DiffuseProbeGrid::SetTransform(const AZ::Transform& transform)
{
m_transform = transform;
m_obbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_extents / 2.0f);
m_obbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_renderExtents / 2.0f);
// probes need to be relocated since the grid position changed
m_remainingRelocationIterations = DefaultNumRelocationIterations;
@@ -144,11 +154,15 @@ namespace AZ
void DiffuseProbeGrid::SetExtents(const AZ::Vector3& extents)
{
m_extents = extents;
m_obbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_extents / 2.0f);
// recompute the number of probes since the extents changed
UpdateProbeCount();
// expand the extents by one probe spacing unit in order to blend properly around the edges of the volume
m_renderExtents = m_extents + m_probeSpacing;
m_obbWs = Obb::CreateFromPositionRotationAndHalfLengths(m_transform.GetTranslation(), m_transform.GetRotation(), m_renderExtents / 2.0f);
// probes need to be relocated since the grid extents changed
m_remainingRelocationIterations = DefaultNumRelocationIterations;
@@ -700,11 +714,11 @@ namespace AZ
RHI::ShaderInputImageIndex imageIndex;
constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_modelToWorld"));
AZ::Matrix3x4 modelToWorld = AZ::Matrix3x4::CreateFromTransform(m_transform) * AZ::Matrix3x4::CreateScale(m_extents);
AZ::Matrix3x4 modelToWorld = AZ::Matrix3x4::CreateFromTransform(m_transform) * AZ::Matrix3x4::CreateScale(m_renderExtents);
m_renderObjectSrg->SetConstant(constantIndex, modelToWorld);
constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_modelToWorldInverse"));
AZ::Matrix3x4 modelToWorldInverse = AZ::Matrix3x4::CreateFromTransform(m_transform).GetInverseFull();
AZ::Matrix3x4 modelToWorldInverse = modelToWorld.GetInverseFull();
m_renderObjectSrg->SetConstant(constantIndex, modelToWorldInverse);
constantIndex = srgLayout->FindShaderInputConstantIndex(Name("m_obbHalfLengths"));
@@ -183,11 +183,14 @@ namespace AZ
// extents of the probe grid
AZ::Vector3 m_extents = AZ::Vector3(0.0f, 0.0f, 0.0f);
// expanded extents for rendering the volume
AZ::Vector3 m_renderExtents = AZ::Vector3(0.0f, 0.0f, 0.0f);
// probe grid OBB (world space), built from transform and extents
AZ::Obb m_obbWs;
// per-axis spacing of probes in the grid
AZ::Vector3 m_probeSpacing;
AZ::Vector3 m_probeSpacing = AZ::Vector3(0.0f, 0.0f, 0.0f);
// per-axis number of probes in the grid
uint32_t m_probeCountX = 0;
@@ -6,6 +6,6 @@
#
#
set(ATOM_RHI_TRAIT_BUILD_SUPPORTS_TEST TRUE)
set(ATOM_RHI_TRAIT_BUILD_SUPPORTS_TEST FALSE)
set(ATOM_RHI_TRAIT_BUILD_SUPPORTS_EDIT TRUE)
set(PAL_TRAIT_BUILD_RENDERDOC_SUPPORTED FALSE)
@@ -348,14 +348,7 @@ namespace AZ::AtomBridge
void AtomDebugDisplayViewportInterface::SetAlpha(float a)
{
m_rendState.m_color.SetA(a);
if (a < 1.0f)
{
m_rendState.m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Opaque;
}
else
{
m_rendState.m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Translucent;
}
m_rendState.m_opacityType = a < 1.0f ? AZ::RPI::AuxGeomDraw::OpacityType::Translucent : AZ::RPI::AuxGeomDraw::OpacityType::Opaque;
}
void AtomDebugDisplayViewportInterface::DrawQuad(
@@ -20,11 +20,10 @@
namespace Multiplayer
{
using AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessor;
using AzToolsFramework::Prefab::PrefabConversionUtils::ProcessedObjectStore;
void NetworkPrefabProcessor::Process(PrefabProcessorContext& context)
void NetworkPrefabProcessor::Process(AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context)
{
using AzToolsFramework::Prefab::PrefabConversionUtils::PrefabDocument;
IMultiplayerTools* mpTools = AZ::Interface<IMultiplayerTools>::Get();
if (mpTools)
{
@@ -33,11 +32,17 @@ namespace Multiplayer
AZ::DataStream::StreamType serializationFormat = GetAzSerializationFormat();
context.ListPrefabs([&context, serializationFormat](AZStd::string_view prefabName, PrefabDom& prefab) {
ProcessPrefab(context, prefabName, prefab, serializationFormat);
});
bool networkPrefabsAdded = false;
context.ListPrefabs(
[&networkPrefabsAdded, &context, serializationFormat](PrefabDocument& prefab)
{
if (ProcessPrefab(context, prefab, serializationFormat))
{
networkPrefabsAdded = true;
}
});
if (mpTools && !context.GetProcessedObjects().empty())
if (mpTools && networkPrefabsAdded)
{
mpTools->SetDidProcessNetworkPrefabs(true);
}
@@ -59,28 +64,6 @@ namespace Multiplayer
}
}
static AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> LoadInstanceFromPrefab(const PrefabDom& prefab)
{
using namespace AzToolsFramework::Prefab;
// convert Prefab DOM into Prefab Instance.
AZStd::unique_ptr<Instance> sourceInstance(aznew Instance());
if (!PrefabDomUtils::LoadInstanceFromPrefabDom(*sourceInstance, prefab, PrefabDomUtils::LoadFlags::AssignRandomEntityId))
{
PrefabDomValueConstReference sourceReference = PrefabDomUtils::FindPrefabDomValue(prefab, PrefabDomUtils::SourceName);
AZStd::string errorMessage("NetworkPrefabProcessor: Failed to Load Prefab Instance from given Prefab Dom.");
if (sourceReference.has_value() && sourceReference->get().IsString() && sourceReference->get().GetStringLength() != 0)
{
AZStd::string_view source(sourceReference->get().GetString(), sourceReference->get().GetStringLength());
errorMessage += AZStd::string::format("Prefab Source: %.*s", AZ_STRING_ARG(source));
}
AZ_Error("NetworkPrefabProcessor", false, errorMessage.c_str());
return nullptr;
}
return sourceInstance;
}
static void GatherNetEntities(
AzToolsFramework::Prefab::Instance* instance,
AZStd::unordered_map<AZ::Entity*, AzToolsFramework::Prefab::Instance*>& entityToInstanceMap,
@@ -103,18 +86,15 @@ namespace Multiplayer
});
}
void NetworkPrefabProcessor::ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab, AZ::DataStream::StreamType serializationFormat)
bool NetworkPrefabProcessor::ProcessPrefab(
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context,
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabDocument& prefab,
AZ::DataStream::StreamType serializationFormat)
{
using AzToolsFramework::Prefab::PrefabConversionUtils::ProcessedObjectStore;
using namespace AzToolsFramework::Prefab;
// convert Prefab DOM into Prefab Instance.
AZStd::unique_ptr<Instance> sourceInstance = LoadInstanceFromPrefab(prefab);
if (!sourceInstance)
{
return;
}
AZStd::string uniqueName = prefabName;
AZStd::string uniqueName = prefab.GetName();
uniqueName += ".network.spawnable";
auto serializer = [serializationFormat](AZStd::vector<uint8_t>& output, const ProcessedObjectStore& object) -> bool {
@@ -127,15 +107,16 @@ namespace Multiplayer
ProcessedObjectStore::Create<AzFramework::Spawnable>(uniqueName, context.GetSourceUuid(), AZStd::move(serializer));
auto& netSpawnableEntities = networkSpawnable->GetEntities();
Instance& sourceInstance = prefab.GetInstance();
// Grab all net entities with their corresponding Instances to handle nested prefabs correctly
AZStd::unordered_map<AZ::Entity*, AzToolsFramework::Prefab::Instance*> netEntityToInstanceMap;
AZStd::vector<AZ::Entity*> prefabNetEntities;
GatherNetEntities(sourceInstance.get(), netEntityToInstanceMap, prefabNetEntities);
GatherNetEntities(&sourceInstance, netEntityToInstanceMap, prefabNetEntities);
if (prefabNetEntities.empty())
{
// No networked entities in the prefab, no need to do anything in this processor.
return;
return false;
}
// Sort the entities prior to processing. The entities will end up in the net spawnable in this order.
@@ -182,7 +163,7 @@ namespace Multiplayer
// Add net spawnable asset holder to the prefab root
{
EntityOptionalReference containerEntityRef = sourceInstance->GetContainerEntity();
EntityOptionalReference containerEntityRef = sourceInstance.GetContainerEntity();
if (containerEntityRef.has_value())
{
auto* networkSpawnableHolderComponent = containerEntityRef.value().get().CreateComponent<NetworkSpawnableHolderComponent>();
@@ -193,18 +174,12 @@ namespace Multiplayer
AZ::Entity* networkSpawnableHolderEntity = aznew AZ::Entity(uniqueName);
auto* networkSpawnableHolderComponent = networkSpawnableHolderEntity->CreateComponent<NetworkSpawnableHolderComponent>();
networkSpawnableHolderComponent->SetNetworkSpawnableAsset(networkSpawnableAsset);
sourceInstance->AddEntity(*networkSpawnableHolderEntity);
sourceInstance.AddEntity(*networkSpawnableHolderEntity);
}
}
// save the final result in the target Prefab DOM.
if (!PrefabDomUtils::StoreInstanceInPrefabDom(*sourceInstance, prefab))
{
AZ_Error("NetworkPrefabProcessor", false, "Saving exported Prefab Instance within a Prefab Dom failed.");
return;
}
context.GetProcessedObjects().push_back(AZStd::move(object));
return true;
}
AZ::DataStream::StreamType NetworkPrefabProcessor::GetAzSerializationFormat() const
@@ -14,23 +14,23 @@
namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
class PrefabProcessorContext;
class PrefabDocument;
}
namespace Multiplayer
{
using AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessor;
using AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext;
using AzToolsFramework::Prefab::PrefabDom;
class NetworkPrefabProcessor : public PrefabProcessor
class NetworkPrefabProcessor : public AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessor
{
public:
AZ_CLASS_ALLOCATOR(NetworkPrefabProcessor, AZ::SystemAllocator, 0);
AZ_RTTI(Multiplayer::NetworkPrefabProcessor, "{AF6C36DA-CBB9-4DF4-AE2D-7BC6CCE65176}", PrefabProcessor);
AZ_RTTI(
Multiplayer::NetworkPrefabProcessor,
"{AF6C36DA-CBB9-4DF4-AE2D-7BC6CCE65176}",
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessor);
~NetworkPrefabProcessor() override = default;
void Process(PrefabProcessorContext& context) override;
void Process(AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context) override;
static void Reflect(AZ::ReflectContext* context);
@@ -44,7 +44,10 @@ namespace Multiplayer
AZ::DataStream::StreamType GetAzSerializationFormat() const;
protected:
static void ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab, AZ::DataStream::StreamType serializationFormat);
static bool ProcessPrefab(
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context,
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabDocument& prefab,
AZ::DataStream::StreamType serializationFormat);
SerializationFormats m_serializationFormat = SerializationFormats::Binary;
};
@@ -57,6 +57,7 @@ namespace UnitTest
TEST_F(PrefabProcessingTestFixture, NetworkPrefabProcessor_ProcessPrefabTwoEntities_NetEntityGoesToNetSpawnable)
{
using AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext;
using AzToolsFramework::Prefab::PrefabConversionUtils::PrefabDocument;
AZStd::vector<AZ::Entity*> entities;
@@ -74,7 +75,9 @@ namespace UnitTest
// Add the prefab into the Prefab Processor Context
const AZStd::string prefabName = "testPrefab";
PrefabProcessorContext prefabProcessorContext{AZ::Uuid::CreateRandom()};
prefabProcessorContext.AddPrefab(prefabName, AZStd::move(prefabDom));
PrefabDocument document(prefabName);
ASSERT_TRUE(document.SetPrefabDom(AZStd::move(prefabDom)));
prefabProcessorContext.AddPrefab(AZStd::move(document));
// Request NetworkPrefabProcessor to process the prefab
Multiplayer::NetworkPrefabProcessor processor;
@@ -73,6 +73,7 @@ namespace PhysX::Utils::Characters
physx::PxMaterial* pxMaterial = static_cast<physx::PxMaterial*>(materials.front()->GetNativePointer());
controllerDesc.material = pxMaterial;
controllerDesc.position = PxMathConvertExtended(characterConfig.m_position);
controllerDesc.slopeLimit = cosf(AZ::DegToRad(characterConfig.m_maximumSlopeAngle));
controllerDesc.stepOffset = characterConfig.m_stepHeight;
controllerDesc.upDirection = characterConfig.m_upDirection.IsZero()
@@ -237,7 +237,7 @@ namespace AZ::Prefab
bool PrefabBuilderComponent::ProcessPrefab(
const AZ::PlatformTagSet& platformTags, const char* filePath, AZ::IO::PathView tempDirPath, const AZ::Uuid& sourceFileUuid,
AzToolsFramework::Prefab::PrefabDom& mutableRootDom, AZStd::vector<AssetBuilderSDK::JobProduct>& jobProducts)
AzToolsFramework::Prefab::PrefabDom&& rootDom, AZStd::vector<AssetBuilderSDK::JobProduct>& jobProducts)
{
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext context(sourceFileUuid);
AZStd::string rootPrefabName;
@@ -247,7 +247,9 @@ namespace AZ::Prefab
filePath);
return false;
}
context.AddPrefab(AZStd::move(rootPrefabName), AZStd::move(mutableRootDom));
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabDocument rootDocument(AZStd::move(rootPrefabName));
rootDocument.SetPrefabDom(AZStd::move(rootDom));
context.AddPrefab(AZStd::move(rootDocument));
context.SetPlatformTags(AZStd::move(platformTags));
@@ -319,8 +321,8 @@ namespace AZ::Prefab
});
if (ProcessPrefab(
platformTags, request.m_fullPath.c_str(), request.m_tempDirPath.c_str(), request.m_sourceFileUUID, mutableRootDom,
response.m_outputProducts))
platformTags, request.m_fullPath.c_str(), request.m_tempDirPath.c_str(), request.m_sourceFileUUID,
AZStd::move(mutableRootDom), response.m_outputProducts))
{
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
}
@@ -53,7 +53,7 @@ namespace AZ::Prefab
const AzToolsFramework::Prefab::PrefabDom& genericDocument);
bool ProcessPrefab(
const AZ::PlatformTagSet& platformTags, const char* filePath, AZ::IO::PathView tempDirPath, const AZ::Uuid& sourceFileUuid,
AzToolsFramework::Prefab::PrefabDom& mutableRootDom,
AzToolsFramework::Prefab::PrefabDom&& rootDom,
AZStd::vector<AssetBuilderSDK::JobProduct>& jobProducts);
protected:
@@ -106,7 +106,8 @@ namespace UnitTest
AzToolsFramework::Prefab::PrefabDom prefabDom;
prefabDom.CopyFrom(prefabSystemComponentInterface->FindTemplateDom(parentInstance->GetTemplateId()), prefabDom.GetAllocator(), false);
ASSERT_TRUE(prefabBuilderComponent.ProcessPrefab({AZ::Crc32("pc")}, "parent.prefab", "unused", AZ::Uuid(), prefabDom, jobProducts));
ASSERT_TRUE(prefabBuilderComponent.ProcessPrefab(
{ AZ::Crc32("pc") }, "parent.prefab", "unused", AZ::Uuid(), AZStd::move(prefabDom), jobProducts));
ASSERT_EQ(jobProducts.size(), 1);
ASSERT_EQ(jobProducts[0].m_dependencies.size(), 1);
@@ -246,6 +246,16 @@ namespace ScriptCanvasBuilder
}
}
void BuildVariableOverrides::SetHandlesToDescription()
{
m_source = m_source.Describe();
for (auto& dependency : m_dependencies)
{
dependency.SetHandlesToDescription();
}
}
ScriptCanvas::RuntimeDataOverrides ConvertToRuntime(const BuildVariableOverrides& buildOverrides)
{
ScriptCanvas::RuntimeDataOverrides runtimeOverrides;
@@ -38,6 +38,8 @@ namespace ScriptCanvasBuilder
// use this to initialize the new data, and make sure they have a editor graph variable for proper editor display
void PopulateFromParsedResults(ScriptCanvas::Grammar::AbstractCodeModelConstPtr abstractCodeModel, const ScriptCanvas::VariableData& variables);
void SetHandlesToDescription();
// #functions2 provide an identifier for the node/variable in the source that caused the dependency. the root will not have one.
ScriptCanvasEditor::SourceHandle m_source;
@@ -245,13 +245,13 @@ namespace ScriptCanvasEditor
void EditorScriptCanvasComponent::OpenEditor([[maybe_unused]] const AZ::Data::AssetId& assetId, const AZ::Data::AssetType&)
{
AzToolsFramework::OpenViewPane(LyViewPane::ScriptCanvas);
AZ::Outcome<int, AZStd::string> openOutcome = AZ::Failure(AZStd::string());
if (m_sourceHandle.IsDescriptionValid())
{
GeneralRequestBus::BroadcastResult(openOutcome, &GeneralRequests::OpenScriptCanvasAsset, m_sourceHandle, Tracker::ScriptCanvasFileState::UNMODIFIED, -1);
if (!openOutcome)
{
AZ_Warning("Script Canvas", openOutcome, "%s", openOutcome.GetError().data());
@@ -261,7 +261,7 @@ namespace ScriptCanvasEditor
{
AzToolsFramework::EntityIdList selectedEntityIds;
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities);
// Going to bypass the multiple selected entities flow for right now.
if (selectedEntityIds.size() == 1)
{
@@ -279,7 +279,7 @@ namespace ScriptCanvasEditor
void EditorScriptCanvasComponent::InitializeSource(const SourceHandle& sourceHandle)
{
m_sourceHandle = sourceHandle;
m_sourceHandle = sourceHandle.Describe();
}
//=========================================================================
@@ -345,6 +345,7 @@ namespace ScriptCanvasEditor
}
m_variableOverrides = parseOutcome.TakeValue();
m_variableOverrides.SetHandlesToDescription();
m_runtimeDataIsValid = true;
}
@@ -373,13 +374,7 @@ namespace ScriptCanvasEditor
void EditorScriptCanvasComponent::SetPrimaryAsset(const AZ::Data::AssetId& assetId)
{
m_sourceHandle = SourceHandle(nullptr, assetId.m_guid, {});
auto completeAsset = CompleteDescription(m_sourceHandle);
if (completeAsset)
{
m_sourceHandle = *completeAsset;
}
CompleteDescriptionInPlace(m_sourceHandle);
OnScriptCanvasAssetChanged(SourceChangeDescription::SelectionChanged);
SetName(m_sourceHandle.Path().Filename().Native());
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_AttributesAndValues);
@@ -399,7 +394,7 @@ namespace ScriptCanvasEditor
OnScriptCanvasAssetChanged(SourceChangeDescription::SelectionChanged);
return AZ::Edit::PropertyRefreshLevels::EntireTree;
}
void EditorScriptCanvasComponent::OnScriptCanvasAssetChanged(SourceChangeDescription changeDescription)
{
ScriptCanvas::GraphIdentifier newIdentifier = GetGraphIdentifier();
@@ -417,20 +412,11 @@ namespace ScriptCanvasEditor
ClearVariables();
}
m_sourceHandle = m_previousHandle;
if (m_sourceHandle.IsDescriptionValid())
{
if (!m_sourceHandle.Get())
{
if (auto loaded = LoadFromFile(m_sourceHandle.Path().c_str()); loaded.IsSuccess())
{
m_sourceHandle = SourceHandle(loaded.TakeValue(), m_sourceHandle.Id(), m_sourceHandle.Path().c_str());
}
}
if (m_sourceHandle.Get())
{
UpdatePropertyDisplay(m_sourceHandle);
}
UpdatePropertyDisplay();
}
AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent);
@@ -492,14 +478,11 @@ namespace ScriptCanvasEditor
return ScriptCanvas::GraphIdentifier(m_sourceHandle.Id(), 0);
}
void EditorScriptCanvasComponent::UpdatePropertyDisplay(const SourceHandle& sourceHandle)
void EditorScriptCanvasComponent::UpdatePropertyDisplay()
{
if (sourceHandle.IsGraphValid())
{
BuildGameEntityData();
UpdateName();
AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent);
}
BuildGameEntityData();
UpdateName();
AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent);
}
void EditorScriptCanvasComponent::ClearVariables()
@@ -121,7 +121,7 @@ namespace ScriptCanvasEditor
void UpdateName();
//=====================================================================
void UpdatePropertyDisplay(const SourceHandle& sourceHandle);
void UpdatePropertyDisplay();
//=====================================================================
void BuildGameEntityData();
@@ -0,0 +1,16 @@
{
"Amazon": {
"AssetProcessor": {
"Settings": {
// The terrain shader doesn't work on mac due to unbounded arrays, so disable problematic materials and material types
// in the terrain gem to prevent dependencies from failing.
"Exclude Terrain DefaultPbrTerrain.material": {
"pattern": "^Materials/Terrain/DefaultPbrTerrain.material"
},
"Exclude Terrain PbrTerrain.materialtype": {
"pattern": "^Materials/Terrain/PbrTerrain.materialtype"
}
}
}
}
}
@@ -342,7 +342,7 @@ namespace Vegetation
// Create the EntitySpawnTicket here. This pointer is going to get handed off to the vegetation system as opaque instance data,
// where it will be tracked and held onto for the lifetime of the vegetation instance. The vegetation system will pass it back
// in to DestroyInstance at the end of the lifetime, so that's the one place where we will delete the ticket pointers.
AzFramework::EntitySpawnTicket* ticket = new AzFramework::EntitySpawnTicket(m_spawnableAsset);
AzFramework::EntitySpawnTicket* ticket = aznew AzFramework::EntitySpawnTicket(m_spawnableAsset);
if (ticket->IsValid())
{
// Track the ticket that we've created.
+1 -1
View File
@@ -24,7 +24,7 @@ ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform
ly_associate_package(PACKAGE_NAME AWSGameLiftServerSDK-3.4.1-rev1-linux TARGETS AWSGameLiftServerSDK PACKAGE_HASH a8149a95bd100384af6ade97e2b21a56173740d921e6c3da8188cd51554d39af)
ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev3-linux TARGETS TIFF PACKAGE_HASH 2377f48b2ebc2d1628d9f65186c881544c92891312abe478a20d10b85877409a)
ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-linux TARGETS freetype PACKAGE_HASH 3f10c703d9001ecd2bb51a3bd003d3237c02d8f947ad0161c0252fdc54cbcf97)
ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev6-linux TARGETS AWSNativeSDK PACKAGE_HASH 490291e4c8057975c3ab86feb971b8a38871c58bac5e5d86abdd1aeb7141eec4)
ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.9.50-rev1-linux TARGETS AWSNativeSDK PACKAGE_HASH f30b6969c6732a7c1a23a59d205a150633a7f219dcb60d837b543888d2c63ea1)
ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-linux TARGETS Lua PACKAGE_HASH 1adc812abe3dd0dbb2ca9756f81d8f0e0ba45779ac85bf1d8455b25c531a38b0)
ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev5-linux TARGETS PhysX PACKAGE_HASH fa72365df409376aef02d1763194dc91d255bdfcb4e8febcfbb64d23a3e50b96)
ly_associate_package(PACKAGE_NAME mcpp-2.7.2_az.2-rev1-linux TARGETS mcpp PACKAGE_HASH df7a998d0bc3fedf44b5bdebaf69ddad6033355b71a590e8642445ec77bc6c41)
+5 -3
View File
@@ -38,7 +38,7 @@ def pipelineParameters = [
booleanParam(defaultValue: false, description: 'Recreates the volume used for the workspace. The volume will be created out of a snapshot taken from main.', name: 'RECREATE_VOLUME')
]
def palSh(cmd, lbl = '', winSlashReplacement = true) {
def palSh(cmd, lbl = '', winSlashReplacement = true, winCharReplacement = true) {
if (env.IS_UNIX) {
sh label: lbl,
script: cmd
@@ -46,7 +46,9 @@ def palSh(cmd, lbl = '', winSlashReplacement = true) {
if (winSlashReplacement) {
cmd = cmd.replace('/','\\')
}
cmd = cmd.replace('%', '%%')
if (winCharReplacement) {
cmd = cmd.replace('%', '%%')
}
bat label: lbl,
script: cmd
}
@@ -262,7 +264,7 @@ def CheckoutRepo(boolean disableSubmodules = false) {
commitDateFmt = '%%cI'
if (env.IS_UNIX) commitDateFmt = '%cI'
palSh("git show -s --format=${commitDateFmt} ${env.CHANGE_ID} > commitdate", 'Getting commit date')
palSh("git show -s --format=${commitDateFmt} ${env.CHANGE_ID} > commitdate", 'Getting commit date', winSlashReplacement=true, winCharReplacement=false)
env.CHANGE_DATE = readFile file: 'commitdate'
env.CHANGE_DATE = env.CHANGE_DATE.trim()
palRm('commitdate')
+20 -3
View File
@@ -14,7 +14,8 @@
],
"steps": [
"profile",
"asset_profile"
"asset_profile",
"test_profile"
]
},
"metrics": {
@@ -89,6 +90,22 @@
"ASSET_PROCESSOR_PLATFORMS": "mac"
}
},
"test_profile": {
"TAGS": [
"daily-pipeline-metrics",
"weekly-build-metrics"
],
"COMMAND": "build_test_mac.sh",
"PARAMETERS": {
"CONFIGURATION": "profile",
"OUTPUT_DIRECTORY": "build/mac",
"CMAKE_OPTIONS": "-G Xcode",
"CMAKE_LY_PROJECTS": "AutomatedTesting",
"CMAKE_TARGET": "ALL_BUILD",
"CTEST_OPTIONS": "-L (SUITE_smoke|SUITE_main) -LE (REQUIRES_gpu) --no-tests=error",
"TEST_RESULTS": "False"
}
},
"periodic_test_profile": {
"TAGS": [
"nightly-incremental",
@@ -102,7 +119,7 @@
"CMAKE_OPTIONS": "-G Xcode",
"CMAKE_LY_PROJECTS": "AutomatedTesting",
"CMAKE_TARGET": "TEST_SUITE_periodic",
"CTEST_OPTIONS": "-L \"(SUITE_periodic)\"",
"CTEST_OPTIONS": "-L (SUITE_periodic)",
"TEST_RESULTS": "False"
}
},
@@ -119,7 +136,7 @@
"CMAKE_OPTIONS": "-G Xcode",
"CMAKE_LY_PROJECTS": "AutomatedTesting",
"CMAKE_TARGET": "TEST_SUITE_benchmark",
"CTEST_OPTIONS": "-L \"(SUITE_benchmark)\"",
"CTEST_OPTIONS": "-L (SUITE_benchmark)",
"TEST_RESULTS": "False"
}
},
+2 -2
View File
@@ -48,7 +48,7 @@ if [[ ! -z "$RUN_CONFIGURE" ]]; then
echo "${CONFIGURE_CMD}" > ${LAST_CONFIGURE_CMD_FILE}
fi
echo [ci_build] cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(sysctl -n hw.ncpu) -- ${CMAKE_NATIVE_BUILD_ARGS}
cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(sysctl -n hw.ncpu) -- ${CMAKE_NATIVE_BUILD_ARGS}
echo [ci_build] cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(/usr/sbin/sysctl -n hw.ncpu) -- ${CMAKE_NATIVE_BUILD_ARGS}
cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(/usr/sbin/sysctl -n hw.ncpu) -- ${CMAKE_NATIVE_BUILD_ARGS}
popd
+3 -2
View File
@@ -19,8 +19,9 @@ fi
pushd $OUTPUT_DIRECTORY
# Find the CTEST_RUN_FLAGS from the CMakeCache.txt file, then replace the $<CONFIG> with the current configuration
IFS='=' read -ra CTEST_RUN_FLAGS <<< $(cmake -N -LA . | grep "CTEST_RUN_FLAGS:STRING")
CTEST_RUN_FLAGS=${CTEST_RUN_FLAGS[1]/$<CONFIG>/${CONFIGURATION}}
CTEST_RUN_FLAGS=$(cmake -N -LA . | grep "CTEST_RUN_FLAGS:STRING")
CTEST_RUN_FLAGS=${CTEST_RUN_FLAGS/CTEST_RUN_FLAGS:STRING=/}
CTEST_RUN_FLAGS=${CTEST_RUN_FLAGS/$<CONFIG>/${CONFIGURATION}}
# Run ctest
echo [ci_build] ctest ${CTEST_RUN_FLAGS} ${CTEST_OPTIONS}
+12 -12
View File
@@ -17,7 +17,7 @@ endif()
# Tests
################################################################################
if(PAL_TRAIT_TEST_LYTESTTOOLS_SUPPORTED)
if(PAL_TRAIT_TEST_PYTEST_SUPPORTED)
foreach(suite_name ${LY_TEST_GLOBAL_KNOWN_SUITE_NAMES})
ly_add_pytest(
NAME pytest_sanity_${suite_name}_no_gpu
@@ -32,16 +32,16 @@ if(PAL_TRAIT_TEST_LYTESTTOOLS_SUPPORTED)
TEST_REQUIRES gpu
)
endforeach()
endif()
# add a custom test which makes sure that the test filtering works!
ly_add_test(
NAME cli_test_driver
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
TEST_COMMAND ${LY_PYTHON_CMD} ${CMAKE_CURRENT_LIST_DIR}/ctest_driver_test.py
-x ${CMAKE_CTEST_COMMAND}
--build-path ${CMAKE_BINARY_DIR}
TEST_LIBRARY pytest
)
# add a custom test which makes sure that the test filtering works!
ly_add_test(
NAME cli_test_driver
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
TEST_COMMAND ${LY_PYTHON_CMD} ${CMAKE_CURRENT_LIST_DIR}/ctest_driver_test.py
-x ${CMAKE_CTEST_COMMAND}
--build-path ${CMAKE_BINARY_DIR}
--config $<CONFIG>
TEST_LIBRARY pytest
)
endif()
+6 -3
View File
@@ -15,10 +15,10 @@ import sys
import argparse
from ctest_driver import SUITES_AND_DESCRIPTIONS
def main(build_path, ctest_executable):
def main(build_path, ctest_executable, config):
script_folder = os.path.dirname(__file__)
# -N prevents tests from running, just lists them:
base_args = [sys.executable, os.path.join(script_folder,'ctest_driver.py'), "--build-path", build_path, '-N']
base_args = [sys.executable, os.path.join(script_folder,'ctest_driver.py'), "--build-path", build_path, "--config", config, '-N']
if ctest_executable:
base_args.append("--ctest-executable")
base_args.append(ctest_executable)
@@ -77,7 +77,10 @@ if __name__ == '__main__':
parser.add_argument('-b', '--build-path',
required=True,
help="Path to a CMake build folder (generated by running cmake)")
parser.add_argument('-c', '--config',
required=True,
help="Configuration to run")
args = parser.parse_args()
sys.exit(main(args.build_path, args.ctest_executable))
sys.exit(main(args.build_path, args.ctest_executable, args.config))