Files
o3de/Code/Editor/EditorFileMonitor.cpp
T
lumberyard-employee-dm f648cb1fd8 Update the FileIO Aliases (#4186)
* Update the FileIOAlias naming to make the cache, project root and engine
root paths more clear

The alias of `@root@`, `@assets@`, and `@projectplatformcache@` has been
collapsed to `@projectproductassets@`

The alias of `@devroot@` and `@engroot@` has been collapsed to
`@engroot@`

The alias of `@devassets@` and `@projectroot@` has been collapsed to
`@projectroot@`

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated use of devassets and devroot properties in python

Those properties now use projectroot and engroot

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updating the alias @engroot@ alias path comment in each platform specific LocalFileIO_*.cpp file

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Removed hardcoded size of 9 for the product asset alias.

The ResolvePath function now just appends the @projectproductassets@
alias with the input path

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Remove duplicate @projectproductassets@ check in ProcessFileTreeRequest

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Fix for typos in Hydra python test

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated LocalFileIO::Copy call on Windows to use the Unicode aware CopyFileW API

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated the AWSMetreicsGemAllocatorFixture to properly suppress asset
cache write errors for Test file creation.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Removed unneeded call to set the @projectproductasstes@ alias at the bottom of the AssetSeedManagerTest SetUp

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Added a deprecated alias map to the FileIO System

When a deprecated alias is accessed, the FileIO System logs an AZ_Error and indicates the alias that should be used

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated python test scripts to use the projectroot binding

Retrieving the AutomatedTesting project path based on "<devroot>/AutomatedTesting" has been removed.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated references to devroot and devgame within the codebase

The GetAbsoluteDevGameFolderPath functions has been replaced with direct call to AZ::Utils::GetProjectPath
The GetAbsoluteDevRootFolderPath functions has been replaced with direct calls to AZ::Utils::GetEnginePath

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated <engroot>/AutomatedTesting references to projectroot


Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Replaced references that assumes the project path is <engroot>/AutomatedTesting with <projectroot> in the AutomatedTesting python test

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Correct casing in emfxworkspace file


Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Removed newly added AppendPathParts function
Removed the Path constructors which accepts a PathIterable instance

The PathIterable isn't safe to return to a user of the Path class as it might be referencing temporary paths supplied via PathView arguments

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Fixed unused parameter warning

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Undid change to the LexicallyProximate function to set the path result to the base path.

It needs to return the *this path if the pathResult is empty

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Moved the LocalFileIO ConvertToAbsolutePath implementations to AZ::Utils

Fixed the ConvertToAbsolutePath implementation for Unix platforms to use a buffer that is size PATH_MAX(4096 on all our supported Unix platforms).
Because the buffer before was AZ::IO::MaxPathLength which as a size of 1024, this was resulting in the Unix `realpath` function smashing the stack when it converts a path to an absolute path that is longer than 1024 characters

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated the EditorCore.Tests to attach the AZ Environment to the EditorCore shared library that is statically loaded on launch.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Fixed for DeprecatedAlaisesKeyVisitor Visit function causing the non string_view overloads being hidden causing a hidden base class function warning

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Changed the AWSMetricsGemMock to use a temporary for writing test assets

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated the LocalFileIO::ResolvePath function to use HasRootPath to determine if a path starts with a root path such as "D:", "D:/" or "/"

IsAbsolute was not the corect check as the path of "D:" is a relative
path.
To be absolute according to the Windows the path must have a root
directory. i.e "D:/" or "D:\"

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Removed absolute path comment from LocalFile_UnixLike.cpp and LocalFile_Android.cpp FindFiles implementations
Updated the ConvertToAlias to supply an AZ::IO::FixedMaxPath

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Replaced usage of the @projectproductassets@ alias with @engroot@ when referring to the LmbrCentral source folder in the CopyDependencyBuilderTest and the SeedBuilderTests

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated the ScriptCanvas Upgrade Tool to output backed up files to the
Project User Path instead of the engine root

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Fixed whitespacing issues in Application.cpp

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Remove unnecessary creation of a FixedMaxPath in the UpgradeTool.cpp

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Modified testSeedFolder variable in the SeedBuilderTests to use the
@engroot@ alias instead of @projectproductassets@/.. alias when
referring to the LmbrCentral Gem source path

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated references to the Project Asset Cache in the PythonTests.

Those tests no longer use the logic `azlmbr.paths.projectroot / "Cache" / "pc"` to retrieve a path to the cache root but instead the `azlmbr.paths.projectproductassets` constant

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Fixed the FileIO Deprecated Alias test on Windows

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Removing @projectsourceassets@ alias, as it is only used once.

Updated the PhysX EditorSystemComponent.cpp to query the ProjectPath
form the SettingsRegistry.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Replaced @projectproductassets@ alias with @products@

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Rollback changes to the PhysX EditorSystemComponent.cpp

The changes to use the ProjectPath from the SettingsRegistry has been implemented in PR #4497

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
2021-10-05 15:12:53 -05:00

215 lines
7.2 KiB
C++

/*
* 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 "EditorFileMonitor.h"
// Editor
#include "CryEdit.h"
#include <AzCore/Utils/Utils.h>
//////////////////////////////////////////////////////////////////////////
CEditorFileMonitor::CEditorFileMonitor()
{
GetIEditor()->RegisterNotifyListener(this);
}
//////////////////////////////////////////////////////////////////////////
CEditorFileMonitor::~CEditorFileMonitor()
{
CFileChangeMonitor::DeleteInstance();
}
//////////////////////////////////////////////////////////////////////////
void CEditorFileMonitor::OnEditorNotifyEvent(EEditorNotifyEvent ev)
{
if (ev == eNotify_OnInit)
{
// We don't want the file monitor to be enabled while
// in console mode...
if (!GetIEditor()->IsInConsolewMode())
{
MonitorDirectories();
}
CFileChangeMonitor::Instance()->Subscribe(this);
}
else if (ev == eNotify_OnQuit)
{
CFileChangeMonitor::Instance()->StopMonitor();
GetIEditor()->UnregisterNotifyListener(this);
}
}
//////////////////////////////////////////////////////////////////////////
bool CEditorFileMonitor::RegisterListener(IFileChangeListener* pListener, const char* sMonitorItem)
{
return RegisterListener(pListener, sMonitorItem, "*");
}
//////////////////////////////////////////////////////////////////////////
static AZStd::string CanonicalizePath(const char* path)
{
auto canon = QFileInfo(path).canonicalFilePath();
return canon.isEmpty() ? AZStd::string(path) : AZStd::string(canon.toUtf8());
}
//////////////////////////////////////////////////////////////////////////
bool CEditorFileMonitor::RegisterListener(IFileChangeListener* pListener, const char* sFolderRelativeToGame, const char* sExtension)
{
bool success = true;
AZStd::string gameFolder = Path::GetEditingGameDataFolder().c_str();
AZStd::string naivePath;
CFileChangeMonitor* fileChangeMonitor = CFileChangeMonitor::Instance();
AZ_Assert(fileChangeMonitor, "CFileChangeMonitor singleton missing.");
naivePath += gameFolder;
// Append slash in preparation for appending the second part.
naivePath = PathUtil::AddSlash(naivePath);
naivePath += sFolderRelativeToGame;
AZ::StringFunc::Replace(naivePath, '/', '\\');
// Remove the final slash if the given item is a folder so the file change monitor correctly picks up on it.
naivePath = PathUtil::RemoveSlash(naivePath);
AZStd::string canonicalizedPath = CanonicalizePath(naivePath.c_str());
if (fileChangeMonitor->IsDirectory(canonicalizedPath.c_str()) || fileChangeMonitor->IsFile(canonicalizedPath.c_str()))
{
if (fileChangeMonitor->MonitorItem(canonicalizedPath.c_str()))
{
m_vecFileChangeCallbacks.push_back(SFileChangeCallback(pListener, sFolderRelativeToGame, sExtension));
}
else
{
CryLogAlways("File Monitor: [%s] not found outside of PAK files. Monitoring disabled for this item", sFolderRelativeToGame);
success = false;
}
}
return success;
}
bool CEditorFileMonitor::UnregisterListener(IFileChangeListener* pListener)
{
bool bRet = false;
// Note that we remove the listener, but we don't currently remove the monitored item
// from the file monitor. This is fine, but inefficient
std::vector<SFileChangeCallback>::iterator iter = m_vecFileChangeCallbacks.begin();
while (iter != m_vecFileChangeCallbacks.end())
{
if (iter->pListener == pListener)
{
iter = m_vecFileChangeCallbacks.erase(iter);
bRet = true;
}
else
{
iter++;
}
}
return bRet;
}
//////////////////////////////////////////////////////////////////////////
void CEditorFileMonitor::MonitorDirectories()
{
QString primaryCD = Path::AddPathSlash(QString(GetIEditor()->GetPrimaryCDFolder()));
// NOTE: Instead of monitoring each sub-directory we monitor the whole root
// folder. This is needed since if the sub-directory does not exist when
// we register it it will never get monitored properly.
CFileChangeMonitor::Instance()->MonitorItem(QStringLiteral("%1/%2/").arg(primaryCD).arg(QString::fromLatin1(Path::GetEditingGameDataFolder().c_str())));
// Add editor directory for scripts
CFileChangeMonitor::Instance()->MonitorItem(QStringLiteral("%1/Editor/").arg(primaryCD));
}
QString RemoveGameName(const QString &filename)
{
// Remove first part of path. File coming in has the game name included
// eg (AutomatedTesting/Animations/Chicken/anim_chicken_flapping.i_caf)->(Animations/Chicken/anim_chicken_flapping.i_caf)
int indexOfFirstSlash = filename.indexOf('/');
int indexOfFirstBackSlash = filename.indexOf('\\');
if (indexOfFirstSlash >= 0)
{
if (indexOfFirstBackSlash >= 0 && indexOfFirstBackSlash < indexOfFirstSlash)
{
indexOfFirstSlash = indexOfFirstBackSlash;
}
}
else
{
indexOfFirstSlash = indexOfFirstBackSlash;
}
return filename.mid(indexOfFirstSlash + 1);
}
///////////////////////////////////////////////////////////////////////////
// Called when file monitor message is received
void CEditorFileMonitor::OnFileMonitorChange(const SFileChangeInfo& rChange)
{
CCryEditApp* app = CCryEditApp::instance();
if (app == nullptr || app->IsExiting())
{
return;
}
// skip folders!
if (QFileInfo(rChange.filename).isDir())
{
return;
}
// Process updated file.
// Make file relative to PrimaryCD folder.
QString filename = rChange.filename;
// Make path relative to the the project directory
AZ::IO::Path projectPath{ AZ::Utils::GetProjectPath() };
AZ::IO::FixedMaxPath projectRelativeFilePath = AZ::IO::PathView(filename.toUtf8().constData()).LexicallyProximate(
projectPath);
if (!projectRelativeFilePath.empty())
{
AZ::IO::PathView ext = projectRelativeFilePath.Extension();
// Check for File Monitor callback
std::vector<SFileChangeCallback>::iterator iter;
for (iter = m_vecFileChangeCallbacks.begin(); iter != m_vecFileChangeCallbacks.end(); ++iter)
{
SFileChangeCallback& sCallback = *iter;
// We compare against length of callback string, so we get directory matches as well as full filenames
if (sCallback.pListener)
{
if (sCallback.extension == "*" || AZ::IO::PathView(sCallback.extension.toUtf8().constData()) == ext)
{
if (AZ::IO::PathView(sCallback.item.toUtf8().constData()) == projectRelativeFilePath)
{
sCallback.pListener->OnFileChange(qPrintable(projectRelativeFilePath.c_str()), IFileChangeListener::EChangeType(rChange.changeType));
}
}
}
}
// Set this flag to make sure that the viewport will update at least once,
// so that the changes will be shown, even if the app does not have focus.
CCryEditApp::instance()->ForceNextIdleProcessing();
}
}