37using namespace std::literals;
46auto checking_dependencies_job_name() -> std::string
52void resolve_includes(
const fs::path& file_path, std::set<fs::path>& processed_files)
59void resolve_includes<gfx::shader>(
const fs::path& file_path, std::set<fs::path>& processed_files)
61 if(!processed_files.insert(file_path).second)
66 std::ifstream file(file_path);
73 const std::string include_keyword =
"#include";
74 const std::string bgfx_include_path =
"/path/to/bgfx/include";
77 while(std::getline(file, line))
80 line.erase(0, line.find_first_not_of(
" \t"));
83 if(line.compare(0, include_keyword.length(), include_keyword) == 0)
86 size_t start = line.find_first_of(
"\"<") + 1;
87 size_t end = line.find_last_of(
"\">");
89 if(start == std::string::npos || end == std::string::npos || start >= end)
95 std::string include_path = line.substr(start, end - start);
96 fs::path resolved_path;
98 if(line[start - 1] ==
'<' && line[end] ==
'>')
107 resolved_path = file_path.parent_path() / include_path;
110 resolved_path = fs::absolute(resolved_path);
114 resolve_includes<gfx::shader>(resolved_path, processed_files);
119auto extract_href_from_link_tag(hpp::string_view link_tag) -> hpp::string_view
121 size_t href_pos = link_tag.find(
"href=");
122 if(href_pos == std::string::npos)
130 char quote_char = link_tag[href_pos];
131 if(quote_char !=
'"' && quote_char !=
'\'')
137 size_t href_end = link_tag.find(quote_char, href_pos);
138 if(href_end == std::string::npos)
143 return link_tag.substr(href_pos, href_end - href_pos);
146auto resolve_ui_tree_dependency_path(
const fs::path& href_value,
const fs::path& base_file_path) -> fs::path
155 return fs::absolute(base_file_path.parent_path() / href_value);
159void resolve_includes<ui_tree>(
const fs::path& file_path, std::set<fs::path>& processed_files)
161 if(!processed_files.insert(file_path).second)
166 std::ifstream file(file_path);
172 std::string content_str((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
173 hpp::string_view content(content_str);
176 while((pos = content.find(
"<link", pos)) != std::string::npos)
179 size_t tag_end = content.find(
'>', pos);
180 if(tag_end == std::string::npos)
185 hpp::string_view link_tag = content.substr(pos, tag_end - pos + 1);
186 hpp::string_view href_value = extract_href_from_link_tag(link_tag);
188 if(!href_value.empty())
190 fs::path resolved_path = resolve_ui_tree_dependency_path(fs::path(href_value), file_path);
194 auto extension = resolved_path.extension().string();
195 if(std::find(supported_deps.begin(), supported_deps.end(), extension) != supported_deps.end())
197 resolve_includes<ui_tree>(resolved_path, processed_files);
206auto has_depencency(
const fs::path& file,
const fs::path& dep_to_check) ->
bool
208 std::set<fs::path> dependecies;
209 resolve_includes<T>(file, dependecies);
211 return dependecies.contains(dep_to_check);
214auto remove_meta_tag(
const fs::path& synced_path) -> fs::path
219auto remove_meta_tag(
const std::vector<fs::path>& synced_paths) -> std::vector<fs::path>
221 std::decay_t<
decltype(synced_paths)> reduced;
222 reduced.reserve(synced_paths.size());
223 for(
const auto& synced_path : synced_paths)
225 reduced.emplace_back(remove_meta_tag(synced_path));
230void unwatch(std::vector<uint64_t>& watchers)
232 for(
const auto&
id : watchers)
239auto get_asset_key(
const fs::path& path) -> std::string
247auto get_meta_key(
const fs::path& path) -> std::string
252 return key +
".meta";
255auto check_files_integrity(
const std::string& key,
const fs::path& entry_path) ->
bool
260 if(!fs::exists(key_path, ec))
263 fs::remove(entry_path, ec);
265 auto meta = get_meta_key(entry_path);
267 if(fs::exists(meta_path, ec))
270 fs::remove(meta_path, ec);
282 auto& am = ctx.get_cached<asset_manager>();
283 auto& ts = ctx.get_cached<threader>();
284 auto& tm = ctx.get_cached<thumbnail_manager>();
285 auto& em = ctx.get_cached<editing_manager>();
287 fs::path watch_dir = fs::path(dir).make_preferred();
289 auto callback = [&am, &ts, &tm, &em](
const auto& entries,
bool is_initial_list)
291 std::set<hpp::uuid> changed;
292 std::set<hpp::uuid> removed;
294 for(
const auto&
entry : entries)
296 auto key = get_asset_key(
entry.path);
300 if(
entry.type == fs::file_type::regular)
304 removed.emplace(am.get_asset<T>(key).uid());
305 am.unload_asset<T>(
key);
307 if constexpr(std::is_same<T, script>::value)
314 auto old_key = get_asset_key(
entry.last_path);
315 am.rename_asset<T>(old_key,
key);
317 if constexpr(std::is_same<T, script>::value)
324 if(check_files_integrity(key,
entry.path))
327 auto asset = am.get_asset<T>(
key, flags);
329 changed.emplace(asset.uid());
332 if constexpr(std::is_same<T, script>::value)
340 if(!changed.empty() || !removed.empty())
342 tpp::invoke(tpp::main_thread::get_id(),
343 [&tm, &em, &am, changed, removed]()
345 for(
const auto& uid : removed)
347 tm.remove_thumbnail(uid);
350 for(
const auto& uid : changed)
352 tm.regenerate_thumbnail(uid);
354 if constexpr(std::is_same<T, prefab>::value)
356 auto asset = am.get_asset<T>(uid);
357 em.on_prefab_updated(asset);
370 auto& am = ctx.get_cached<asset_manager>();
371 auto& ts = ctx.get_cached<threader>();
373 fs::path watch_dir = fs::path(dir).make_preferred();
375 auto callback = [&am, &ts](
const auto& entries,
bool is_initial_list)
382 for(
const auto&
entry : entries)
386 if(
entry.type == fs::file_type::regular)
396 auto task = ts.pool->schedule(checking_dependencies_job_name<T>(),
399 auto assets = am.get_assets<T>();
400 for(
const auto& asset : assets)
402 auto meta = am.get_metadata(asset.uid());
405 if(has_depencency<T>(absolute_path,
entry.path))
429 [&ts, &am](
const std::string& ext,
const auto& ref_path,
const auto& synced_paths,
bool is_initial_listing)
431 auto paths = remove_meta_tag(synced_paths);
433 for(
const auto& output : paths)
436 if(is_initial_listing && fs::exists(output, err))
440 auto key = get_asset_key(output);
441 if(check_files_integrity(key, output))
443 auto task = ts.pool->schedule(get_job_name<T>(),
444 [&am, ref_path, output]()
454 syncer.
set_mapping(
type +
".meta", {
".asset"}, on_modified, on_modified, on_removed, on_renamed);
459static void watch_synced(
rtti::context& ctx, std::vector<uint64_t>& watchers,
const fs::path& dir)
464 watchers.push_back(watch_id);
478 [&ts, &am](
const std::string& ext,
const auto& ref_path,
const auto& synced_paths,
bool is_initial_listing)
480 auto paths = remove_meta_tag(synced_paths);
487 for(
const auto& output : paths)
490 std::find(std::begin(platform_supported), std::end(platform_supported), output.extension().string());
492 if(it == std::end(platform_supported))
498 if(is_initial_listing && fs::exists(output, err))
503 auto key = get_asset_key(output);
504 if(check_files_integrity(key, output))
506 auto task = ts.pool->schedule(get_job_name<gfx::shader>(),
507 [&am, ref_path, output]()
518 {
".asset.dx11",
".asset.dx12",
".asset.gl",
".asset.spirv"},
527void watch_synced<gfx::shader>(
rtti::context& ctx, std::vector<uint64_t>& watchers,
const fs::path& dir)
532 const auto watch_id = watch_assets<gfx::shader>(ctx, dir,
fs::pattern_filter(
"*" +
type +
".asset" + renderer_extension),
true);
533 watchers.push_back(watch_id);
542 const auto on_dir_modified =
543 [](
const std::string& ext,
const auto& ,
const auto& ,
bool )
547 const auto on_dir_removed = [](
const std::string& ext,
const auto& ,
const auto& synced_paths)
549 for(
const auto& synced_path : synced_paths)
552 fs::remove_all(synced_path, err);
556 const auto on_dir_renamed = [](
const std::string& ext,
const auto& ,
const auto& synced_paths)
558 for(
const auto& synced_path : synced_paths)
561 fs::rename(synced_path.first, synced_path.second, err);
568 std::vector<uint64_t>& watchers,
570 const fs::path& data_dir,
571 const fs::path& meta_dir,
574 setup_directory(ctx, syncer);
577 const auto on_file_removed = [&am](
const std::string& ext,
const auto& ref_path,
const auto& synced_paths)
579 for(
const auto& synced_path : synced_paths)
582 fs::remove_all(synced_path, err);
584 am.remove_asset_info_for_path(ref_path);
588 const auto on_file_renamed = [](
const std::string& ext,
const auto& ,
const auto& synced_paths)
590 for(
const auto& synced_path : synced_paths)
593 fs::rename(synced_path.first, synced_path.second, err);
597 const auto on_file_modified =
598 [&am](
const std::string& ext,
const auto& ref_path,
const auto& synced_paths,
bool is_initial_listing)
600 for(
const auto& synced_path : synced_paths)
604 if(fs::exists(synced_path, err))
609 if(meta.uid.is_nil())
612 meta = am.generate_metadata(key);
614 meta.uid = am.add_asset_info_for_path(ref_path, meta,
true);
622 for(
const auto&
type : asset_set)
624 syncer.
set_mapping(
type, {
".meta"}, on_file_modified, on_file_modified, on_file_removed, on_file_renamed);
630 auto id = watch_assets_depenencies<gfx::shader>(ctx, data_dir,
fs::pattern_filter(
"*" + dep_ex));
631 watchers.emplace_back(
id);
636 auto id = watch_assets_depenencies<ui_tree>(ctx, data_dir,
fs::pattern_filter(
"*" + dep_ex));
637 watchers.emplace_back(
id);
640 syncer.
sync(data_dir, meta_dir);
650 std::vector<uint64_t>& watchers,
652 const fs::path& meta_dir,
653 const fs::path& cache_dir,
656 setup_directory(ctx, syncer);
658 auto on_removed = [](
const std::string& ext,
const auto& ,
const auto& synced_paths)
660 for(
const auto& synced_path : synced_paths)
662 auto synced_asset = remove_meta_tag(synced_path);
664 fs::remove_all(synced_asset, err);
668 auto on_renamed = [](
const std::string& ext,
const auto& ,
const auto& synced_paths)
670 for(
const auto& synced_path : synced_paths)
672 auto synced_old_asset = remove_meta_tag(synced_path.first);
673 auto synced_new_asset = remove_meta_tag(synced_path.second);
675 fs::rename(synced_old_asset, synced_new_asset, err);
679 add_to_syncer<gfx::texture>(ctx, syncer, on_removed, on_renamed);
680 add_to_syncer<gfx::shader>(ctx, syncer, on_removed, on_renamed);
681 add_to_syncer<mesh>(ctx, syncer, on_removed, on_renamed);
682 add_to_syncer<material>(ctx, syncer, on_removed, on_renamed);
683 add_to_syncer<animation_clip>(ctx, syncer, on_removed, on_renamed);
684 add_to_syncer<prefab>(ctx, syncer, on_removed, on_renamed);
685 add_to_syncer<scene_prefab>(ctx, syncer, on_removed, on_renamed);
686 add_to_syncer<physics_material>(ctx, syncer, on_removed, on_renamed);
687 add_to_syncer<audio_clip>(ctx, syncer, on_removed, on_renamed);
688 add_to_syncer<font>(ctx, syncer, on_removed, on_renamed);
689 add_to_syncer<script>(ctx, syncer, on_removed, on_renamed);
690 add_to_syncer<ui_tree>(ctx, syncer, on_removed, on_renamed);
691 add_to_syncer<style_sheet>(ctx, syncer, on_removed, on_renamed);
693 syncer.
sync(meta_dir, cache_dir);
701 watch_synced<gfx::texture>(ctx, watchers, cache_dir);
702 watch_synced<gfx::shader>(ctx, watchers, cache_dir);
703 watch_synced<mesh>(ctx, watchers, cache_dir);
704 watch_synced<material>(ctx, watchers, cache_dir);
705 watch_synced<animation_clip>(ctx, watchers, cache_dir);
706 watch_synced<prefab>(ctx, watchers, cache_dir);
707 watch_synced<scene_prefab>(ctx, watchers, cache_dir);
708 watch_synced<physics_material>(ctx, watchers, cache_dir);
709 watch_synced<audio_clip>(ctx, watchers, cache_dir);
710 watch_synced<font>(ctx, watchers, cache_dir);
711 watch_synced<script>(ctx, watchers, cache_dir);
712 watch_synced<ui_tree>(ctx, watchers, cache_dir);
713 watch_synced<style_sheet>(ctx, watchers, cache_dir);
724void asset_watcher::on_os_event(
rtti::context& ctx, os::event& e)
726 if(e.type == os::events::window)
729 if(e.window.type == os::window_event_id::focus_lost)
731 if(!os::window::is_any_focused())
737 if(
e.window.type == os::window_event_id::focus_gained)
739 if(os::window::is_any_focused())
750 APPLOG_TRACE(
"{}::{}", hpp::type_name_str(*
this), __func__);
753 ev.
on_os_event.connect(sentinel_, 1000,
this, &asset_watcher::on_os_event);
755 watch_assets(ctx,
"engine:/",
true);
762 APPLOG_TRACE(
"{}::{}", hpp::type_name_str(*
this), __func__);
764 unwatch_assets(ctx,
"engine:/");
770 auto& w = watched_protocols_[protocol];
776 setup_meta_syncer(ctx,
783 setup_cache_syncer(ctx,
793 auto& w = watched_protocols_[protocol];
796 w.meta_syncer.unsync();
797 w.cache_syncer.unsync();
799 watched_protocols_.erase(protocol);
A filter that combines include and exclude patterns for file/directory filtering.
void set_mapping(const std::string &ref_ext, const std::vector< std::string > &synced_ext, on_entry_created_t on_entry_created, on_entry_modified_t on_entry_modified, on_entry_removed_t on_entry_removed, on_entry_renamed_t on_entry_renamed)
Remaps a specific extension of the reference directory to extensions of the synced directory....
std::function< void(const std::string &, const rename_pair_t &, const std::vector< rename_pair_t > &)> on_entry_renamed_t
void sync(const fs::path &reference_dir, const fs::path &synced_dir)
Start syncing the synced_dir with reference to the reference_dir i.e changes that occur in the refere...
void set_directory_mapping(on_entry_created_t on_entry_created, on_entry_modified_t on_entry_modified, on_entry_removed_t on_entry_removed, on_entry_renamed_t on_entry_renamed)
std::function< void(const std::string &, const fs::path &, const std::vector< fs::path > &)> on_entry_removed_t
static void unwatch(std::uint64_t key)
Un-watches a previously registered file or directory.
static void touch(const fs::path &path, bool recursive, fs::file_time_type time=fs::now())
Sets the last modification time of a file or directory. by default sets the time to the current time.
static auto watch(const fs::path &path, const pattern_filter &filter, bool recursive, bool initial_list, clock_t::duration poll_interval, notify_callback callback) -> std::uint64_t
Watches a file or directory for modification and call back the specified std::function....
Manages assets, including loading, unloading, and storage.
void unload_group(const std::string &group)
Unloads all assets in a specified group.
auto deinit(rtti::context &ctx) -> bool
void watch_assets(rtti::context &ctx, const std::string &protocol, bool wait=false)
auto init(rtti::context &ctx) -> bool
void unwatch_assets(rtti::context &ctx, const std::string &protocol)
#define APPLOG_WARNING(...)
#define APPLOG_TRACE(...)
auto get_suported_formats< gfx::shader >() -> const std::vector< std::string > &
auto get_all_formats() -> const std::vector< std::vector< std::string > > &
auto get_compiled_directory_no_slash(const std::string &prefix={}) -> std::string
auto get_data_directory(const std::string &prefix={}) -> std::string
auto get_type() -> const std::string &
auto get_meta_directory_no_slash(const std::string &prefix={}) -> std::string
auto get_compiled_directory(const std::string &prefix={}) -> std::string
auto get_suported_dependencies_formats< gfx::shader >() -> const std::vector< std::string > &
auto get_meta_directory(const std::string &prefix={}) -> std::string
auto get_suported_formats() -> const std::vector< std::string > &
auto get_data_directory_no_slash(const std::string &prefix={}) -> std::string
auto get_suported_dependencies_formats() -> const std::vector< std::string > &
path extract_protocol(const path &_path)
Given the specified path/filename, resolve the final full filename. This will be based on either the ...
path reduce_trailing_extensions(const path &_path)
another.
path resolve_protocol(const path &_path)
Given the specified path/filename, resolve the final full filename. This will be based on either the ...
bool has_known_protocol(const path &_path)
Checks whether the path has a known protocol.
path replace(const path &_path, const path &_sequence, const path &_new_sequence)
Replacing any occurences of the specified path sequence with another.
auto to_string(const watcher::entry &e) -> std::string
path convert_to_protocol(const path &_path)
Oposite of the resolve_protocol this function tries to convert to protocol path from an absolute one.
auto get_renderer_platform_supported_filename_extensions() -> const std::vector< std::string > &
auto get_current_renderer_filename_extension() -> const std::string &
void end(encoder *_encoder)
auto start(seq_action action, const seq_scope_policy &scope_policy, hpp::source_location location) -> seq_id_t
Starts a new action.
auto compile< gfx::shader >(asset_manager &am, const fs::path &key, const fs::path &output, uint32_t flags) -> bool
auto compile(asset_manager &am, const fs::path &key, const fs::path &output_key, uint32_t flags=0) -> bool
auto get_job_name() -> std::string
void load_from_file(const std::string &absolute_path, animation_clip &obj)
void save_to_file(const std::string &absolute_path, const animation_clip &obj)
hpp::event< void(rtti::context &, os::event &e)> on_os_event
os events
static void set_needs_recompile(const std::string &protocol, bool now=false)