mirror of
https://github.com/Theaninova/BeatLanguageMapper.git
synced 2026-04-21 03:48:53 +00:00
Mk2Rev1
various bugfixes and such. also bookmarks, temp song loaderm and undo overhaul with near complete multiplayer, but menu items disabled. i really wish i could split this into multiple commits, but i don't know how to work unreal.
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "WindowsFileUtilityPrivatePCH.h"
|
||||
#include "WFUFileListInterface.h"
|
||||
|
||||
|
||||
UWFUFileListInterface::UWFUFileListInterface(const class FObjectInitializer& PCIP)
|
||||
: Super(PCIP)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
#include "WindowsFileUtilityPrivatePCH.h"
|
||||
#include "WindowsFileUtilityFunctionLibrary.h"
|
||||
#include "WFUFileListLambdaDelegate.h"
|
||||
|
||||
UWFUFileListLambdaDelegate::UWFUFileListLambdaDelegate()
|
||||
{
|
||||
OnDoneCallback = nullptr;
|
||||
}
|
||||
|
||||
void UWFUFileListLambdaDelegate::SetOnDoneCallback(TFunction<void(const TArray<FString>&, const TArray<FString>&)> InOnDoneCallback)
|
||||
{
|
||||
OnDoneCallback = InOnDoneCallback;
|
||||
}
|
||||
|
||||
void UWFUFileListLambdaDelegate::OnListFileFound_Implementation(const FString& FileName, int32 ByteCount, const FString& FilePath)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void UWFUFileListLambdaDelegate::OnListDirectoryFound_Implementation(const FString& DirectoryName, const FString& FilePath)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void UWFUFileListLambdaDelegate::OnListDone_Implementation(const FString& DirectoryPath, const TArray<FString>& Files, const TArray<FString>& Folders)
|
||||
{
|
||||
if (OnDoneCallback != nullptr)
|
||||
{
|
||||
OnDoneCallback(Files, Folders);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Object.h"
|
||||
#include "WFUFileListLambdaDelegate.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class WINDOWSFILEUTILITY_API UWFUFileListLambdaDelegate : public UObject, public IWFUFileListInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UWFUFileListLambdaDelegate();
|
||||
public:
|
||||
void SetOnDoneCallback(TFunction<void(const TArray<FString>&, const TArray<FString>&)> InOnDoneCallback);
|
||||
|
||||
protected:
|
||||
//File List Interface
|
||||
|
||||
virtual void OnListFileFound_Implementation(const FString& FileName, int32 ByteCount, const FString& FilePath) override;
|
||||
virtual void OnListDirectoryFound_Implementation(const FString& DirectoryName, const FString& FilePath) override;
|
||||
virtual void OnListDone_Implementation(const FString& DirectoryPath, const TArray<FString>& Files, const TArray<FString>& Folders) override;
|
||||
|
||||
TFunction<void(const TArray<FString>&, const TArray<FString>&)> OnDoneCallback;
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "WindowsFileUtilityPrivatePCH.h"
|
||||
#include "WFUFolderWatchInterface.h"
|
||||
|
||||
|
||||
UWFUFolderWatchInterface::UWFUFolderWatchInterface(const class FObjectInitializer& PCIP)
|
||||
: Super(PCIP)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
#include "WindowsFileUtilityPrivatePCH.h"
|
||||
#include "WindowsFileUtilityFunctionLibrary.h"
|
||||
#include "WFUFolderWatchLambdaDelegate.h"
|
||||
|
||||
UWFUFolderWatchLambdaDelegate::UWFUFolderWatchLambdaDelegate()
|
||||
{
|
||||
OnFileChangedCallback = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void UWFUFolderWatchLambdaDelegate::SetOnFileChangedCallback(TFunction<void(FString, FString)> InOnFileChangedCallback)
|
||||
{
|
||||
OnFileChangedCallback = InOnFileChangedCallback;
|
||||
}
|
||||
|
||||
|
||||
void UWFUFolderWatchLambdaDelegate::OnFileChanged_Implementation(const FString& FileName, const FString& FilePath)
|
||||
{
|
||||
if (OnFileChangedCallback != nullptr)
|
||||
{
|
||||
OnFileChangedCallback(FileName, FilePath);
|
||||
}
|
||||
}
|
||||
|
||||
void UWFUFolderWatchLambdaDelegate::OnDirectoryChanged_Implementation(const FString& DirectoryName, const FString& DirectoryPath)
|
||||
{
|
||||
if (OnFileChangedCallback != nullptr)
|
||||
{
|
||||
OnFileChangedCallback(DirectoryName, DirectoryPath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Object.h"
|
||||
#include "WFUFolderWatchLambdaDelegate.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class WINDOWSFILEUTILITY_API UWFUFolderWatchLambdaDelegate : public UObject, public IWFUFolderWatchInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UWFUFolderWatchLambdaDelegate();
|
||||
public:
|
||||
void SetOnFileChangedCallback(TFunction<void(FString, FString)> InOnFileChangedCallback);
|
||||
|
||||
protected:
|
||||
TFunction<void(FString, FString)> OnFileChangedCallback;
|
||||
|
||||
//IWFUFolderWatchInterface
|
||||
virtual void OnFileChanged_Implementation(const FString& FileName, const FString& FilePath) override;
|
||||
virtual void OnDirectoryChanged_Implementation(const FString& DirectoryName, const FString& DirectoryPath) override;
|
||||
};
|
||||
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include "WindowsFileUtilityPrivatePCH.h"
|
||||
#include "WFULambdaRunnable.h"
|
||||
|
||||
uint64 WFULambdaRunnable::ThreadNumber = 0;
|
||||
|
||||
FQueuedThreadPool* WFULambdaRunnable::ThreadPool = nullptr;
|
||||
|
||||
WFULambdaRunnable::WFULambdaRunnable(TFunction< void()> InFunction)
|
||||
{
|
||||
FunctionPointer = InFunction;
|
||||
|
||||
FString threadStatGroup = FString::Printf(TEXT("FLambdaRunnable%d"), ThreadNumber++);
|
||||
Thread = NULL;
|
||||
Thread = FRunnableThread::Create(this, *threadStatGroup, 0, TPri_BelowNormal); //windows default = 8mb for thread, could specify more
|
||||
}
|
||||
|
||||
WFULambdaRunnable::~WFULambdaRunnable()
|
||||
{
|
||||
if (Thread == NULL)
|
||||
{
|
||||
delete Thread;
|
||||
Thread = NULL;
|
||||
}
|
||||
|
||||
ThreadPool->Destroy();
|
||||
}
|
||||
|
||||
//Run
|
||||
uint32 WFULambdaRunnable::Run()
|
||||
{
|
||||
if (FunctionPointer)
|
||||
FunctionPointer();
|
||||
|
||||
//UE_LOG(LogClass, Log, TEXT("FLambdaRunnable %d Run complete"), Number);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WFULambdaRunnable::Exit()
|
||||
{
|
||||
//UE_LOG(LogClass, Log, TEXT("FLambdaRunnable %d Exit"), Number);
|
||||
|
||||
//delete ourselves when we're done
|
||||
delete this;
|
||||
}
|
||||
|
||||
void WFULambdaRunnable::InitThreadPool(int32 NumberOfThreads)
|
||||
{
|
||||
if (ThreadPool == nullptr)
|
||||
{
|
||||
ThreadPool = FQueuedThreadPool::Allocate();
|
||||
int32 NumThreadsInThreadPool = NumberOfThreads;
|
||||
ThreadPool->Create(NumThreadsInThreadPool, 32 * 1024);
|
||||
}
|
||||
}
|
||||
|
||||
void WFULambdaRunnable::EnsureCompletion()
|
||||
{
|
||||
Thread->WaitForCompletion();
|
||||
}
|
||||
|
||||
WFULambdaRunnable* WFULambdaRunnable::RunLambdaOnBackGroundThread(TFunction< void()> InFunction)
|
||||
{
|
||||
if (FPlatformProcess::SupportsMultithreading())
|
||||
{
|
||||
//UE_LOG(LogClass, Log, TEXT("FLambdaRunnable RunLambdaBackGroundThread"));
|
||||
return new WFULambdaRunnable(InFunction);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IQueuedWork* WFULambdaRunnable::AddLambdaToQueue(TFunction< void()> InFunction)
|
||||
{
|
||||
if (ThreadPool == nullptr)
|
||||
{
|
||||
WFULambdaRunnable::InitThreadPool(FPlatformMisc::NumberOfIOWorkerThreadsToSpawn());
|
||||
}
|
||||
|
||||
if (ThreadPool)
|
||||
{
|
||||
return AsyncLambdaPool(*ThreadPool, InFunction);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool WFULambdaRunnable::RemoveLambdaFromQueue(IQueuedWork* Work)
|
||||
{
|
||||
if (ThreadPool)
|
||||
{
|
||||
return ThreadPool->RetractQueuedWork(Work);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FGraphEventRef WFULambdaRunnable::RunShortLambdaOnGameThread(TFunction< void()> InFunction)
|
||||
{
|
||||
return FFunctionGraphTask::CreateAndDispatchWhenReady(InFunction, TStatId(), nullptr, ENamedThreads::GameThread);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "WindowsFileUtilityPrivatePCH.h"
|
||||
|
||||
class FWindowsFileUtility : public IWindowsFileUtility
|
||||
{
|
||||
/** IModuleInterface implementation */
|
||||
virtual void StartupModule() override
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual void ShutdownModule() override
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_MODULE(IWindowsFileUtility, WindowsFileUtility)
|
||||
@@ -0,0 +1,414 @@
|
||||
#include "WindowsFileUtilityPrivatePCH.h"
|
||||
#include "WFUFolderWatchInterface.h"
|
||||
#include "WFUFileListInterface.h"
|
||||
#include "WindowsFileUtilityFunctionLibrary.h"
|
||||
|
||||
//static TMAP definition
|
||||
TMap<FString, TArray<FWatcher>> UWindowsFileUtilityFunctionLibrary::Watchers = TMap<FString, TArray<FWatcher>>();
|
||||
int TotalWatchers = 0;
|
||||
|
||||
UWindowsFileUtilityFunctionLibrary::UWindowsFileUtilityFunctionLibrary(const class FObjectInitializer& PCIP)
|
||||
: Super(PCIP)
|
||||
{
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
#include "AllowWindowsPlatformTypes.h"
|
||||
#include <shellapi.h>
|
||||
#include <Shlwapi.h>
|
||||
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
|
||||
bool UWindowsFileUtilityFunctionLibrary::DoesFileExist(const FString& FullPath)
|
||||
{
|
||||
return 0 != PathFileExistsW(*FullPath);
|
||||
}
|
||||
|
||||
bool UWindowsFileUtilityFunctionLibrary::MoveFileTo(const FString& From, const FString& To)
|
||||
{
|
||||
//Using windows api
|
||||
return 0 != MoveFileW(*From, *To);
|
||||
}
|
||||
|
||||
|
||||
bool UWindowsFileUtilityFunctionLibrary::CreateDirectoryAt(const FString& FullPath)
|
||||
{
|
||||
//Using windows api
|
||||
return 0 != CreateDirectoryW(*FullPath, NULL);
|
||||
}
|
||||
|
||||
bool UWindowsFileUtilityFunctionLibrary::DeleteFileAt(const FString& FullPath)
|
||||
{
|
||||
//Using windows api
|
||||
return 0 != DeleteFileW(*FullPath);
|
||||
}
|
||||
|
||||
bool UWindowsFileUtilityFunctionLibrary::DeleteEmptyFolder(const FString& FullPath)
|
||||
{
|
||||
//Using windows api
|
||||
return 0 != RemoveDirectoryW(*FullPath);
|
||||
}
|
||||
|
||||
bool IsSubPathOf(const FString& path, const FString& basePath)
|
||||
{
|
||||
return path.Contains(basePath);
|
||||
}
|
||||
|
||||
//Dangerous function not recommended to be exposed to blueprint
|
||||
bool UWindowsFileUtilityFunctionLibrary::DeleteFolderRecursively(const FString& FullPath)
|
||||
{
|
||||
//Only allow user to delete folders sub-class to game folder
|
||||
if (!IsSubPathOf(FullPath, FPaths::ProjectDir()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int len = _tcslen(*FullPath);
|
||||
TCHAR *pszFrom = new TCHAR[len + 2];
|
||||
wcscpy_s(pszFrom, len + 2, *FullPath);
|
||||
pszFrom[len] = 0;
|
||||
pszFrom[len + 1] = 0;
|
||||
|
||||
SHFILEOPSTRUCT fileop;
|
||||
fileop.hwnd = NULL; // no status display
|
||||
fileop.wFunc = FO_DELETE; // delete operation
|
||||
fileop.pFrom = pszFrom; // source file name as double null terminated string
|
||||
fileop.pTo = NULL; // no destination needed
|
||||
fileop.fFlags = FOF_NOCONFIRMATION | FOF_SILENT; // do not prompt the user
|
||||
|
||||
fileop.fAnyOperationsAborted = FALSE;
|
||||
fileop.lpszProgressTitle = NULL;
|
||||
fileop.hNameMappings = NULL;
|
||||
|
||||
int ret = SHFileOperation(&fileop);
|
||||
delete[] pszFrom;
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
void UWindowsFileUtilityFunctionLibrary::WatchFolder(const FString& FullPath, UObject* WatcherDelegate)
|
||||
{
|
||||
//Do we have an entry for this path?
|
||||
if (!Watchers.Contains(FullPath))
|
||||
{
|
||||
//Make an entry
|
||||
TArray<FWatcher> FreshList;
|
||||
Watchers.Add(FullPath, FreshList);
|
||||
Watchers[FullPath] = FreshList;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if we do do we already watch from this object?
|
||||
TArray<FWatcher>& PathWatchers = Watchers[FullPath];
|
||||
|
||||
for (auto Watcher : PathWatchers)
|
||||
{
|
||||
if (Watcher.Delegate == WatcherDelegate)
|
||||
{
|
||||
//Already accounted for
|
||||
UE_LOG(LogTemp, Warning, TEXT("UWindowsFileUtilityFunctionLibrary::WatchFolder Duplicate watcher ignored!"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Add to watchers
|
||||
FWatcher FreshWatcher;
|
||||
FreshWatcher.Delegate = WatcherDelegate;
|
||||
FreshWatcher.Path = FullPath;
|
||||
|
||||
const FWatcher* WatcherPtr = &FreshWatcher;
|
||||
|
||||
//fork this off to another process
|
||||
WFULambdaRunnable* Runnable = WFULambdaRunnable::RunLambdaOnBackGroundThread([FullPath, WatcherDelegate, WatcherPtr]()
|
||||
{
|
||||
UWindowsFileUtilityFunctionLibrary::WatchFolderOnBgThread(FullPath, WatcherPtr);
|
||||
});
|
||||
|
||||
FreshWatcher.Runnable = Runnable;
|
||||
|
||||
TArray<FWatcher>& PathWatchers = Watchers[FullPath];
|
||||
PathWatchers.Add(FreshWatcher);
|
||||
}
|
||||
|
||||
void UWindowsFileUtilityFunctionLibrary::StopWatchingFolder(const FString& FullPath, UObject* WatcherDelegate)
|
||||
{
|
||||
//Do we have an entry?
|
||||
if (!Watchers.Contains(FullPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//We have an entry for this path, remove our watcher
|
||||
TArray<FWatcher> PathWatchers = Watchers[FullPath];
|
||||
for (int i = 0; i < PathWatchers.Num();i++)
|
||||
{
|
||||
FWatcher& PathWatcher = PathWatchers[i];
|
||||
if (PathWatcher.Delegate == WatcherDelegate)
|
||||
{
|
||||
//Stop the runnable
|
||||
PathWatcher.ShouldRun = false;
|
||||
PathWatcher.Runnable->Stop();
|
||||
|
||||
//Remove the watcher and we're done
|
||||
PathWatchers.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UWindowsFileUtilityFunctionLibrary::ListContentsOfFolder(const FString& FullPath, UObject* Delegate)
|
||||
{
|
||||
//Longer than max path? throw error
|
||||
if (FullPath.Len() > MAX_PATH)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("UWindowsFileUtilityFunctionLibrary::ListContentsOfFolder Error, path too long, listing aborted."));
|
||||
return;
|
||||
}
|
||||
|
||||
WFULambdaRunnable* Runnable = WFULambdaRunnable::RunLambdaOnBackGroundThread([&FullPath, Delegate]()
|
||||
{
|
||||
WIN32_FIND_DATA ffd;
|
||||
LARGE_INTEGER filesize;
|
||||
HANDLE hFind = INVALID_HANDLE_VALUE;
|
||||
DWORD dwError = 0;
|
||||
|
||||
FString SearchPath = FullPath + TEXT("\\*");
|
||||
|
||||
hFind = FindFirstFile(*SearchPath, &ffd);
|
||||
|
||||
if (INVALID_HANDLE_VALUE == hFind)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("UWindowsFileUtilityFunctionLibrary::ListContentsOfFolder Error, invalid handle, listing aborted."));
|
||||
return;
|
||||
}
|
||||
|
||||
//Arrays to hold full information on Done
|
||||
TArray<FString> FileNames;
|
||||
TArray<FString> FolderNames;
|
||||
|
||||
//List loop, callback on game thread
|
||||
do
|
||||
{
|
||||
FString Name = FString(ffd.cFileName);
|
||||
FString ItemPath = FullPath + TEXT("\\") + Name;
|
||||
|
||||
//UE_LOG(LogTemp, Log, TEXT("Name: <%s>"), *Name);
|
||||
|
||||
if (Name.Equals(FString(TEXT("."))) ||
|
||||
Name.Equals(FString(TEXT(".."))) )
|
||||
{
|
||||
//ignore these first
|
||||
}
|
||||
//Folder
|
||||
else if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
FolderNames.Add(Name);
|
||||
WFULambdaRunnable::RunShortLambdaOnGameThread([Delegate, ItemPath, Name]
|
||||
{
|
||||
((IWFUFileListInterface*)Delegate)->Execute_OnListDirectoryFound((UObject*)Delegate, Name, ItemPath);
|
||||
});
|
||||
}
|
||||
//File
|
||||
else
|
||||
{
|
||||
FileNames.Add(Name);
|
||||
|
||||
filesize.LowPart = ffd.nFileSizeLow;
|
||||
filesize.HighPart = ffd.nFileSizeHigh;
|
||||
int32 TruncatedFileSize = filesize.QuadPart;
|
||||
|
||||
WFULambdaRunnable::RunShortLambdaOnGameThread([Delegate, ItemPath, Name, TruncatedFileSize]
|
||||
{
|
||||
((IWFUFileListInterface*)Delegate)->Execute_OnListFileFound((UObject*)Delegate, Name, TruncatedFileSize, ItemPath);
|
||||
});
|
||||
}
|
||||
|
||||
} while (FindNextFile(hFind, &ffd) != 0);
|
||||
|
||||
dwError = GetLastError();
|
||||
if (dwError != ERROR_NO_MORE_FILES)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("UWindowsFileUtilityFunctionLibrary::ListContentsOfFolder Error while listing."));
|
||||
return;
|
||||
}
|
||||
|
||||
FindClose(hFind);
|
||||
|
||||
//Done callback with full list of names found
|
||||
WFULambdaRunnable::RunShortLambdaOnGameThread([Delegate, FullPath, FileNames, FolderNames]
|
||||
{
|
||||
((IWFUFileListInterface*)Delegate)->Execute_OnListDone((UObject*)Delegate, FullPath, FileNames, FolderNames);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void UWindowsFileUtilityFunctionLibrary::ListContentsOfFolderToCallback(const FString& FullPath, TFunction<void(const TArray<FString>&, const TArray<FString>&)> OnListCompleteCallback)
|
||||
{
|
||||
UWFUFileListLambdaDelegate* LambdaDelegate = NewObject<UWFUFileListLambdaDelegate>();
|
||||
LambdaDelegate->SetOnDoneCallback(OnListCompleteCallback);
|
||||
|
||||
ListContentsOfFolder(FullPath, LambdaDelegate);
|
||||
}
|
||||
|
||||
void UWindowsFileUtilityFunctionLibrary::WatchFolderOnBgThread(const FString& FullPath, const FWatcher* WatcherPtr)
|
||||
{
|
||||
//mostly from https://msdn.microsoft.com/en-us/library/windows/desktop/aa365261(v=vs.85).aspx
|
||||
//call the delegate when the folder changes
|
||||
|
||||
//TODO: find out which file changed
|
||||
|
||||
DWORD dwWaitStatus;
|
||||
HANDLE dwChangeHandles[2];
|
||||
TCHAR lpDrive[4];
|
||||
TCHAR lpFile[_MAX_FNAME];
|
||||
TCHAR lpExt[_MAX_EXT];
|
||||
|
||||
//finding out about the notification
|
||||
FILE_NOTIFY_INFORMATION strFileNotifyInfo[1024];
|
||||
DWORD dwBytesReturned = 0;
|
||||
|
||||
_tsplitpath_s(*FullPath, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);
|
||||
lpDrive[2] = (TCHAR)'\\';
|
||||
lpDrive[3] = (TCHAR)'\0';
|
||||
|
||||
// Watch the directory for file creation and deletion.
|
||||
|
||||
dwChangeHandles[0] = FindFirstChangeNotification(
|
||||
*FullPath, // directory to watch
|
||||
TRUE, // watch the subtree
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE |
|
||||
FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE// watch for generic file changes
|
||||
); // watch last write or file size change
|
||||
|
||||
if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("\n ERROR: FindFirstChangeNotification function failed.\n"));
|
||||
//ExitProcess(GetLastError());
|
||||
}
|
||||
|
||||
// Watch the subtree for directory creation and deletion.
|
||||
|
||||
dwChangeHandles[1] = FindFirstChangeNotification(
|
||||
lpDrive, // directory to watch
|
||||
TRUE, // watch the subtree
|
||||
FILE_NOTIFY_CHANGE_DIR_NAME); // watch dir name changes
|
||||
|
||||
if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("\n ERROR: FindFirstChangeNotification function failed.\n"));
|
||||
//ExitProcess(GetLastError());
|
||||
}
|
||||
|
||||
// Make a final validation check on our handles.
|
||||
if ((dwChangeHandles[0] == NULL) || (dwChangeHandles[1] == NULL))
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("\n ERROR: Unexpected NULL from FindFirstChangeNotification.\n"));
|
||||
//ExitProcess(GetLastError());
|
||||
}
|
||||
const FString DrivePath = FString(lpDrive);
|
||||
FString FileString;
|
||||
FString DirectoryString;
|
||||
const UObject* WatcherDelegate = WatcherPtr->Delegate;
|
||||
|
||||
//Wait while the runnable pointer hasn't been set
|
||||
|
||||
TotalWatchers++;
|
||||
UE_LOG(LogTemp, Log, TEXT("\nStarting Watcher loop %d...\n"), TotalWatchers);
|
||||
|
||||
while (WatcherPtr->ShouldRun) //Watcher.Runnable->Finished == false
|
||||
{
|
||||
// Wait for notification.
|
||||
//UE_LOG(LogTemp, Log, TEXT("\nWaiting for notification...\n"));
|
||||
|
||||
dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,
|
||||
FALSE, INFINITE);
|
||||
|
||||
if (!WatcherPtr->ShouldRun)
|
||||
{
|
||||
UE_LOG(LogTemp, Log, TEXT("\nStop called while sleeping\n"));
|
||||
break;
|
||||
}
|
||||
if (!WatcherDelegate->IsValidLowLevel())
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("\nInvalid Watcher Delegate, exiting watch\n"));
|
||||
break;
|
||||
}
|
||||
|
||||
switch (dwWaitStatus)
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
|
||||
ReadDirectoryChangesW(dwChangeHandles[0], (LPVOID)&strFileNotifyInfo, sizeof(strFileNotifyInfo), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, &dwBytesReturned, NULL, NULL);
|
||||
//UE_LOG(LogTemp, Warning, TEXT("Received info about: %s"), strFileNotifyInfo->FileName);
|
||||
|
||||
FileString = FString(strFileNotifyInfo[0].FileNameLength, strFileNotifyInfo[0].FileName);
|
||||
|
||||
// A file was created, renamed, or deleted in the directory.
|
||||
// Refresh this directory and restart the notification.
|
||||
|
||||
|
||||
|
||||
WFULambdaRunnable::RunShortLambdaOnGameThread([FullPath, FileString, WatcherDelegate]()
|
||||
{
|
||||
if (WatcherDelegate->GetClass()->ImplementsInterface(UWFUFolderWatchInterface::StaticClass()))
|
||||
{
|
||||
FString FilePath = FString::Printf(TEXT("%s\\%s"), *FullPath, *FileString);
|
||||
((IWFUFolderWatchInterface*)WatcherDelegate)->Execute_OnFileChanged((UObject*)WatcherDelegate, FileString, FilePath);
|
||||
}
|
||||
});
|
||||
if (FindNextChangeNotification(dwChangeHandles[0]) == FALSE)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("\n ERROR: FindNextChangeNotification function failed.\n"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case WAIT_OBJECT_0 + 1:
|
||||
|
||||
// A directory was created, renamed, or deleted.
|
||||
// Refresh the tree and restart the notification.
|
||||
|
||||
ReadDirectoryChangesW(dwChangeHandles[1], (LPVOID)&strFileNotifyInfo, sizeof(strFileNotifyInfo), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, &dwBytesReturned, NULL, NULL);
|
||||
DirectoryString = FString(strFileNotifyInfo[0].FileNameLength, strFileNotifyInfo[0].FileName);
|
||||
|
||||
WFULambdaRunnable::RunShortLambdaOnGameThread([FullPath, WatcherDelegate, DirectoryString]()
|
||||
{
|
||||
if (WatcherDelegate->GetClass()->ImplementsInterface(UWFUFolderWatchInterface::StaticClass()))
|
||||
{
|
||||
FString ChangedDirectoryPath = FString::Printf(TEXT("%s\\%s"), *FullPath, *DirectoryString);
|
||||
((IWFUFolderWatchInterface*)WatcherDelegate)->Execute_OnDirectoryChanged((UObject*)WatcherDelegate, DirectoryString, ChangedDirectoryPath);
|
||||
}
|
||||
});
|
||||
if (FindNextChangeNotification(dwChangeHandles[1]) == FALSE)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("\n ERROR: FindNextChangeNotification function failed.\n"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case WAIT_TIMEOUT:
|
||||
|
||||
// A timeout occurred, this would happen if some value other
|
||||
// than INFINITE is used in the Wait call and no changes occur.
|
||||
// In a single-threaded environment you might not want an
|
||||
// INFINITE wait.
|
||||
|
||||
UE_LOG(LogTemp, Warning, TEXT("\nNo changes in the timeout period.\n"));
|
||||
break;
|
||||
|
||||
default:
|
||||
UE_LOG(LogTemp, Warning, TEXT("\n ERROR: Unhandled dwWaitStatus.\n"));
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TotalWatchers--;
|
||||
UE_LOG(LogTemp, Log, TEXT("\n Watcher loop stopped, total now: %d.\n"), TotalWatchers);
|
||||
}
|
||||
|
||||
#include "HideWindowsPlatformTypes.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CoreUObject.h"
|
||||
#include "EngineMinimal.h"
|
||||
|
||||
#include "IWindowsFileUtility.h"
|
||||
#include "WFULambdaRunnable.h"
|
||||
#include "WFUFileListInterface.h"
|
||||
#include "WFUFolderWatchInterface.h"
|
||||
Reference in New Issue
Block a user