2#ifndef LIBSBX_ASSETS_ASSETS_MODULE_HPP_
3#define LIBSBX_ASSETS_ASSETS_MODULE_HPP_
6#include <unordered_map>
11#include <libsbx/utility/compression.hpp>
12#include <libsbx/utility/exception.hpp>
13#include <libsbx/utility/type_id.hpp>
14#include <libsbx/utility/iterator.hpp>
15#include <libsbx/utility/logger.hpp>
16#include <libsbx/utility/hashed_string.hpp>
17#include <libsbx/utility/string_literal.hpp>
19#include <libsbx/math/uuid.hpp>
21#include <libsbx/core/module.hpp>
23#include <libsbx/filesystem/alias.hpp>
24#include <libsbx/filesystem/filesystem_module.hpp>
25#include <libsbx/filesystem/native_filesystem.hpp>
27#include <libsbx/assets/thread_pool.hpp>
28#include <libsbx/assets/metadata.hpp>
30namespace sbx::assets {
38template<utility::
string_literal String>
39requires (String.size() == 4u)
40constexpr auto fourcc() -> std::uint32_t {
41 return String[0] | (String[1] << 8) | (String[2] << 16) | (String[3] << 24);
49template<
typename Type>
52template<utility::
string_literal Type>
55 inline static constexpr auto hash = Type.hash();
57 inline static constexpr auto invalid = std::uint32_t{0xFFFFFFFF};
63 constexpr asset_handle(
const std::uint32_t handle,
const std::uint32_t generation)
65 _generation{generation} { }
67 constexpr auto handle()
const noexcept -> std::uint32_t {
71 constexpr auto generation()
const noexcept -> std::uint32_t {
75 constexpr auto operator==(
const asset_handle& other)
const noexcept ->
bool {
76 return _handle == other._handle && _generation == other._generation;
79 constexpr auto is_valid()
const noexcept ->
bool {
80 return _handle != invalid;
83 constexpr operator bool()
const noexcept {
89 std::uint32_t _handle;
90 std::uint32_t _generation;
95 std::filesystem::path path;
97 std::string type{
"unknown"};
98 std::string source{
"dynamic"};
103 std::function<void()> save;
104 std::function<void()> load;
113 template<
typename Type>
116 template<
typename Type, std::invocable<const Type&> Save, std::invocable<
void> Load>
117 auto register_asset(
const std::string& name, Save&& save, Load&& load) ->
void {
124 .save = [s = std::forward<Save>(save)]() ->
void {
127 .load = []() ->
void {
133 auto get(
const std::uint32_t
id) ->
asset_io& {
134 return _by_id.at(
id);
137 auto has(
const std::uint32_t
id) ->
bool {
138 return _by_id.contains(
id);
141 auto get(
const std::string& name) ->
asset_io& {
142 return _by_id.at(_by_name.at(name));
147 std::unordered_map<std::uint32_t, asset_io> _by_id;
148 std::unordered_map<std::string, std::uint32_t> _by_name;
154 inline static const auto is_registered = register_module(stage::post, dependencies<filesystem::filesystem_module>{});
159 : _thread_pool{std::thread::hardware_concurrency()} {
160 _register_asset_root(std::filesystem::current_path());
164 for (
const auto& container : _containers) {
169 auto update() ->
void override {
173 auto asset_root()
const -> std::filesystem::path {
174 auto& filesystem_module = core::engine::get_module<filesystem::filesystem_module>();
176 return filesystem_module.native_path_of(std::string{
"res://"});
179 auto set_asset_root(
const std::filesystem::path& root) ->
void {
180 if (!std::filesystem::exists(root)) {
184 utility::logger<
"assets">::debug(
"Setting asset_root to '{}'", root.string());
186 _register_asset_root(root);
189 auto resolve_path(
const std::filesystem::path& path) -> std::filesystem::path {
190 auto& filesystem_module = core::engine::get_module<filesystem::filesystem_module>();
192 return filesystem_module.native_path_of(path);
195 template<
typename Function,
typename... Args>
196 requires (std::is_invocable_v<Function, Args...>)
197 auto submit(Function&& function, Args&&... args) -> std::future<std::invoke_result_t<Function, Args...>> {
198 return _thread_pool.submit(std::forward<Function>(function), std::forward<Args>(args)...);
202 auto load_asset(
const std::filesystem::path& path, Args&&... args) ->
asset_handle<Type> {
206 template<
typename Type, std::invocable<
void> Save, std::invocable<
void> Load>
207 auto register_asset(
const std::string& name, Save&& save, Load&& load) ->
void {
208 _asset_io_registry.register_asset<Type>(name, std::forward<Save>(save), std::forward<Load>(load));
212 return _asset_io_registry.get(
id);
215 auto has_asset_io(
const std::uint32_t
id) ->
bool {
216 return _asset_io_registry.has(
id);
219 template<
typename Type,
typename... Args>
220 auto add_asset(Args&&... args) ->
math::uuid {
224 if (type >= _containers.size()) {
225 _containers.resize(std::max(_containers.size(),
static_cast<std::size_t
>(type + 1u)));
228 if (!_containers[type]) {
229 _containers[type] = std::make_unique<container<Type>>();
232 static_cast<container<Type>*
>(_containers[type].get())->add(
id, std::forward<Args>(args)...);
237 template<
typename Type>
238 auto add_asset(std::unique_ptr<Type>&& asset) ->
math::uuid {
242 if (type >= _containers.size()) {
243 _containers.resize(std::max(_containers.size(),
static_cast<std::size_t
>(type + 1u)));
246 if (!_containers[type]) {
247 _containers[type] = std::make_unique<container<Type>>();
250 static_cast<container<Type>*
>(_containers[type].get())->add(
id, std::move(asset));
255 template<
typename Type>
256 auto get_asset(
const math::uuid&
id)
const ->
const Type& {
259 if (type >= _containers.size() || !_containers[type]) {
260 throw std::runtime_error{
"Asset does not exist"};
263 return static_cast<const container<Type>*
>(_containers[type].get())->get(
id);
266 template<
typename Type>
267 auto get_asset(
const math::uuid&
id) -> Type& {
270 if (type >= _containers.size() || !_containers[type]) {
271 throw std::runtime_error{
"Asset does not exist"};
274 return static_cast<container<Type>*
>(_containers[type].get())->get(
id);
279 auto _register_asset_root(
const std::filesystem::path& root) ->
void {
280 auto& filesystem_module = core::engine::get_module<filesystem::filesystem_module>();
284 if (filesystem_module.is_alias_registered(alias)) {
285 filesystem_module.unregister_alias(alias);
293 struct container_base {
294 virtual ~container_base() =
default;
295 virtual auto remove(
const math::uuid&
id) ->
void = 0;
296 virtual auto clear() ->
void = 0;
299 template<
typename Type>
300 class container :
public container_base {
308 ~container()
override {
312 auto remove(
const math::uuid&
id) ->
void override {
316 auto clear() ->
void override {
320 template<
typename... Args>
321 auto add(
const math::uuid&
id, Args&&... args) ->
void {
322 _assets.insert({id, std::make_unique<Type>(std::forward<Args>(args)...)});
325 auto add(
const math::uuid&
id, std::unique_ptr<Type>&& asset) ->
void {
326 _assets.insert({id, std::move(asset)});
329 auto get(
const math::uuid&
id)
const ->
const Type& {
330 const auto entry = _assets.find(
id);
332 if (entry == _assets.end()) {
336 return *entry->second;
340 auto entry = _assets.find(
id);
342 if (entry == _assets.end()) {
346 return *entry->second;
351 std::unordered_map<math::uuid, std::unique_ptr<Type>> _assets;
355 std::vector<std::unique_ptr<container_base>> _containers;
Definition: assets_module.hpp:107
Definition: assets_module.hpp:152
Definition: thread_pool.hpp:23
Definition: module.hpp:92
Definition: native_filesystem.hpp:20
Definition: string_literal.hpp:30
Definition: logger.hpp:124
Definition: assets_module.hpp:53
Definition: assets_module.hpp:101
Definition: assets_module.hpp:34
Definition: exception.hpp:18
A scoped type ID generator. Allows for generating unique IDs for types within a specific scope.
Definition: type_id.hpp:31
static auto value() noexcept -> std::uint32_t
Generates a unique ID for the type.
Definition: type_id.hpp:41