Files
XCEngine/editor/src/Core/ProjectAssetWatcher.h

90 lines
2.5 KiB
C++

#pragma once
#include "Core/IEditorContext.h"
#include <atomic>
#include <cstdint>
#include <filesystem>
#include <mutex>
#include <string>
#include <thread>
#include <unordered_map>
namespace XCEngine {
namespace Editor {
class ProjectAssetWatcher {
public:
~ProjectAssetWatcher();
void Attach(const std::string& projectPath);
void Detach();
void Update(IEditorContext& context, float dt);
private:
struct AssetEntryState {
bool isDirectory = false;
std::uint64_t fileSize = 0;
std::uint64_t writeTime = 0;
bool operator==(const AssetEntryState& other) const {
return isDirectory == other.isDirectory &&
fileSize == other.fileSize &&
writeTime == other.writeTime;
}
};
struct ChangeStats {
std::uint32_t added = 0;
std::uint32_t modified = 0;
std::uint32_t removed = 0;
bool HasChanges() const {
return added > 0 || modified > 0 || removed > 0;
}
void Clear() {
added = 0;
modified = 0;
removed = 0;
}
void Accumulate(const ChangeStats& other) {
added += other.added;
modified += other.modified;
removed += other.removed;
}
};
using Snapshot = std::unordered_map<std::string, AssetEntryState>;
void RefreshProjectBinding(const std::string& projectPath);
void StartNativeWatcher();
void StopNativeWatcher();
void RunNativeWatcher(void* directoryHandle, std::filesystem::path watchedRoot);
void ConsumeNativeChanges();
void ScheduleRefresh(const ChangeStats& changes);
void ScanForChanges();
void FlushPendingRefresh(IEditorContext& context);
static void BuildSnapshot(const std::filesystem::path& assetsRoot, Snapshot& outSnapshot);
static ChangeStats DiffSnapshots(const Snapshot& previousSnapshot, const Snapshot& currentSnapshot);
std::string m_projectPath;
std::filesystem::path m_assetsRoot;
Snapshot m_snapshot;
ChangeStats m_pendingChanges;
float m_scanCooldownSeconds = 0.0f;
float m_nativeRestartCooldownSeconds = 0.0f;
float m_debounceSeconds = 0.0f;
bool m_hasPendingRefresh = false;
std::thread m_nativeWatcherThread;
std::mutex m_nativeChangeMutex;
ChangeStats m_threadPendingChanges;
std::atomic<bool> m_nativeWatcherHealthy{false};
std::atomic<bool> m_pollingResyncRequested{false};
void* m_nativeStopEvent = nullptr;
};
} // namespace Editor
} // namespace XCEngine