Sasquatch
Bigfoot / Sonarqube (push) Skipped
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang (Unity Build: OFF, Variant: game) (push) Successful in 34s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang (Unity Build: ON, Variant: game) (push) Successful in 22s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang_asan (Unity Build: ON, Variant: game) (push) Successful in 44s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang_asan (Unity Build: OFF, Variant: toolmode) (push) Failing after 57s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang (Unity Build: OFF, Variant: game) (push) Successful in 34s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang (Unity Build: ON, Variant: game) (push) Successful in 23s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang (Unity Build: ON, Variant: game) (push) Failing after 15s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang (Unity Build: OFF, Variant: toolmode) (push) Failing after 14s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang_asan (Unity Build: OFF, Variant: game) (push) Failing after 21s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang (Unity Build: OFF, Variant: toolmode) (push) Successful in 34s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang (Unity Build: ON, Variant: toolmode) (push) Successful in 23s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang_asan (Unity Build: OFF, Variant: game) (push) Successful in 54s
Bigfoot / Build & Test Debug with ./ConanProfiles/host/clang_asan (Unity Build: ON, Variant: toolmode) (push) Failing after 46s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang (Unity Build: OFF, Variant: toolmode) (push) Successful in 38s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang (Unity Build: ON, Variant: toolmode) (push) Successful in 27s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang_asan (Unity Build: OFF, Variant: game) (push) Successful in 53s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang_asan (Unity Build: ON, Variant: game) (push) Successful in 42s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang_asan (Unity Build: OFF, Variant: toolmode) (push) Failing after 1m0s
Bigfoot / Build & Test RelWithDebInfo with ./ConanProfiles/host/clang_asan (Unity Build: ON, Variant: toolmode) (push) Failing after 47s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang (Unity Build: OFF, Variant: game) (push) Failing after 16s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang (Unity Build: ON, Variant: toolmode) (push) Failing after 16s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang_asan (Unity Build: ON, Variant: toolmode) (push) Failing after 21s
Bigfoot / Clang Format Checks (push) Successful in 11s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang_asan (Unity Build: ON, Variant: game) (push) Failing after 20s
Bigfoot / Build & Test Release with ./ConanProfiles/host/clang_asan (Unity Build: OFF, Variant: toolmode) (push) Failing after 15s

