Bigfoot / Sonarqube (push) Skipped
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang_asan (Unity Build: ON, Variant: game) (push) Failing after 21s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang_asan (Unity Build: ON, Variant: game) (push) Failing after 26s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang (Unity Build: OFF, Variant: game) (push) Failing after 26s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang (Unity Build: ON, Variant: game) (push) Failing after 17s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang (Unity Build: OFF, Variant: toolmode) (push) Failing after 26s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang (Unity Build: ON, Variant: toolmode) (push) Failing after 19s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang_asan (Unity Build: OFF, Variant: game) (push) Failing after 27s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang_asan (Unity Build: OFF, Variant: toolmode) (push) Failing after 28s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang_asan (Unity Build: ON, Variant: toolmode) (push) Failing after 24s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang (Unity Build: OFF, Variant: game) (push) Failing after 29s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang (Unity Build: ON, Variant: game) (push) Failing after 26s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang (Unity Build: OFF, Variant: toolmode) (push) Failing after 30s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang (Unity Build: ON, Variant: toolmode) (push) Failing after 30s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang_asan (Unity Build: OFF, Variant: game) (push) Failing after 35s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang (Unity Build: OFF, Variant: game) (push) Canceled after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang (Unity Build: OFF, Variant: toolmode) (push) Canceled after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang (Unity Build: ON, Variant: game) (push) Canceled after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang (Unity Build: ON, Variant: toolmode) (push) Canceled after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang_asan (Unity Build: OFF, Variant: game) (push) Canceled after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang_asan (Unity Build: OFF, Variant: toolmode) (push) Canceled after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang_asan (Unity Build: ON, Variant: game) (push) Canceled after 0s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang_asan (Unity Build: ON, Variant: toolmode) (push) Canceled after 0s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang_asan (Unity Build: ON, Variant: toolmode) (push) Canceled after 0s
Bigfoot / Clang Format Checks (push) Canceled after 0s
Bigfoot / Sonarqube (pull_request) Canceled after 0s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang_asan (Unity Build: OFF, Variant: toolmode) (push) Canceled after 13s
267 lines
10 KiB
C++
267 lines
10 KiB
C++
/*********************************************************************
|
|
* \file Sasquatch.cpp
|
|
*
|
|
* \author Romain BOULLARD
|
|
* \date August 2026
|
|
*********************************************************************/
|
|
#include <Engine/Sasquatch/Sasquatch.hpp>
|
|
|
|
#include <Engine/EngineAssertHandler.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
namespace Bigfoot
|
|
{
|
|
#if defined(BIGFOOT_TOOLMODE) || defined(BIGFOOT_BUILD_TESTS) || defined(BIGFOOT_BUILD_BENCHMARKS)
|
|
SasquatchWriter::SasquatchWriter(const File& p_file,
|
|
const std::uint64_t p_assetCount,
|
|
const std::size_t p_totalFlatbufferBytes,
|
|
const std::size_t p_totalHardReferencesBytes):
|
|
m_assetCount(p_assetCount),
|
|
m_currentDataOffset(sizeof(SasquatchHeader) + (m_assetCount * sizeof(SasquatchEntry))),
|
|
m_file(p_file,
|
|
sizeof(SasquatchHeader) + (m_assetCount * sizeof(SasquatchEntry)) + p_totalFlatbufferBytes +
|
|
p_totalHardReferencesBytes)
|
|
{
|
|
m_entries.reserve(m_assetCount);
|
|
|
|
SasquatchHeader header;
|
|
header.m_assetCount = m_assetCount;
|
|
|
|
std::memcpy(m_file.GetData().data(), &header, sizeof(SasquatchHeader));
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
SasquatchWriter::~SasquatchWriter()
|
|
{
|
|
ASSERT(EngineAssertHandler,
|
|
m_entries.size() == m_assetCount,
|
|
"SasquatchWriter expected {} assets, only {} were added",
|
|
m_assetCount,
|
|
m_entries.size());
|
|
|
|
m_file.Prefetch(sizeof(SasquatchHeader), m_entries.size() * sizeof(SasquatchEntry));
|
|
|
|
if (!m_entries.empty())
|
|
{
|
|
std::memcpy(m_file.GetData().data() + sizeof(SasquatchHeader),
|
|
m_entries.data(),
|
|
m_entries.size() * sizeof(SasquatchEntry));
|
|
}
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
void SasquatchWriter::WriteAsset(const UUID& p_uuid,
|
|
eastl::span<const std::byte> p_flatbuffer,
|
|
eastl::span<const UUID> p_hardReferences)
|
|
{
|
|
ASSERT(EngineAssertHandler,
|
|
m_entries.size() < m_assetCount,
|
|
"SasquatchWriter can only hold {} assets",
|
|
m_assetCount);
|
|
|
|
const std::size_t offset = m_currentDataOffset;
|
|
|
|
const eastl::span<std::byte> data = m_file.GetData();
|
|
ASSERT(EngineAssertHandler,
|
|
offset + p_flatbuffer.size() + (p_hardReferences.size() * UUID::UUID_BYTE_SIZE) <= data.size(),
|
|
"SasquatchWriter can only write {} bytes",
|
|
data.size());
|
|
|
|
const std::size_t writeEnd = offset + p_flatbuffer.size() + (p_hardReferences.size() * UUID::UUID_BYTE_SIZE);
|
|
if (writeEnd > m_prefetchedUpTo)
|
|
{
|
|
const std::size_t prefetchEnd = std::min(writeEnd + PREFETCH_BYTES, data.size());
|
|
m_file.Prefetch(m_prefetchedUpTo, prefetchEnd - m_prefetchedUpTo);
|
|
m_prefetchedUpTo = prefetchEnd;
|
|
}
|
|
|
|
SasquatchEntry entry;
|
|
std::memcpy(entry.m_uuid.data(), p_uuid.ToBytes().data(), UUID::UUID_BYTE_SIZE);
|
|
entry.m_assetOffset = offset;
|
|
entry.m_assetSize = p_flatbuffer.size();
|
|
entry.m_hardReferencesOffset = entry.m_assetOffset + entry.m_assetSize;
|
|
entry.m_hardReferencesSize = p_hardReferences.size() * UUID::UUID_BYTE_SIZE;
|
|
|
|
std::memcpy(data.data() + entry.m_assetOffset, p_flatbuffer.data(), entry.m_assetSize);
|
|
|
|
for (std::uint32_t i = 0; i < p_hardReferences.size(); ++i)
|
|
{
|
|
const std::span<const std::byte, UUID::UUID_BYTE_SIZE> rawUUID = p_hardReferences[i].ToBytes();
|
|
std::memcpy(data.data() + entry.m_hardReferencesOffset + (static_cast<std::size_t>(i) * UUID::UUID_BYTE_SIZE),
|
|
rawUUID.data(),
|
|
UUID::UUID_BYTE_SIZE);
|
|
}
|
|
|
|
m_currentDataOffset += entry.m_assetSize + entry.m_hardReferencesSize;
|
|
m_entries.push_back(entry);
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
Sasquatch::Sasquatch(const File& p_file):
|
|
m_file(p_file)
|
|
{
|
|
const eastl::span<const std::byte> data = m_file.GetData();
|
|
|
|
CRITICAL_ASSERT(EngineAssertHandler,
|
|
data.size() >= sizeof(SasquatchHeader),
|
|
"Sasquatch file {} is smaller than its header",
|
|
p_file.GetPath());
|
|
|
|
std::memcpy(&m_header, data.data(), sizeof(SasquatchHeader));
|
|
|
|
CRITICAL_ASSERT(EngineAssertHandler,
|
|
m_header.m_magic == SasquatchHeader::MAGIC,
|
|
"Sasquatch file {} has an invalid magic number (got {} / expected {})",
|
|
p_file.GetPath(),
|
|
m_header.m_magic,
|
|
SasquatchHeader::MAGIC);
|
|
CRITICAL_ASSERT(EngineAssertHandler,
|
|
m_header.m_version == SasquatchHeader::VERSION,
|
|
"Sasquatch file {} has an unsupported version (got {} / expected {})",
|
|
p_file.GetPath(),
|
|
m_header.m_version,
|
|
SasquatchHeader::VERSION);
|
|
|
|
CRITICAL_ASSERT(EngineAssertHandler,
|
|
data.size() >= sizeof(SasquatchHeader) + (m_header.m_assetCount * sizeof(SasquatchEntry)),
|
|
"Sasquatch file {} index is truncated (got {} / expected at least {})",
|
|
p_file.GetPath(),
|
|
data.size(),
|
|
sizeof(SasquatchHeader) + (m_header.m_assetCount * sizeof(SasquatchEntry)));
|
|
|
|
eastl::vector<SasquatchEntry> entries(m_header.m_assetCount);
|
|
if (!entries.empty())
|
|
{
|
|
std::memcpy(entries.data(), data.data() + sizeof(SasquatchHeader), entries.size() * sizeof(SasquatchEntry));
|
|
}
|
|
|
|
m_entries.reserve(m_header.m_assetCount);
|
|
for (const SasquatchEntry& entry: entries)
|
|
{
|
|
CRITICAL_ASSERT(EngineAssertHandler,
|
|
entry.m_assetOffset + entry.m_assetSize + entry.m_hardReferencesSize <= data.size(),
|
|
"Sasquatch file {} has an out-of-bounds asset entry",
|
|
p_file.GetPath());
|
|
|
|
m_entries.emplace(UUID {entry.m_uuid},
|
|
Entry {.m_assetOffset = entry.m_assetOffset,
|
|
.m_assetSize = entry.m_assetSize,
|
|
.m_hardReferencesOffset = entry.m_hardReferencesOffset,
|
|
.m_hardReferencesSize = entry.m_hardReferencesSize});
|
|
}
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
const SasquatchHeader& Sasquatch::GetHeader() const
|
|
{
|
|
return m_header;
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
eastl::vector<std::byte> Sasquatch::GetAssetFlatbuffer(const UUID& p_uuid) const
|
|
{
|
|
const auto entryIt = m_entries.find(p_uuid);
|
|
if (entryIt == m_entries.end())
|
|
{
|
|
return {};
|
|
}
|
|
|
|
const eastl::span<const std::byte> data = m_file.GetData();
|
|
const eastl::span<const std::byte> bytes {data.data() + entryIt->second.m_assetOffset,
|
|
static_cast<std::size_t>(entryIt->second.m_assetSize)};
|
|
return eastl::vector<std::byte> {bytes.begin(), bytes.end()};
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
eastl::vector<eastl::vector<std::byte>> Sasquatch::GetAssetFlatbuffers(const eastl::span<const UUID> p_uuids) const
|
|
{
|
|
eastl::vector<eastl::vector<std::byte>> flatbuffers;
|
|
flatbuffers.reserve(p_uuids.size());
|
|
|
|
for (const UUID& uuid: p_uuids)
|
|
{
|
|
flatbuffers.push_back(GetAssetFlatbuffer(uuid));
|
|
}
|
|
|
|
return flatbuffers;
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
eastl::vector<UUID> Sasquatch::GetAssetHardReferences(const UUID& p_uuid) const
|
|
{
|
|
eastl::vector<UUID> hardReferences;
|
|
|
|
const auto entryIt = m_entries.find(p_uuid);
|
|
if (entryIt == m_entries.end())
|
|
{
|
|
return hardReferences;
|
|
}
|
|
|
|
const eastl::span<const std::byte> data = m_file.GetData();
|
|
const eastl::span<const std::byte> bytes {data.data() + entryIt->second.m_hardReferencesOffset,
|
|
static_cast<std::size_t>(entryIt->second.m_hardReferencesSize)};
|
|
|
|
const std::size_t hardReferenceCount = bytes.size() / UUID::UUID_BYTE_SIZE;
|
|
hardReferences.reserve(hardReferenceCount);
|
|
|
|
for (std::size_t i = 0; i < hardReferenceCount; ++i)
|
|
{
|
|
std::array<std::byte, UUID::UUID_BYTE_SIZE> rawUUID;
|
|
std::memcpy(rawUUID.data(), bytes.data() + (i * UUID::UUID_BYTE_SIZE), UUID::UUID_BYTE_SIZE);
|
|
hardReferences.emplace_back(rawUUID);
|
|
}
|
|
|
|
return hardReferences;
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
eastl::vector<eastl::vector<UUID>> Sasquatch::GetAssetsHardReferences(eastl::span<const UUID> p_uuids) const
|
|
{
|
|
eastl::vector<eastl::vector<UUID>> hardReferences;
|
|
hardReferences.reserve(p_uuids.size());
|
|
|
|
for (const UUID& uuid: p_uuids)
|
|
{
|
|
hardReferences.push_back(GetAssetHardReferences(uuid));
|
|
}
|
|
|
|
return hardReferences;
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
void Sasquatch::SaveAssetFlatbuffer([[maybe_unused]] const UUID& p_uuid,
|
|
[[maybe_unused]] eastl::span<const std::byte> p_flatbuffer,
|
|
[[maybe_unused]] eastl::span<const UUID> p_hardReferences)
|
|
{
|
|
ASSERT(EngineAssertHandler, false, "Sasquatch is read-only, it cannot save assets");
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
void Sasquatch::SaveAssetFlatbuffers([[maybe_unused]] const eastl::span<const UUID> p_uuids,
|
|
[[maybe_unused]] eastl::span<const eastl::vector<std::byte>> p_flatbuffers,
|
|
[[maybe_unused]] eastl::span<const eastl::vector<UUID>> p_hardReferences)
|
|
{
|
|
ASSERT(EngineAssertHandler, false, "Sasquatch is read-only, it cannot save assets");
|
|
}
|
|
|
|
/****************************************************************************************/
|
|
|
|
bool Sasquatch::Has(const UUID& p_uuid) const
|
|
{
|
|
return m_entries.contains(p_uuid);
|
|
}
|
|
#endif
|
|
} // namespace Bigfoot
|