This commit is contained in:
2026-08-29 00:20:02 +02:00
parent 7804647768
commit f6cde4f025
28 changed files with 1230 additions and 38 deletions
+14 -10
View File
@@ -127,22 +127,26 @@ IncludeCategories:
Priority: 2
- Regex: '^<Utils/'
Priority: 3
- Regex: '^<EngineTests/'
- Regex: '^<SasquatchBaker/'
Priority: 4
- Regex: '^<SystemTests/'
- Regex: '^<EngineTests/'
Priority: 5
- Regex: '^<UtilsTests/'
- Regex: '^<SystemTests/'
Priority: 6
- Regex: '^<AssetsForTesting/'
- Regex: '^<UtilsTests/'
Priority: 7
- Regex: '^<EngineBenchmarks/'
- Regex: '^<AssetsForTesting/'
Priority: 8
- Regex: '^<AssetsForBenchmarking/'
- Regex: '^<SasquatchBakerTests/'
Priority: 9
- Regex: '^<[a-zA-Z0-9_/]+\.h>'
- Regex: '^<EngineBenchmarks/'
Priority: 10
- Regex: '^<[a-zA-Z0-9_/]+\.hpp>'
Priority: 10
- Regex: '^<[a-zA-Z0-9_/]+>'
- Regex: '^<AssetsForBenchmarking/'
Priority: 11
- Regex: '^<[a-zA-Z0-9_/]+\.h>'
Priority: 12
- Regex: '^<[a-zA-Z0-9_/]+\.hpp>'
Priority: 12
- Regex: '^<[a-zA-Z0-9_/]+>'
Priority: 13
MainIncludeChar: AngleBracket
+17 -21
View File
@@ -23,16 +23,14 @@
namespace Bigfoot
{
#ifdef BIGFOOT_TOOLMODE
namespace
{
using Random = effolkronium::random_static;
constexpr std::uint32_t ASSET_COUNT = 20'000;
constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
class Fixture: public benchmark::Fixture
class BigFileFixture: public benchmark::Fixture
{
public:
protected:
static constexpr std::uint32_t ASSET_COUNT = 20'000;
static constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
void SetUp(benchmark::State&) override
{
BigFile::Request {m_bigFile, "DELETE FROM Asset;"}.Execute();
@@ -63,7 +61,6 @@ class Fixture: public benchmark::Fixture
m_bigFile.SaveAssetFlatbuffers(metadatas, flatbuffers);
}
protected:
[[nodiscard]]
eastl::vector<UUID> RandomBatch(const std::size_t p_batchSize) const
{
@@ -94,11 +91,10 @@ class Fixture: public benchmark::Fixture
BigFile m_bigFile {File {BIGFILE_ENGINEBENCHMARKS_LOCATION}};
eastl::vector<UUID> m_uuids;
};
} // namespace
/****************************************************************************************/
BENCHMARK_DEFINE_F(Fixture, GetAssetFlatbuffer)(benchmark::State& state)
BENCHMARK_DEFINE_F(BigFileFixture, GetAssetFlatbuffer)(benchmark::State& state)
{
std::int64_t bytesProcessed = 0;
@@ -118,11 +114,11 @@ BENCHMARK_DEFINE_F(Fixture, GetAssetFlatbuffer)(benchmark::State& state)
state.SetBytesProcessed(bytesProcessed);
}
BENCHMARK_REGISTER_F(Fixture, GetAssetFlatbuffer)->Name("BigFile/GetAssetFlatbuffer");
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetFlatbuffer)->Name("BigFile/GetAssetFlatbuffer");
/****************************************************************************************/
BENCHMARK_DEFINE_F(Fixture, GetAssetFlatbuffers)(benchmark::State& state)
BENCHMARK_DEFINE_F(BigFileFixture, GetAssetFlatbuffers)(benchmark::State& state)
{
const auto batchSize = static_cast<std::size_t>(state.range(0));
@@ -149,7 +145,7 @@ BENCHMARK_DEFINE_F(Fixture, GetAssetFlatbuffers)(benchmark::State& state)
state.SetBytesProcessed(bytesProcessed);
}
BENCHMARK_REGISTER_F(Fixture, GetAssetFlatbuffers)
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetFlatbuffers)
->Name("BigFile/GetAssetFlatbuffers")
->Arg(1)
->Arg(8)
@@ -159,7 +155,7 @@ BENCHMARK_REGISTER_F(Fixture, GetAssetFlatbuffers)
/****************************************************************************************/
BENCHMARK_DEFINE_F(Fixture, GetAssetMetadata)(benchmark::State& state)
BENCHMARK_DEFINE_F(BigFileFixture, GetAssetMetadata)(benchmark::State& state)
{
for (auto _: state)
{
@@ -169,11 +165,11 @@ BENCHMARK_DEFINE_F(Fixture, GetAssetMetadata)(benchmark::State& state)
state.SetItemsProcessed(state.iterations());
}
BENCHMARK_REGISTER_F(Fixture, GetAssetMetadata)->Name("BigFile/GetAssetMetadata");
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetMetadata)->Name("BigFile/GetAssetMetadata");
/****************************************************************************************/
BENCHMARK_DEFINE_F(Fixture, GetAssetMetadatas)(benchmark::State& state)
BENCHMARK_DEFINE_F(BigFileFixture, GetAssetMetadatas)(benchmark::State& state)
{
const auto batchSize = static_cast<std::size_t>(state.range(0));
@@ -190,7 +186,7 @@ BENCHMARK_DEFINE_F(Fixture, GetAssetMetadatas)(benchmark::State& state)
state.SetItemsProcessed(state.iterations() * batchSize);
}
BENCHMARK_REGISTER_F(Fixture, GetAssetMetadatas)
BENCHMARK_REGISTER_F(BigFileFixture, GetAssetMetadatas)
->Name("BigFile/GetAssetMetadatas")
->Arg(1)
->Arg(8)
@@ -200,7 +196,7 @@ BENCHMARK_REGISTER_F(Fixture, GetAssetMetadatas)
/****************************************************************************************/
BENCHMARK_DEFINE_F(Fixture, SaveAssetFlatbuffer)(benchmark::State& state)
BENCHMARK_DEFINE_F(BigFileFixture, SaveAssetFlatbuffer)(benchmark::State& state)
{
std::int64_t bytesProcessed = 0;
@@ -226,11 +222,11 @@ BENCHMARK_DEFINE_F(Fixture, SaveAssetFlatbuffer)(benchmark::State& state)
state.SetBytesProcessed(bytesProcessed);
}
BENCHMARK_REGISTER_F(Fixture, SaveAssetFlatbuffer)->Name("BigFile/SaveAssetFlatbuffer");
BENCHMARK_REGISTER_F(BigFileFixture, SaveAssetFlatbuffer)->Name("BigFile/SaveAssetFlatbuffer");
/****************************************************************************************/
BENCHMARK_DEFINE_F(Fixture, SaveAssetFlatbuffers)(benchmark::State& state)
BENCHMARK_DEFINE_F(BigFileFixture, SaveAssetFlatbuffers)(benchmark::State& state)
{
const auto batchSize = static_cast<std::size_t>(state.range(0));
std::int64_t bytesProcessed = 0;
@@ -265,7 +261,7 @@ BENCHMARK_DEFINE_F(Fixture, SaveAssetFlatbuffers)(benchmark::State& state)
state.SetBytesProcessed(bytesProcessed);
}
BENCHMARK_REGISTER_F(Fixture, SaveAssetFlatbuffers)
BENCHMARK_REGISTER_F(BigFileFixture, SaveAssetFlatbuffers)
->Name("BigFile/SaveAssetFlatbuffers")
->Arg(1)
->Arg(8)
+2
View File
@@ -10,3 +10,5 @@ target_link_libraries(${PROJECT_NAME}
$<LINK_LIBRARY:WHOLE_ARCHIVE,AssetsForBenchmarking>)
bigfoot_create_bigfile("Benchmarks/Bigfoot")
bigfoot_create_sasquatch_info()
@@ -0,0 +1,22 @@
// AUTO-GENERATED DO NOT TOUCH
/*********************************************************************
* \file SasquatchInfo.generated.hpp
*
*********************************************************************/
#ifndef BIGFOOT_ENGINEBENCHMARKS_SASQUATCHINFO_GENERATED_HPP
#define BIGFOOT_ENGINEBENCHMARKS_SASQUATCHINFO_GENERATED_HPP
#include <EASTL/string_view.h>
#if defined BIGFOOT_GAME
namespace Bigfoot
{
/*
* Sasquatch location
*/
constexpr eastl::string_view SASQUATCH_ENGINEBENCHMARKS_LOCATION {"./EngineBenchmarks-sasquatch.sasquatch"};
} // namespace Bigfoot
#endif
#endif
@@ -0,0 +1,176 @@
/*********************************************************************
* \file Sasquatch.cpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#include <Engine/Sasquatch/Sasquatch.hpp>
#include <System/File/File.hpp>
#include <System/UUID/UUID.hpp>
#include <EngineBenchmarks/SasquatchInfo_generated.hpp>
#include <AssetsForBenchmarking/Asset/BenchmarkAsset.hpp>
#include <EASTL/optional.h>
#include <EASTL/vector.h>
#include <benchmark/benchmark.h>
#include <effolkronium/random.hpp>
#include <cstddef>
#include <cstdint>
namespace Bigfoot
{
#ifdef BIGFOOT_GAME
using Random = effolkronium::random_static;
class SasquatchFixture: public benchmark::Fixture
{
protected:
static constexpr std::uint32_t ASSET_COUNT = 20'000;
static constexpr std::size_t ASSET_PAYLOAD_SIZE = 256;
void SetUp([[maybe_unused]] benchmark::State& p_state) override
{
File {SASQUATCH_ENGINEBENCHMARKS_LOCATION}.Delete();
eastl::vector<eastl::vector<std::byte>> flatbuffers;
flatbuffers.reserve(ASSET_COUNT);
m_uuids.clear();
m_uuids.reserve(ASSET_COUNT);
for (std::uint32_t i = 0; i < ASSET_COUNT; ++i)
{
BenchmarkAsset asset;
asset.SetName(asset.GetHeader().uuid.ToString().c_str());
asset.GetAsset().payload.assign(ASSET_PAYLOAD_SIZE, std::uint8_t {0xAB});
flatbuffers.push_back(asset.Pack());
m_uuids.push_back(asset.GetHeader().uuid);
}
eastl::vector<SasquatchData> assets;
assets.reserve(ASSET_COUNT);
for (std::uint32_t i = 0; i < ASSET_COUNT; ++i)
{
assets.push_back(SasquatchData {.m_uuid = m_uuids[i], .m_flatbuffer = flatbuffers[i]});
}
std::uint64_t totalFlatbufferBytes = 0;
for (const SasquatchData& asset: assets)
{
totalFlatbufferBytes += asset.m_flatbuffer.size();
}
{
SasquatchWriter writer {File {SASQUATCH_ENGINEBENCHMARKS_LOCATION}, assets.size(), totalFlatbufferBytes};
for (const SasquatchData& asset: assets)
{
writer.WriteAsset(asset.m_uuid, asset.m_flatbuffer);
}
}
m_sasquatch.emplace(File {SASQUATCH_ENGINEBENCHMARKS_LOCATION});
}
void TearDown(benchmark::State&) override
{
m_sasquatch.reset();
}
[[nodiscard]]
eastl::vector<UUID> RandomBatch(const std::size_t p_batchSize) const
{
eastl::vector<UUID> batch;
batch.reserve(p_batchSize);
for (std::size_t i = 0; i < p_batchSize; ++i)
{
batch.push_back(m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
}
return batch;
}
[[nodiscard]]
eastl::vector<eastl::vector<UUID>> RandomBatchPool(const std::size_t p_batchSize,
const std::size_t p_poolSize) const
{
eastl::vector<eastl::vector<UUID>> pool;
pool.reserve(p_poolSize);
for (std::size_t i = 0; i < p_poolSize; ++i)
{
pool.push_back(RandomBatch(p_batchSize));
}
return pool;
}
eastl::optional<Sasquatch> m_sasquatch;
eastl::vector<UUID> m_uuids;
};
/****************************************************************************************/
BENCHMARK_DEFINE_F(SasquatchFixture, GetAssetFlatbuffer)(benchmark::State& state)
{
std::int64_t bytesProcessed = 0;
for (auto _: state)
{
eastl::optional<eastl::vector<std::byte>> flatbuffer = m_sasquatch->GetAssetFlatbuffer(
m_uuids[Random::get<std::size_t>(0, m_uuids.size() - 1)]);
benchmark::DoNotOptimize(flatbuffer);
if (flatbuffer.has_value())
{
bytesProcessed += static_cast<std::int64_t>(flatbuffer->size());
}
}
state.SetItemsProcessed(state.iterations());
state.SetBytesProcessed(bytesProcessed);
}
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetFlatbuffer)->Name("Sasquatch/GetAssetFlatbuffer");
/****************************************************************************************/
BENCHMARK_DEFINE_F(SasquatchFixture, GetAssetFlatbuffers)(benchmark::State& state)
{
const auto batchSize = static_cast<std::size_t>(state.range(0));
constexpr std::size_t BATCH_POOL_SIZE = 64;
const eastl::vector<eastl::vector<UUID>> batchPool = RandomBatchPool(batchSize, BATCH_POOL_SIZE);
std::int64_t bytesProcessed = 0;
std::size_t batchIndex = 0;
for (auto _: state)
{
eastl::vector<eastl::vector<std::byte>> flatbuffers = m_sasquatch->GetAssetFlatbuffers(batchPool[batchIndex]);
benchmark::DoNotOptimize(flatbuffers);
for (const eastl::vector<std::byte>& flatbuffer: flatbuffers)
{
bytesProcessed += static_cast<std::int64_t>(flatbuffer.size());
}
batchIndex = (batchIndex + 1) % BATCH_POOL_SIZE;
}
state.SetItemsProcessed(state.iterations() * batchSize);
state.SetBytesProcessed(bytesProcessed);
}
BENCHMARK_REGISTER_F(SasquatchFixture, GetAssetFlatbuffers)
->Name("Sasquatch/GetAssetFlatbuffers")
->Arg(1)
->Arg(8)
->Arg(64)
->Arg(512)
->Arg(4096);
#endif
} // namespace Bigfoot
@@ -11,10 +11,7 @@
namespace Bigfoot
{
namespace
{
using Random = effolkronium::random_static;
} // namespace
struct MyComplexStruct
{
+4 -1
View File
@@ -1,3 +1,6 @@
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/System)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
if(${TOOLMODE})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Tools)
endif()
@@ -0,0 +1,214 @@
/*********************************************************************
* \file Sasquatch.hpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#ifndef BIGFOOT_ENGINE_SASQUATCH_SASQUATCH_HPP
#define BIGFOOT_ENGINE_SASQUATCH_SASQUATCH_HPP
#include <Engine/DataAccessor/DataAccessor.hpp>
#include <System/File/File.hpp>
#include <System/File/MemoryMappedFile.hpp>
#include <System/UUID/UUID.hpp>
#include <EASTL/span.h>
#include <EASTL/vector.h>
#include <ankerl/unordered_dense.h>
#include <array>
#include <cstddef>
#include <cstdint>
#include <type_traits>
namespace Bigfoot
{
struct SasquatchHeader
{
static constexpr std::uint32_t MAGIC = 0x53515443; // 'SQTC'
static constexpr std::uint32_t VERSION = 1;
std::uint32_t m_magic = MAGIC;
std::uint32_t m_version = VERSION;
std::uint64_t m_assetCount = 0;
};
static_assert(sizeof(SasquatchHeader) == 16);
static_assert(std::is_trivially_copyable_v<SasquatchHeader>);
/****************************************************************************************/
struct SasquatchEntry
{
std::array<std::byte, UUID::UUID_BYTE_SIZE> m_uuid {};
std::size_t m_offset = 0;
std::size_t m_size = 0;
};
static_assert(sizeof(SasquatchEntry) == 32);
static_assert(std::is_trivially_copyable_v<SasquatchEntry>);
/****************************************************************************************/
#if defined(BIGFOOT_TOOLMODE) || defined(BIGFOOT_BUILD_TESTS) || defined(BIGFOOT_BUILD_BENCHMARKS)
struct SasquatchData
{
UUID m_uuid;
eastl::span<const std::byte> m_flatbuffer;
};
class SasquatchWriter
{
public:
/**
* Constructor
* Writes the header
*
* \param p_file The file to write
* \param p_assetCount The number of assets that will be written
* \param p_totalFlatbufferBytes The sum of the sizes of every flatbuffer that will be written
*/
SasquatchWriter(const File& p_file, std::uint64_t p_assetCount, std::size_t p_totalFlatbufferBytes);
SasquatchWriter(const SasquatchWriter& p_writer) = delete;
SasquatchWriter(SasquatchWriter&& p_writer) = delete;
/**
* Destructor
* Writes the entries
*
*/
~SasquatchWriter();
/**
* Writes an asset to the file.
*
* \param p_uuid The UUID of the asset
* \param p_flatbuffer The flatbuffer of the asset
*/
void WriteAsset(const UUID& p_uuid, eastl::span<const std::byte> p_flatbuffer);
SasquatchWriter& operator=(const SasquatchWriter& p_writer) = delete;
SasquatchWriter& operator=(SasquatchWriter&& p_writer) = delete;
private:
static constexpr std::uint64_t PREFETCH_BYTES = 4 * 1024 * 1024;
/**
* The number of assets expected
*/
std::uint64_t m_assetCount;
/**
* The offset the next WriteAsset call will write to
*/
std::size_t m_nextOffset;
/**
* How far into m_file has already been prefetched
*/
std::size_t m_prefetchedUpTo;
/**
* The Sasquatch file being written, mapped at its final size
*/
WritableMemoryMappedFile m_file;
/**
* The entries
*/
eastl::vector<SasquatchEntry> m_entries;
};
#endif
/****************************************************************************************/
#ifdef BIGFOOT_GAME
class Sasquatch: public DataAccessor
{
public:
/**
* Constructor
*
* \param p_file The sasquatch file
*/
Sasquatch(const File& p_file);
Sasquatch(const Sasquatch& p_sasquatch) = delete;
Sasquatch(Sasquatch&& p_sasquatch) = delete;
~Sasquatch() override = default;
/**
* Get an Asset flatbuffer
*
* \param p_uuid The asset to get the flatbuffer of
* \return The flatbuffer, or nullopt if the asset was not found
*/
eastl::optional<eastl::vector<std::byte>> GetAssetFlatbuffer(const UUID& p_uuid) const override;
/**
* Get several Asset flatbuffers
*
* \param p_uuids The assets to get the flatbuffers of
* \return The flatbuffers that were found
*/
eastl::vector<eastl::vector<std::byte>> GetAssetFlatbuffers(eastl::span<const UUID> p_uuids) const override;
/**
* Sasquatch only serves flatbuffers: this will always fail
*
*/
eastl::optional<AssetMetadata> GetAssetMetadata(const UUID& p_uuid) const override;
/**
* Sasquatch only serves flatbuffers: this will always fail
*
*/
eastl::vector<AssetMetadata> GetAssetMetadatas(eastl::span<const UUID> p_uuids) const override;
/**
* Sasquatch is read-only: this will always fail
*
*/
void SaveAssetFlatbuffer(const AssetMetadata& p_metadata, eastl::span<const std::byte> p_flatbuffer) override;
/**
* Sasquatch is read-only: this will always fail
*
*/
void SaveAssetFlatbuffers(eastl::span<const AssetMetadata> p_metadatas,
eastl::span<const eastl::vector<std::byte>> p_flatbuffers) override;
/**
* Check if the Asset exists
*
* \param p_uuid The asset to check
* \param True if it exists, false otherwise
*/
bool Has(const UUID& p_uuid) const override;
Sasquatch& operator=(const Sasquatch& p_sasquatch) = delete;
Sasquatch& operator=(Sasquatch&& p_sasquatch) = delete;
private:
struct Entry
{
std::size_t m_offset;
std::size_t m_size;
};
/**
* The Sasquatch file
*/
MemoryMappedFile m_file;
/**
* UUID to entry
*/
ankerl::unordered_dense::map<UUID, Entry> m_entries;
};
#endif
} // namespace Bigfoot
#endif
@@ -0,0 +1,22 @@
@AUTO_GENERATED_COMMENT@
/*********************************************************************
* \file SasquatchInfo.generated.hpp
*
*********************************************************************/
#ifndef BIGFOOT_@SASQUATCH_NAME@_SASQUATCHINFO_GENERATED_HPP
#define BIGFOOT_@SASQUATCH_NAME@_SASQUATCHINFO_GENERATED_HPP
#include <EASTL/string_view.h>
#if defined BIGFOOT_GAME
namespace Bigfoot
{
/*
* Sasquatch location
*/
constexpr eastl::string_view SASQUATCH_@SASQUATCH_NAME@_LOCATION {"@SASQUATCH_LOCATION@"};
} // namespace Bigfoot
#endif
#endif
@@ -0,0 +1,232 @@
/*********************************************************************
* \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):
m_assetCount(p_assetCount),
m_nextOffset(sizeof(SasquatchHeader) + p_assetCount * sizeof(SasquatchEntry)),
m_prefetchedUpTo(0),
m_file(p_file, m_nextOffset + p_totalFlatbufferBytes)
{
m_entries.reserve(p_assetCount);
SasquatchHeader header;
header.m_assetCount = p_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));
std::memcpy(m_file.GetData().data() + sizeof(SasquatchHeader),
m_entries.data(),
m_entries.size() * sizeof(SasquatchEntry));
}
/****************************************************************************************/
void SasquatchWriter::WriteAsset(const UUID& p_uuid, const eastl::span<const std::byte> p_flatbuffer)
{
ASSERT(EngineAssertHandler,
m_entries.size() < m_assetCount,
"SasquatchWriter can only hold {} assets",
m_assetCount);
const eastl::span<std::byte> data = m_file.GetData();
ASSERT(EngineAssertHandler,
m_nextOffset + p_flatbuffer.size() <= data.size(),
"SasquatchWriter can only write {} bytes",
data.size());
const std::size_t writeEnd = m_nextOffset + p_flatbuffer.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_offset = m_nextOffset;
entry.m_size = p_flatbuffer.size();
m_entries.push_back(entry);
std::memcpy(data.data() + m_nextOffset, p_flatbuffer.data(), p_flatbuffer.size());
m_nextOffset += entry.m_size;
}
#endif
/****************************************************************************************/
#ifdef BIGFOOT_GAME
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());
SasquatchHeader header;
std::memcpy(&header, data.data(), sizeof(SasquatchHeader));
CRITICAL_ASSERT(EngineAssertHandler,
header.m_magic == SasquatchHeader::MAGIC,
"Sasquatch file {} has an invalid magic number (got {} / expected {})",
p_file.GetPath(),
header.m_magic,
SasquatchHeader::MAGIC);
CRITICAL_ASSERT(EngineAssertHandler,
header.m_version == SasquatchHeader::VERSION,
"Sasquatch file {} has an unsupported version (got {} / expected {})",
p_file.GetPath(),
header.m_version,
SasquatchHeader::VERSION);
CRITICAL_ASSERT(EngineAssertHandler,
data.size() >= sizeof(SasquatchHeader) + header.m_assetCount * sizeof(SasquatchEntry),
"Sasquatch file {} index is truncated (got {} / expected at least {})",
p_file.GetPath(),
data.size(),
sizeof(SasquatchHeader) + header.m_assetCount * sizeof(SasquatchEntry));
eastl::vector<SasquatchEntry> entries(header.m_assetCount);
std::memcpy(entries.data(), data.data() + sizeof(SasquatchHeader), entries.size() * sizeof(SasquatchEntry));
m_entries.reserve(header.m_assetCount);
for (const SasquatchEntry& entry: entries)
{
CRITICAL_ASSERT(EngineAssertHandler,
entry.m_offset + entry.m_size <= data.size(),
"Sasquatch file {} has an out-of-bounds asset entry",
p_file.GetPath());
m_entries.emplace(UUID {entry.m_uuid}, Entry {.m_offset = entry.m_offset, .m_size = entry.m_size});
}
}
/****************************************************************************************/
eastl::optional<eastl::vector<std::byte>> Sasquatch::GetAssetFlatbuffer(const UUID& p_uuid) const
{
const auto it = m_entries.find(p_uuid);
if (it == m_entries.end())
{
return eastl::nullopt;
}
const eastl::span<const std::byte> data = m_file.GetData();
const eastl::span<const std::byte> bytes {data.data() + it->second.m_offset,
static_cast<std::size_t>(it->second.m_size)};
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;
if (p_uuids.empty())
{
return flatbuffers;
}
flatbuffers.reserve(p_uuids.size());
if (p_uuids.size() == 1)
{
if (eastl::optional<eastl::vector<std::byte>> flatbuffer = GetAssetFlatbuffer(p_uuids[0]);
flatbuffer.has_value())
{
flatbuffers.push_back(std::move(*flatbuffer));
}
return flatbuffers;
}
ankerl::unordered_dense::set<UUID> seen;
seen.reserve(p_uuids.size());
for (const UUID& uuid: p_uuids)
{
if (!seen.insert(uuid).second)
{
continue;
}
if (const auto it = m_entries.find(uuid); it != m_entries.end())
{
const eastl::span<const std::byte> data = m_file.GetData();
const eastl::span<const std::byte> bytes {data.data() + it->second.m_offset,
static_cast<std::size_t>(it->second.m_size)};
flatbuffers.emplace_back(bytes.begin(), bytes.end());
}
}
return flatbuffers;
}
/****************************************************************************************/
eastl::optional<AssetMetadata> Sasquatch::GetAssetMetadata(const UUID&) const
{
ASSERT(EngineAssertHandler, false, "Sasquatch does not support metadata queries, only flatbuffers");
return eastl::nullopt;
}
/****************************************************************************************/
eastl::vector<AssetMetadata> Sasquatch::GetAssetMetadatas(const eastl::span<const UUID>) const
{
ASSERT(EngineAssertHandler, false, "Sasquatch does not support metadata queries, only flatbuffers");
return {};
}
/****************************************************************************************/
void Sasquatch::SaveAssetFlatbuffer(const AssetMetadata&, eastl::span<const std::byte>)
{
ASSERT(EngineAssertHandler, false, "Sasquatch is read-only, it cannot save assets");
}
/****************************************************************************************/
void Sasquatch::SaveAssetFlatbuffers(eastl::span<const AssetMetadata>, eastl::span<const eastl::vector<std::byte>>)
{
ASSERT(EngineAssertHandler, false, "Sasquatch is read-only, it cannot save assets");
}
/****************************************************************************************/
bool Sasquatch::Has(const UUID& p_uuid) const
{
return m_entries.find(p_uuid) != m_entries.end();
}
#endif
} // namespace Bigfoot
+2
View File
@@ -0,0 +1,2 @@
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/SasquatchBaker)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Executables/SasquatchBaker)
@@ -0,0 +1,33 @@
project(SasquatchBakerCLI)
add_executable(${PROJECT_NAME})
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
target_link_libraries(${PROJECT_NAME}
PRIVATE
BigfootCompileAndLinkFlags
bfg::lyra
$<LINK_LIBRARY:WHOLE_ARCHIVE,SasquatchBaker>)
file(GLOB_RECURSE _SOURCES
CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
)
file(GLOB_RECURSE _HEADERS
CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/*.h
${CMAKE_CURRENT_SOURCE_DIR}/*.hpp
)
target_sources(${PROJECT_NAME}
PRIVATE
${_SOURCES}
${_HEADERS}
)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src FILES ${_SOURCES} ${_HEADERS})
set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER Bigfoot/Tools/Executables)
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME SasquatchBaker)
@@ -0,0 +1,49 @@
/*********************************************************************
* \file main.cpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#include <System/File/File.hpp>
#include <Utils/Log/LogMacros.hpp>
#include <Utils/TargetMacros.h>
#include <SasquatchBaker/SasquatchBaker.hpp>
#include <EASTL/string_view.h>
#include <lyra/lyra.hpp>
#include <iostream>
#include <string>
int main(int argc, char** argv)
{
BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime logLifetime);
bool showHelp = false;
std::string bigFilePath;
std::string outputPath;
auto cli = lyra::help(showHelp) |
lyra::opt(bigFilePath, "bigfile")["-b"]["--bigfile"]("The BigFile to bake (must exist)").required() |
lyra::opt(outputPath, "output")["-o"]["--output"]("The Sasquatch file to write").required();
const lyra::parse_result result = cli.parse({argc, argv});
if (!result)
{
std::cerr << result.message() << "\n\n" << cli << std::endl;
return 1;
}
if (showHelp)
{
std::cout << cli << std::endl;
return 0;
}
const Bigfoot::BigFile bigFile {Bigfoot::File {eastl::string_view {bigFilePath.c_str()}}};
Bigfoot::Bake(bigFile, Bigfoot::File {eastl::string_view {outputPath.c_str()}});
return 0;
}
@@ -0,0 +1,18 @@
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
project(${PackageName})
set(PublicDependencies)
set(PrivateDependencies)
set(BigfootPublicDependencies
Engine)
set(BigfootPrivateDependencies
Utils)
bigfoot_create_package_lib(
"${PublicDependencies}"
"${PrivateDependencies}"
"${BigfootPublicDependencies}"
"${BigfootPrivateDependencies}"
"Tools")
bigfoot_create_logger()
@@ -0,0 +1,24 @@
/*********************************************************************
* \file SasquatchBaker.hpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#ifndef BIGFOOT_TOOLS_SASQUATCHBAKER_SASQUATCHBAKER_HPP
#define BIGFOOT_TOOLS_SASQUATCHBAKER_SASQUATCHBAKER_HPP
#include <Engine/BigFile/BigFile.hpp>
#include <System/File/File.hpp>
namespace Bigfoot
{
/**
* Bake every Asset of a BigFile into a Sasquatch file
*
* \param p_bigFile The BigFile to bake
* \param p_outputFile The file to write to
*/
void Bake(const BigFile& p_bigFile, const File& p_outputFile);
} // namespace Bigfoot
#endif
@@ -0,0 +1,20 @@
/*********************************************************************
* \file SasquatchBakerAssertHandler.hpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#ifndef BIGFOOT_TOOLS_SASQUATCHBAKER_SASQUATCHBAKERASSERTHANDLER_HPP
#define BIGFOOT_TOOLS_SASQUATCHBAKER_SASQUATCHBAKERASSERTHANDLER_HPP
#include <Utils/Assert/AssertHandler.hpp>
#include <SasquatchBaker/SasquatchBakerLogger_generated.hpp>
#if defined BIGFOOT_NOT_OPTIMIZED
namespace Bigfoot
{
using SasquatchBakerAssertHandler = AssertHandler<SASQUATCHBAKER_LOGGER>;
} // namespace Bigfoot
#endif
#endif
@@ -0,0 +1,21 @@
// AUTO-GENERATED DO NOT TOUCH
/*********************************************************************
* \file SasquatchBakerLogger.generated.hpp
*
*********************************************************************/
#ifndef BIGFOOT_SASQUATCHBAKERLOGGER_GENERATED_HPP
#define BIGFOOT_SASQUATCHBAKERLOGGER_GENERATED_HPP
#include <Utils/Log/LogMacros.hpp>
#if defined BIGFOOT_NOT_OPTIMIZED
namespace Bigfoot
{
/*
* Logger
*/
inline Log::LoggerInfo SASQUATCHBAKER_LOGGER {"SASQUATCHBAKER_LOGGER", Flat::LogLevel::Trace};
} // namespace Bigfoot
#endif
#endif
@@ -0,0 +1,54 @@
/*********************************************************************
* \file SasquatchBaker.cpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#include <SasquatchBaker/SasquatchBaker.hpp>
#include <Engine/Sasquatch/Sasquatch.hpp>
#include <SasquatchBaker/SasquatchBakerAssertHandler.hpp>
namespace Bigfoot
{
void Bake(const BigFile& p_bigFile, const File& p_outputFile)
{
std::uint64_t assetCount = 0;
{
BigFile::Request countRequest {p_bigFile, "SELECT COUNT(*) FROM Asset;"};
[[maybe_unused]]
const bool hasCount = countRequest.Step();
ASSERT(SasquatchBakerAssertHandler, hasCount, "Failed to count the assets of the BigFile");
assetCount = countRequest.Get(0);
}
std::uint64_t totalFlatbufferBytes = 0;
{
BigFile::Request sizeRequest {p_bigFile, "SELECT COALESCE(SUM(LENGTH(Asset)), 0) FROM Asset;"};
[[maybe_unused]]
const bool hasSize = sizeRequest.Step();
ASSERT(SasquatchBakerAssertHandler, hasSize, "Failed to sum the asset sizes of the BigFile");
totalFlatbufferBytes = sizeRequest.Get(0);
}
SasquatchWriter writer {p_outputFile, assetCount, totalFlatbufferBytes};
BigFile::Request request {p_bigFile, "SELECT UUID, Asset FROM Asset;"};
while (request.Step())
{
const eastl::span<const std::byte> uuidBytes = request.Get(0);
const eastl::span<const std::byte> flatbuffer = request.Get(1);
ASSERT(SasquatchBakerAssertHandler,
uuidBytes.size() == UUID::UUID_BYTE_SIZE,
"Unexpected UUID blob size in BigFile (got {} / expected {})",
uuidBytes.size(),
UUID::UUID_BYTE_SIZE);
writer.WriteAsset(
UUID {{std::span<const std::byte, UUID::UUID_BYTE_SIZE> {uuidBytes.data(), UUID::UUID_BYTE_SIZE}}},
flatbuffer);
}
}
} // namespace Bigfoot
+4 -1
View File
@@ -2,4 +2,7 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Misc)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Utils)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/System)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Engine)
if(${TOOLMODE})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Tools)
endif()
+3 -1
View File
@@ -10,4 +10,6 @@ bigfoot_create_package_tests(
"${BigfootDependencies}"
"")
bigfoot_create_bigfile("Tests/Bigfoot")
bigfoot_create_bigfile("Tests/Bigfoot")
bigfoot_create_sasquatch_info()
@@ -0,0 +1,22 @@
// AUTO-GENERATED DO NOT TOUCH
/*********************************************************************
* \file SasquatchInfo.generated.hpp
*
*********************************************************************/
#ifndef BIGFOOT_ENGINETESTS_SASQUATCHINFO_GENERATED_HPP
#define BIGFOOT_ENGINETESTS_SASQUATCHINFO_GENERATED_HPP
#include <EASTL/string_view.h>
#if defined BIGFOOT_GAME
namespace Bigfoot
{
/*
* Sasquatch location
*/
constexpr eastl::string_view SASQUATCH_ENGINETESTS_LOCATION {"./EngineTests-sasquatch.sasquatch"};
} // namespace Bigfoot
#endif
#endif
@@ -0,0 +1,118 @@
/*********************************************************************
* \file Sasquatch.cpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#include <Engine/Sasquatch/Sasquatch.hpp>
#include <System/File/File.hpp>
#include <EngineTests/SasquatchInfo_generated.hpp>
#include <AssetsForTesting/Asset/AssetA.hpp>
#include <AssetsForTesting/Asset/AssetB.hpp>
#include <gtest/gtest.h>
namespace Bigfoot
{
#ifdef BIGFOOT_GAME
class SasquatchFixture: public ::testing::Test
{
protected:
void SetUp()
{
File {SASQUATCH_ENGINETESTS_LOCATION}.Delete();
m_assetA.SetName("hello");
m_flatbufferA = m_assetA.Pack();
m_assetB.SetName("world");
m_flatbufferB = m_assetB.Pack();
const eastl::vector<SasquatchData> assets {
SasquatchData {.m_uuid = m_assetA.GetHeader().uuid, .m_flatbuffer = m_flatbufferA},
SasquatchData {.m_uuid = m_assetB.GetHeader().uuid, .m_flatbuffer = m_flatbufferB}};
std::uint64_t totalFlatbufferBytes = 0;
for (const SasquatchData& asset: assets)
{
totalFlatbufferBytes += asset.m_flatbuffer.size();
}
{
SasquatchWriter writer {File {SASQUATCH_ENGINETESTS_LOCATION}, assets.size(), totalFlatbufferBytes};
for (const SasquatchData& asset: assets)
{
writer.WriteAsset(asset.m_uuid, asset.m_flatbuffer);
}
}
m_sasquatch.emplace(File {SASQUATCH_ENGINETESTS_LOCATION});
}
AssetA m_assetA;
AssetB m_assetB;
eastl::vector<std::byte> m_flatbufferA;
eastl::vector<std::byte> m_flatbufferB;
eastl::optional<Sasquatch> m_sasquatch;
};
/****************************************************************************************/
TEST_F(SasquatchFixture, GetAssetFlatbuffer_ShouldReturnNulloptForNonExistentUUID)
{
EXPECT_FALSE(m_sasquatch->GetAssetFlatbuffer(UUID {}).has_value());
}
/****************************************************************************************/
TEST_F(SasquatchFixture, GetAssetFlatbuffer_ShouldGetTheAssetFlatbuffer)
{
const eastl::optional<eastl::vector<std::byte>> savedFlatbuffer = m_sasquatch->GetAssetFlatbuffer(
m_assetA.GetHeader().uuid);
ASSERT_TRUE(savedFlatbuffer.has_value());
EXPECT_EQ(*savedFlatbuffer, m_flatbufferA);
}
/****************************************************************************************/
TEST_F(SasquatchFixture, GetAssetFlatbuffers_ShouldOmitUUIDsThatDoNotExist)
{
const eastl::vector<UUID> uuids {m_assetA.GetHeader().uuid, UUID {}, m_assetB.GetHeader().uuid};
const eastl::vector<eastl::vector<std::byte>> flatbuffers = m_sasquatch->GetAssetFlatbuffers(uuids);
ASSERT_EQ(flatbuffers.size(), 2);
EXPECT_TRUE((flatbuffers[0] == m_flatbufferA && flatbuffers[1] == m_flatbufferB) ||
(flatbuffers[0] == m_flatbufferB && flatbuffers[1] == m_flatbufferA));
}
/****************************************************************************************/
TEST_F(SasquatchFixture, GetAssetFlatbuffers_ShouldNotDuplicateResultsForADuplicateUUID)
{
const eastl::vector<UUID> uuids {m_assetA.GetHeader().uuid, m_assetA.GetHeader().uuid};
const eastl::vector<eastl::vector<std::byte>> flatbuffers = m_sasquatch->GetAssetFlatbuffers(uuids);
ASSERT_EQ(flatbuffers.size(), 1);
EXPECT_EQ(flatbuffers[0], m_flatbufferA);
}
/****************************************************************************************/
TEST_F(SasquatchFixture, Has_ShouldReturnTrueIfTheAssetExists)
{
EXPECT_TRUE(m_sasquatch->Has(m_assetA.GetHeader().uuid));
}
/****************************************************************************************/
TEST_F(SasquatchFixture, Has_ShouldReturnFalseIfTheAssetDoesNotExist)
{
EXPECT_FALSE(m_sasquatch->Has(UUID {}));
}
#endif
} // namespace Bigfoot
+1
View File
@@ -0,0 +1 @@
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/SasquatchBaker)
@@ -0,0 +1,13 @@
get_filename_component(PackageName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
project(${PackageName}Tests)
set(Dependencies)
set(BigfootDependencies
AssetsForTesting)
bigfoot_create_package_tests(
"${Dependencies}"
"${BigfootDependencies}"
"Tools")
bigfoot_create_bigfile("Tests/Tools")
@@ -0,0 +1,113 @@
/*********************************************************************
* \file SasquatchBaker.cpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#include <SasquatchBaker/SasquatchBaker.hpp>
#include <Engine/Sasquatch/Sasquatch.hpp>
#include <System/File/File.hpp>
#include <AssetsForTesting/Asset/AssetA.hpp>
#include <AssetsForTesting/Asset/AssetB.hpp>
#include <SasquatchBakerTests/BigFileInfo_generated.hpp>
#include <gtest/gtest.h>
#include <cstring>
namespace Bigfoot
{
class SasquatchBakerFixture: public ::testing::Test
{
protected:
void SetUp() override
{
BigFile::Request {m_bigFile, "DELETE FROM Asset;"}.Execute();
BigFile::Request {m_bigFile, "DELETE FROM AssetMetadata;"}.Execute();
m_sasquatch.Delete();
}
[[nodiscard]]
SasquatchHeader ReadHeader(const eastl::vector<std::byte>& p_data)
{
SasquatchHeader header;
std::memcpy(&header, p_data.data(), sizeof(SasquatchHeader));
return header;
}
[[nodiscard]]
eastl::optional<SasquatchEntry> FindEntry(const eastl::vector<std::byte>& p_data, const UUID& p_uuid)
{
const SasquatchHeader header = ReadHeader(p_data);
for (std::uint64_t i = 0; i < header.m_assetCount; ++i)
{
SasquatchEntry entry;
std::memcpy(&entry,
p_data.data() + sizeof(SasquatchHeader) + i * sizeof(SasquatchEntry),
sizeof(SasquatchEntry));
if (UUID {entry.m_uuid} == p_uuid)
{
return entry;
}
}
return eastl::nullopt;
}
static constexpr eastl::string_view SASQUATCH_SASQUATCHBAKERTESTS_LOCATION {
"./SasquatchBakerTests-sasquatch.sasquatch"};
BigFile m_bigFile {File {BIGFILE_SASQUATCHBAKERTESTS_LOCATION}};
File m_sasquatch {SASQUATCH_SASQUATCHBAKERTESTS_LOCATION};
};
/****************************************************************************************/
TEST_F(SasquatchBakerFixture, Bake_ShouldWriteAnEmptyFileWhenTheBigFileIsEmpty)
{
Bake(m_bigFile, m_sasquatch);
const eastl::vector<std::byte> data = m_sasquatch.Read(0, m_sasquatch.GetSize());
ASSERT_EQ(data.size(), sizeof(SasquatchHeader));
const SasquatchHeader header = ReadHeader(data);
EXPECT_EQ(header.m_magic, SasquatchHeader::MAGIC);
EXPECT_EQ(header.m_version, SasquatchHeader::VERSION);
EXPECT_EQ(header.m_assetCount, 0);
}
/****************************************************************************************/
TEST_F(SasquatchBakerFixture, Bake_ShouldWriteEveryAssetOfTheBigFile)
{
AssetA assetA;
assetA.SetName("hello");
m_bigFile.SaveAssetFlatbuffer(AssetMetadata {.m_uuid = assetA.GetHeader().uuid,
.m_name = assetA.GetHeader().name,
.m_typeID = assetA.GetHeader().type_id,
.m_typeName = assetA.GetHeader().type_name},
assetA.Pack());
AssetA assetB;
assetB.SetName("world");
m_bigFile.SaveAssetFlatbuffer(AssetMetadata {.m_uuid = assetB.GetHeader().uuid,
.m_name = assetB.GetHeader().name,
.m_typeID = assetB.GetHeader().type_id,
.m_typeName = assetB.GetHeader().type_name},
assetB.Pack());
Bake(m_bigFile, m_sasquatch);
const eastl::vector<std::byte> data = m_sasquatch.Read(0, m_sasquatch.GetSize());
const SasquatchHeader header = ReadHeader(data);
EXPECT_EQ(header.m_assetCount, 2);
EXPECT_TRUE(FindEntry(data, assetA.GetHeader().uuid).has_value());
EXPECT_TRUE(FindEntry(data, assetB.GetHeader().uuid).has_value());
}
} // namespace Bigfoot
@@ -0,0 +1,19 @@
/*********************************************************************
* \file main.cpp
*
* \author Romain BOULLARD
* \date August 2026
*********************************************************************/
#include <Utils/Log/LogMacros.hpp>
#include <Utils/TargetMacros.h>
#include <gtest/gtest.h>
int main(int argc, char** argv)
{
testing::InitGoogleTest(&argc, argv);
BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime);
return RUN_ALL_TESTS();
}
+3 -1
View File
@@ -97,7 +97,9 @@ function(bigfoot_create_package_tests PackageDependencies PackageBigfootDependen
)
include(GoogleTest)
gtest_discover_tests(${PROJECT_NAME} XML_OUTPUT_DIR ${CMAKE_BINARY_DIR}/TestResults/)
gtest_discover_tests(${PROJECT_NAME}
WORKING_DIRECTORY $<TARGET_FILE_DIR:${PROJECT_NAME}>
XML_OUTPUT_DIR ${CMAKE_BINARY_DIR}/TestResults/)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX Src/ FILES ${_SOURCES} ${_HEADERS} ${_OTHERS})
+10
View File
@@ -38,6 +38,16 @@ function(bigfoot_create_bigfile ParentFolder)
)
endfunction()
function(bigfoot_create_sasquatch_info)
string(TOUPPER ${PROJECT_NAME} SASQUATCH_NAME)
set(SASQUATCH_LOCATION "./${PROJECT_NAME}-sasquatch.sasquatch")
configure_file(
${CMAKE_SOURCE_DIR}/Bigfoot/Sources/Engine/Include/Engine/Sasquatch/SasquatchInfo_generated.hpp.in
${CMAKE_CURRENT_SOURCE_DIR}/Include/${PROJECT_NAME}/SasquatchInfo_generated.hpp
@ONLY
)
endfunction()
function(_bigfoot_collect_includes_recursive Target UseAllLinks)
get_property(_Visited GLOBAL PROPERTY _BIGFOOT_VISITED_TARGETS)
if("${Target}" IN_LIST _Visited)