29#include <filedialog/filedialog.h>
45auto get_vscode_executable() -> fs::path
47 fs::path executablePath;
49#if UNRAVEL_PLATFORM_WINDOWS
54 std::vector<fs::path> possiblePaths = {
"C:\\Program Files\\Microsoft VS Code\\Code.exe",
55 "C:\\Program Files (x86)\\Microsoft VS Code\\Code.exe",
56 fs::path(std::getenv(
"LOCALAPPDATA")) /
"Programs" /
57 "Microsoft VS Code" /
"Code.exe"};
59 for(
const auto& path : possiblePaths)
63 executablePath = path;
68 if(executablePath.empty())
71 const char* pathEnv = std::getenv(
"PATH");
74 std::string pathEnvStr(pathEnv);
75 std::stringstream ss(pathEnvStr);
77 while(std::getline(ss,
token,
';'))
79 fs::path codePath = fs::path(
token) /
"Code.exe";
80 if(fs::exists(codePath))
82 executablePath = codePath;
89 if(executablePath.empty())
91 std::vector<fs::path> directoriesToSearch = {
"C:\\Program Files",
92 "C:\\Program Files (x86)",
93 fs::path(std::getenv(
"LOCALAPPDATA")) /
"Programs"};
95 for(
const auto& dir : directoriesToSearch)
99 for(
const auto&
entry : fs::recursive_directory_iterator(dir))
101 if(
entry.is_regular_file() &&
entry.path().filename() ==
"Code.exe")
103 executablePath =
entry.path();
107 if(!executablePath.empty())
112 catch(
const fs::filesystem_error&)
120 catch(
const std::exception& e)
122 std::cerr <<
"Error finding VSCode executable path on Windows: " <<
e.what() << std::endl;
125#elif UNRAVEL_PLATFORM_OSX
130 std::vector<fs::path> possibleAppPaths = {
"/Applications/Visual Studio Code.app",
131 "/Applications/Visual Studio Code - Insiders.app",
132 fs::path(std::getenv(
"HOME")) /
"Applications" /
133 "Visual Studio Code.app"};
135 for(
const auto& appPath : possibleAppPaths)
137 if(fs::exists(appPath))
140 fs::path codeExecutable = appPath /
"Contents" /
"MacOS" /
"Electron";
141 if(fs::exists(codeExecutable))
143 executablePath = codeExecutable;
149 if(executablePath.empty())
152 std::vector<fs::path> possibleLinks = {
"/usr/local/bin/code",
"/usr/bin/code"};
153 for(
const auto& linkPath : possibleLinks)
155 if(fs::exists(linkPath))
158 executablePath = fs::canonical(linkPath);
164 if(executablePath.empty())
167 const char* pathEnv = std::getenv(
"PATH");
170 std::string pathEnvStr(pathEnv);
171 std::stringstream ss(pathEnvStr);
173 while(std::getline(ss,
token,
':'))
175 fs::path codePath = fs::path(
token) /
"code";
176 if(fs::exists(codePath))
178 executablePath = fs::canonical(codePath);
185 catch(
const std::exception& e)
187 std::cerr <<
"Error finding VSCode executable path on macOS: " <<
e.what() << std::endl;
190#elif UNRAVEL_PLATFORM_LINUX
195 const char* pathEnv = std::getenv(
"PATH");
198 std::string pathEnvStr(pathEnv);
199 std::stringstream ss(pathEnvStr);
201 while(std::getline(ss,
token,
':'))
203 fs::path codePath = fs::path(
token) /
"code";
204 if(fs::exists(codePath) && fs::is_regular_file(codePath))
207 executablePath = fs::canonical(codePath);
213 if(executablePath.empty())
216 std::vector<fs::path> possiblePaths = {
220 "/usr/share/code/bin/code",
221 "/usr/share/code-insiders/bin/code",
222 "/usr/local/share/code/bin/code",
223 "/opt/visual-studio-code/bin/code",
224 "/var/lib/flatpak/app/com.visualstudio.code/current/active/files/bin/code",
225 fs::path(std::getenv(
"HOME")) /
".vscode" /
"bin" /
"code"};
227 for(
const auto& path : possiblePaths)
231 executablePath = path;
237 catch(
const std::exception& e)
239 std::cerr <<
"Error finding VSCode executable path on Linux: " <<
e.what() << std::endl;
243#error "Unsupported operating system."
246 return executablePath;
249void remove_extensions(std::vector<std::vector<std::string>>& resourceExtensions,
250 const std::vector<std::string>& extsToRemove)
253 std::unordered_set<std::string> extsToRemoveSet;
254 for(
const auto& ext : extsToRemove)
259 for(
auto outerIt = resourceExtensions.begin(); outerIt != resourceExtensions.end();)
261 std::vector<std::string>& innerVec = *outerIt;
263 innerVec.erase(std::remove_if(innerVec.begin(),
265 [&extsToRemoveSet](
const std::string& ext)
267 return extsToRemoveSet.find(string_utils::to_lower(ext)) !=
268 extsToRemoveSet.end();
274 outerIt = resourceExtensions.erase(outerIt);
282void generate_workspace_file(
const std::string& file_path,
283 const std::vector<std::vector<std::string>>& exclude_extensions,
284 const editor_settings& settings)
287 std::ostringstream json_stream;
289 json_stream <<
"{\n";
290 json_stream <<
" \"folders\": [\n";
291 json_stream <<
" {\n";
292 json_stream <<
" \"path\": \"..\"\n";
293 json_stream <<
" }\n";
294 json_stream <<
" ],\n";
295 json_stream <<
" \"settings\": {\n";
296 json_stream <<
" \"dotnet.preferCSharpExtension\": true,\n";
297 json_stream <<
" \"files.exclude\": {\n";
298 json_stream <<
" \"**/.git\": true,\n";
299 json_stream <<
" \"**/.svn\": true";
302 for(
const auto& extensions : exclude_extensions)
304 for(
const auto& ext : extensions)
309 std::string pattern =
"**/*" + ext;
312 json_stream <<
",\n";
313 json_stream <<
" \"" << pattern <<
"\": true";
319 json_stream <<
" },\n";
320 json_stream <<
" \"files.associations\": {\n";
321 json_stream <<
" \"*.rcss\": \"css\",\n";
322 json_stream <<
" \"*.rhtml\": \"html\"\n";
323 json_stream <<
" }\n";
324 json_stream <<
" }\n";
327 json_stream <<
",\n";
328 json_stream <<
" \"extensions\": {\n";
329 json_stream <<
" \"recommendations\": [\n";
330#if DOTNETPP_BACKEND_MONO
331 json_stream <<
" \"ms-vscode.mono-debug\",\n";
333 json_stream <<
" \"ms-dotnettools.csharp\"\n";
334 json_stream <<
" ]\n";
335 json_stream <<
" }\n";
338 json_stream <<
",\n";
339 json_stream <<
" \"launch\": {\n";
340 json_stream <<
" \"version\": \"0.2.0\",\n";
341 json_stream <<
" \"configurations\": [\n";
342#if DOTNETPP_BACKEND_MONO
343 json_stream <<
" {\n";
344 json_stream <<
" \"name\": \"Attach to Mono\",\n";
345 json_stream <<
" \"request\": \"attach\",\n";
346 json_stream <<
" \"type\": \"mono\",\n";
347 json_stream <<
" \"address\": \"" << settings.debugger.ip <<
"\",\n";
348 json_stream <<
" \"port\": " << settings.debugger.port <<
"\n";
349 json_stream <<
" }\n";
352 json_stream <<
" {\n";
353 json_stream <<
" \"name\": \"Attach to " << EDITOR_NAME <<
"\",\n";
354 json_stream <<
" \"type\": \"coreclr\",\n";
355 json_stream <<
" \"request\": \"attach\"\n";
356 json_stream <<
" \"processName\": \"" << EDITOR_NAME <<
"\"\n";
357 json_stream <<
" },\n";
358 json_stream <<
" {\n";
359 json_stream <<
" \"name\": \".NET Core Attach\",\n";
360 json_stream <<
" \"type\": \"coreclr\",\n";
361 json_stream <<
" \"request\": \"attach\"\n";
362 json_stream <<
" }\n";
364 json_stream <<
" ]\n";
365 json_stream <<
" }\n";
371 std::ofstream file(file_path);
374 file << json_stream.str();
392#if !DOTNETPP_BACKEND_MONO
393void generate_csproj(
const fs::path& source_directory,
394 const std::vector<fs::path>& external_dll_paths,
395 const fs::path& output_directory,
396 const std::string& project_name =
"MyLibrary",
397 std::string dotnet_sdk_version = {})
399 if(dotnet_sdk_version.empty())
401 dotnet_sdk_version = dotnet::get_dotnet_version();
406 fs::create_directories(output_directory);
408 catch(
const fs::filesystem_error& e)
410 throw std::runtime_error(
"Failed to create output directory: " + std::string(
e.what()));
414 if(!fs::exists(source_directory) || !fs::is_directory(source_directory))
416 throw std::runtime_error(
"Source directory does not exist or is not a directory: " + source_directory.string());
420 for(
const auto& dll_path : external_dll_paths)
422 if(!fs::exists(dll_path) || !fs::is_regular_file(dll_path))
424 throw std::runtime_error(
"External DLL does not exist or is not a file: " + dll_path.string());
429 std::vector<fs::path> csharp_sources;
432 for(
const auto&
entry : fs::recursive_directory_iterator(source_directory))
434 if(
entry.is_regular_file() &&
entry.path().extension() ==
".cs")
437 fs::path relative_path = fs::relative(
entry.path(), source_directory);
438 csharp_sources.push_back(relative_path);
442 catch(
const fs::filesystem_error& e)
444 throw std::runtime_error(
"Error while iterating source directory: " + std::string(
e.what()));
448 std::string csharp_source_items;
449 for(
const auto& source_file : csharp_sources)
452 std::string source_file_str = source_file.string();
453 fs::path full_physical_path = fs::absolute(source_directory / source_file);
454 std::string full_physical_path_str = full_physical_path.string();
457 csharp_source_items +=
" <Compile Include=\"" + full_physical_path_str +
"\">\n";
458 csharp_source_items +=
" <Link>" + source_file_str +
"</Link>\n";
459 csharp_source_items +=
" </Compile>\n";
463 std::string external_dll_references;
464 for(
const auto& dll_path : external_dll_paths)
466 std::string dll_name = dll_path.filename().string();
467 fs::path dll_absolute_path = fs::absolute(dll_path);
468 std::string dll_absolute_path_str = dll_absolute_path.string();
470 external_dll_references +=
" <Reference Include=\"" + dll_name +
"\">\n";
471 external_dll_references +=
" <HintPath>" + dll_absolute_path_str +
"</HintPath>\n";
472 external_dll_references +=
" <Private>False</Private>\n";
473 external_dll_references +=
" </Reference>\n";
479 std::string csproj_content;
480 csproj_content +=
"<Project Sdk=\"Microsoft.NET.Sdk\">\n";
481 csproj_content +=
" <PropertyGroup>\n";
482 csproj_content +=
" <TargetFramework>net" + dotnet_sdk_version +
"</TargetFramework>\n";
483 csproj_content +=
" <OutputType>Library</OutputType>\n";
484 csproj_content +=
" <AssemblyName>" + project_name +
"</AssemblyName>\n";
485 csproj_content +=
" <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\n";
486 csproj_content +=
" <ImplicitUsings>disable</ImplicitUsings>\n";
487 csproj_content +=
" <Nullable>disable</Nullable>\n";
488 csproj_content +=
" <GenerateAssemblyInfo>false</GenerateAssemblyInfo>\n";
489 csproj_content +=
" <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>\n";
490 csproj_content +=
" <BaseOutputPath>temp/bin</BaseOutputPath>\n";
491 csproj_content +=
" <BaseIntermediateOutputPath>temp/obj</BaseIntermediateOutputPath>\n";
493 " <EnableDefaultCompileItems>false</EnableDefaultCompileItems>\n";
494 csproj_content +=
" </PropertyGroup>\n";
495 csproj_content +=
" <ItemGroup>\n";
496 csproj_content += csharp_source_items;
497 csproj_content +=
" </ItemGroup>\n";
498 csproj_content +=
" <ItemGroup>\n";
499 csproj_content += external_dll_references;
500 csproj_content +=
" </ItemGroup>\n";
501 csproj_content +=
"</Project>\n";
504 fs::path csproj_path = output_directory / (project_name +
".csproj");
507 std::ofstream csproj_file(csproj_path);
508 if(!csproj_file.is_open())
510 APPLOG_ERROR(
"Failed to create .csproj file at {}", csproj_path.string());
514 csproj_file << csproj_content;
519void generate_csproj_legacy(
const fs::path& source_directory,
520 const std::vector<fs::path>& external_dll_paths,
521 const fs::path& output_directory,
522 const std::string& project_name =
"MyLibrary",
523 const std::string& dotnet_framework_version =
"v4.7.1")
526 fs::path output_path = fs::path(
"temp") /
"bin" /
"Debug";
527 fs::path intermediate_output_path = fs::path(
"temp") /
"obj" /
"Debug";
532 fs::create_directories(output_directory);
534 catch(
const fs::filesystem_error& e)
536 throw std::runtime_error(
"Failed to create output directory: " + std::string(
e.what()));
540 if(!fs::exists(source_directory) || !fs::is_directory(source_directory))
542 throw std::runtime_error(
"Source directory does not exist or is not a directory: " + source_directory.string());
546 for(
const auto& dll_path : external_dll_paths)
548 if(!fs::exists(dll_path) || !fs::is_regular_file(dll_path))
550 throw std::runtime_error(
"External DLL does not exist or is not a file: " + dll_path.string());
555 std::vector<fs::path> csharp_sources;
558 for(
const auto&
entry : fs::recursive_directory_iterator(source_directory))
560 if(
entry.is_regular_file() &&
entry.path().extension() ==
".cs")
563 fs::path relative_path = fs::relative(
entry.path(), output_directory);
564 csharp_sources.push_back(relative_path);
568 catch(
const fs::filesystem_error& e)
570 throw std::runtime_error(
"Error while iterating source directory: " + std::string(
e.what()));
574 std::string csharp_source_items;
575 for(
const auto& source_file : csharp_sources)
578 std::string source_file_str = source_file.string();
579 csharp_source_items +=
" <Compile Include=\"" + source_file_str +
"\" />\n";
583 std::string external_dll_references;
584 for(
const auto& dll_path : external_dll_paths)
586 std::string dll_name = dll_path.filename().string();
587 fs::path dll_absolute_path = fs::absolute(dll_path);
588 std::string dll_absolute_path_str = dll_absolute_path.string();
590 external_dll_references +=
" <Reference Include=\"" + dll_name +
"\">\n";
591 external_dll_references +=
" <HintPath>" + dll_absolute_path_str +
"</HintPath>\n";
592 external_dll_references +=
" <Private>False</Private>\n";
593 external_dll_references +=
" </Reference>\n";
597 std::string csproj_content;
598 csproj_content +=
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
599 csproj_content +=
"<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" "
600 "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n";
601 csproj_content +=
" <PropertyGroup>\n";
602 csproj_content +=
" <LangVersion>9.0</LangVersion>\n";
603 csproj_content +=
" </PropertyGroup>\n";
604 csproj_content +=
" <PropertyGroup>\n";
605 csproj_content +=
" <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n";
606 csproj_content +=
" <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n";
607 csproj_content +=
" <ProductVersion>10.0.20506</ProductVersion>\n";
608 csproj_content +=
" <SchemaVersion>2.0</SchemaVersion>\n";
609 csproj_content +=
" <RootNamespace></RootNamespace>\n";
610 csproj_content +=
" <ProjectGuid>{" + hpp::to_string_upper(uid) +
"}</ProjectGuid>\n";
611 csproj_content +=
" <OutputType>Library</OutputType>\n";
612 csproj_content +=
" <AppDesignerFolder>Properties</AppDesignerFolder>\n";
613 csproj_content +=
" <AssemblyName>" + project_name +
"</AssemblyName>\n";
614 csproj_content +=
" <TargetFrameworkVersion>" + dotnet_framework_version +
"</TargetFrameworkVersion>\n";
615 csproj_content +=
" <FileAlignment>512</FileAlignment>\n";
616 csproj_content +=
" <BaseDirectory>.</BaseDirectory>\n";
617 csproj_content +=
" <OutputPath>" + output_path.string() +
"</OutputPath>\n";
619 " <IntermediateOutputPath>" + intermediate_output_path.string() +
"</IntermediateOutputPath>\n";
621 csproj_content +=
" </PropertyGroup>\n";
627 csproj_content +=
" <ItemGroup>\n";
628 csproj_content += csharp_source_items;
629 csproj_content +=
" </ItemGroup>\n";
632 csproj_content +=
" <ItemGroup>\n";
633 csproj_content += external_dll_references;
634 csproj_content +=
" </ItemGroup>\n";
640 csproj_content +=
" <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n";
643 csproj_content +=
" <Target Name=\"GenerateTargetFrameworkMonikerAttribute\" />\n";
647 " <!-- To modify your build process, add your task inside one of the targets below and uncomment it.\n";
648 csproj_content +=
" Other similar extension points exist, see Microsoft.Common.targets.\n";
649 csproj_content +=
" <Target Name=\"BeforeBuild\">\n";
650 csproj_content +=
" </Target>\n";
651 csproj_content +=
" <Target Name=\"AfterBuild\">\n";
652 csproj_content +=
" </Target>\n";
653 csproj_content +=
" -->\n";
655 csproj_content +=
"</Project>\n";
658 fs::path csproj_path = output_directory / (project_name +
".csproj");
661 std::ofstream csproj_file(csproj_path);
662 if(!csproj_file.is_open())
664 APPLOG_ERROR(
"Failed to create .csproj file at {}", csproj_path.string());
668 csproj_file << csproj_content;
674auto trim_line = [](std::string& line)
677 line.erase(std::find_if(line.rbegin(),
681 return !std::isspace(int(ch));
687auto parse_line(std::string& line,
const fs::path& fs_parent_path) ->
bool
689#if UNRAVEL_PLATFORM_WINDOWS
691 if(line.find(
"[ApplicationDirectory]") != std::string::npos)
693 std::size_t pos = line.find(
':');
694 if(pos != std::string::npos)
696 line = line.substr(pos + 2);
704 size_t pos = line.find(
"=> ");
705 bool found = pos != std::string::npos;
710 pos = line.find(
'\t');
711 found = pos != std::string::npos;
719 line = line.substr(pos + 3);
723 line = line.substr(pos + 1);
725 size_t address_pos = line.find(
" (0x");
726 if(address_pos != std::string::npos)
728 line = line.substr(0, address_pos);
733 fs::path fs_path(line);
737 fs_path = fs_parent_path / fs_path;
738 line = fs_path.string();
741 if(fs::exists(fs_path) && fs::exists(fs_parent_path))
743 if(fs::equivalent(fs_path.parent_path(), fs_parent_path))
754auto get_subprocess_params(
const fs::path& file) -> std::vector<std::string>
756 std::vector<std::string> params;
758#if UNRAVEL_PLATFORM_WINDOWS
759 params.emplace_back(
fs::resolve_protocol(
"editor:/tools/dependencies/Dependencies.exe").
string());
760 params.emplace_back(
"-modules");
761 params.emplace_back(file.string());
765 params.emplace_back(
"ldd");
766 params.emplace_back(file.string());
771auto parse_dependencies(
const std::string&
input,
const fs::path& fs_parent_path) -> std::vector<std::string>
773 std::vector<std::string> dependencies;
774 std::stringstream ss(
input);
777 while(std::getline(ss, line))
779 if(parse_line(line, fs_parent_path))
781 dependencies.push_back(line);
787auto get_dependencies(
const fs::path& file) -> std::vector<std::string>
789 auto parent_path = file.parent_path();
791 auto params = get_subprocess_params(file);
796 return parse_dependencies(result.out_output, parent_path);
799#if !DOTNETPP_BACKEND_MONO
801auto parse_version_name(
const std::string&
name) -> std::vector<int>
803 std::vector<int> parts;
807 if(c >=
'0' && c <=
'9')
813 parts.push_back(current.empty() ? 0 : std::atoi(current.c_str()));
823 parts.push_back(std::atoi(current.c_str()));
832auto pick_highest_version_dir(
const fs::path& base,
int preferred_major = -1) -> fs::path
835 std::vector<int> best_version;
836 bool best_matches_major =
false;
839 for(
const auto&
entry : fs::directory_iterator(base, ec))
841 if(!
entry.is_directory(ec))
845 auto version = parse_version_name(
entry.path().filename().string());
850 bool matches_major = preferred_major >= 0 &&
version[0] == preferred_major;
853 bool better = best.empty();
854 if(!better && matches_major != best_matches_major)
856 better = matches_major;
860 better = std::lexicographical_compare(best_version.begin(),
869 best_matches_major = matches_major;
876auto version_major(
const std::string&
version) ->
int
878 int major = std::atoi(
version.c_str());
879 return major > 0 ? major : -1;
883auto save_scene_impl(
rtti::context& ctx,
const fs::path& path) ->
bool
888auto add_extension_if_missing(
const std::string& p) -> fs::path
890 fs::path def_path =
p;
899auto save_scene_as_impl(
rtti::context& ctx, fs::path& path,
const std::string& default_name = {}) ->
bool
909 if(em.is_prefab_mode())
911 em.save_prefab_changes(ctx);
917 if(!default_name.empty())
919 auto def_path = add_extension_if_missing(default_name);
921 save_path += def_path.string();
925 if(native::save_file_dialog(picked,
933 path = add_extension_if_missing(picked);
935 return save_scene_impl(ctx, path);
941void try_delete_empty_parents(
const fs::path&
start,
const fs::path& root, fs::error_code& ec)
943 fs::path current =
start.parent_path();
944 while(current != root && fs::is_empty(current, ec))
946 APPLOG_TRACE(
"Removing Empty Parent Directory {}", current.generic_string());
947 fs::remove(current, ec);
948 current = current.parent_path();
952void remove_unreferenced_files(
const fs::path& root)
955 const fs::recursive_directory_iterator
end;
957 std::vector<fs::path> deleted_dirs;
961 fs::recursive_directory_iterator it(root, ec);
964 const fs::path current_path = it->path();
972 APPLOG_TRACE(
"Removing Script {}", current_path.generic_string());
973 fs::remove(current_path, ec);
974 deleted_dirs.push_back(current_path.parent_path());
983 fs::recursive_directory_iterator it(root, ec);
986 const fs::path current_path = it->path();
989 if(current_path.extension().generic_string() ==
".manifest")
991 APPLOG_TRACE(
"Removing Manifest {}", current_path.generic_string());
992 fs::remove(current_path, ec);
995 if(current_path.extension().generic_string() ==
".temp")
997 APPLOG_TRACE(
"Removing Temp File {}", current_path.generic_string());
998 fs::remove(current_path, ec);
1005 fs::recursive_directory_iterator it(root, ec);
1008 const fs::path current_path = it->path();
1011 if(fs::is_directory(current_path, ec) && fs::is_empty(current_path, ec))
1013 APPLOG_TRACE(
"Removing Empty Directory {}", current_path.generic_string());
1014 fs::remove(current_path, ec);
1015 deleted_dirs.push_back(current_path.parent_path());
1021 std::sort(deleted_dirs.begin(), deleted_dirs.end());
1022 deleted_dirs.erase(std::unique(deleted_dirs.begin(), deleted_dirs.end()), deleted_dirs.end());
1023 std::sort(deleted_dirs.begin(),
1025 [](
const fs::path&
a,
const fs::path&
b)
1027 return a.string().size() > b.string().size();
1031 for(
const auto& path : deleted_dirs)
1033 try_delete_empty_parents(path, root, ec);
1042 if(play.is_active())
1046 prompt_save_scene(ctx,
1061 std::string*
error) ->
bool
1074 *
error =
"Failed to load scene: " + asset.id();
1079 em.sync_prefab_instances(ctx, &
scene);
1080 em.clear_unsaved_changes();
1086 pm.save_project_editor_settings();
1102 em.clear_unsaved_changes();
1108 pm.save_project_editor_settings();
1114 const fs::path& path,
1116 bool show_notification) ->
bool
1119 if(play.is_active())
1124 fs::path absolute = path;
1129 absolute = fs::absolute(absolute);
1141 if(show_notification)
1156 pm.save_project_editor_settings();
1166 if(play.is_active())
1168 play.set_active(ctx,
false);
1172 if(native::open_file_dialog(picked,
1184 return open_scene_from_asset(ctx, asset);
1192 return prompt_save_scene(ctx,
1208 if(em.is_prefab_mode())
1210 em.save_prefab_changes(ctx);
1217 if(save_scene_as_impl(ctx, picked,
"Scene3D"))
1229 return save_scene_impl(ctx, path);
1240 return save_scene_as_impl(ctx, p,
scene.
source.name());
1247 if(play.is_active())
1254 if(!em.has_unsaved_changes())
1261 "Do you want to save the changes you made?",
1282 if(play.is_active())
1287 prompt_save_scene(ctx, [&ctx]() {
1299 if(play.is_active())
1304 if(!pm.has_open_project())
1310 pm.close_project(ctx);
1313 em.
queue_action(
"Reload Project", [&ctx, &pm, project_path]()
1315 pm.open_project(ctx, project_path);
1328 auto&
settings = pm.get_settings();
1329 bool valid_location = fs::is_directory(params.deploy_location);
1331 return valid_location && valid_startup_scene;
1336 const deploy_settings& params) -> std::map<std::string, tpp::shared_future<void>>
1340 std::map<std::string, tpp::shared_future<void>> jobs;
1341 std::vector<tpp::shared_future<void>> jobs_seq;
1348 auto project_name = pm.get_name();
1349 auto executable_path = params.deploy_location / (project_name + fs::executable_extension());
1353 if(params.deploy_dependencies)
1355 APPLOG_INFO(
"Clearing {}", params.deploy_location.generic_string());
1356 fs::remove_all(params.deploy_location, ec);
1357 fs::create_directories(params.deploy_location, ec);
1361 ->schedule(
"Deploying Dependencies",
1362 [params, executable_path]()
1366 fs::path app_executable =
1368 auto deps = get_dependencies(app_executable);
1371 for(
const auto& dep : deps)
1374 fs::path(dep).generic_string(),
1375 params.deploy_location.generic_string());
1376 fs::copy(dep, params.deploy_location, fs::copy_options::overwrite_existing, ec);
1381 app_executable.generic_string(),
1382 params.deploy_location.generic_string());
1383 fs::copy(app_executable, executable_path, fs::copy_options::overwrite_existing, ec);
1388 jobs[
"Deploying Dependencies"] = job;
1389 jobs_seq.emplace_back(job);
1394 ->schedule(
"Deploying Project Settings",
1400 fs::path dst = params.deploy_location /
"data" /
"app" /
"settings";
1405 fs::remove_all(dst, ec);
1406 fs::create_directories(dst, ec);
1408 APPLOG_TRACE(
"Copying {} -> {}", data.generic_string(), dst.generic_string());
1409 fs::copy(data, dst, fs::copy_options::recursive, ec);
1415 jobs[
"Deploying Project Settings"] = job;
1416 jobs_seq.emplace_back(job);
1423 "Deploying Project Data",
1431 fs::path cached_data =
1434 APPLOG_TRACE(
"Clearing {}", cached_data.generic_string());
1435 fs::remove_all(cached_data, ec);
1436 fs::create_directories(cached_data, ec);
1438 APPLOG_TRACE(
"Copying {} -> {}", data.generic_string(), cached_data.generic_string());
1439 fs::copy(data, cached_data, fs::copy_options::recursive, ec);
1441 remove_unreferenced_files(cached_data);
1445 fs::path cached_data = params.deploy_location /
"data" /
"app" /
"assets.pack";
1446 APPLOG_TRACE(
"Creating Asset Pack -> {}", cached_data.generic_string());
1447 am.save_database(
"app:/", cached_data);
1454 jobs[
"Deploying Project Data"] = job;
1455 jobs_seq.emplace_back(job);
1462 "Deploying Engine Data",
1469 fs::path cached_data =
1473 APPLOG_TRACE(
"Clearing {}", cached_data.generic_string());
1474 fs::remove_all(cached_data, ec);
1475 fs::create_directories(cached_data, ec);
1477 APPLOG_TRACE(
"Copying {} -> {}", data.generic_string(), cached_data.generic_string());
1478 fs::copy(data, cached_data, fs::copy_options::recursive, ec);
1480 remove_unreferenced_files(cached_data);
1484 fs::path cached_data = params.deploy_location /
"data" /
"engine" /
"assets.pack";
1485 APPLOG_TRACE(
"Creating Asset Pack -> {}", cached_data.generic_string());
1486 am.save_database(
"engine:/", cached_data);
1492 jobs[
"Deploying Engine Data..."] = job;
1493 jobs_seq.emplace_back(job);
1496#if DOTNETPP_BACKEND_MONO
1502 [params, &am, &ctx]()
1507 fs::path assembly_path = dotnet::get_core_assembly_path();
1508 fs::path assembly_dir = assembly_path.parent_path();
1509 fs::path lib_version = assembly_dir.filename();
1511 fs::path assembly_dir_gac = assembly_dir.parent_path() /
"gac";
1516 fs::path cached_data = params.deploy_location /
"data" /
"engine" /
"mono" /
"lib";
1518 APPLOG_TRACE(
"Clearing {}", cached_data.generic_string());
1521 APPLOG_TRACE(
"Creating directories {}", cached_data.generic_string());
1522 fs::create_directories(cached_data, ec);
1524 auto mono_libraries = dotnet::get_common_library_names_for_deploy();
1526 fs::path lib_dir = assembly_dir.parent_path().parent_path();
1527 for(
const auto& path : mono_libraries)
1529 fs::path so_file = lib_dir / path;
1530 if(fs::exists(so_file))
1532 auto dst = cached_data / path;
1533 APPLOG_TRACE(
"Copying {} -> {}", so_file.generic_string(), dst.generic_string());
1534 fs::copy(so_file, dst, fs::copy_options::overwrite_existing, ec);
1539 cached_data /=
"mono";
1541 APPLOG_TRACE(
"Clearing {}", cached_data.generic_string());
1542 fs::remove_all(cached_data, ec);
1544 fs::path cached_data_lib_version = cached_data / lib_version;
1545 fs::path cached_data_gac = cached_data /
"gac";
1547 fs::create_directories(cached_data, ec);
1550 assembly_dir.generic_string(),
1551 cached_data.generic_string());
1552 fs::copy(assembly_dir, cached_data_lib_version, fs::copy_options::recursive, ec);
1554 fs::copy(assembly_dir_gac, cached_data_gac, fs::copy_options::recursive, ec);
1557 fs::path config_dir = paths.config_dir;
1558 config_dir /=
"mono";
1561 fs::path cached_data = params.deploy_location /
"data" /
"engine" /
"mono" /
"etc";
1562 cached_data /=
"mono";
1564 APPLOG_TRACE(
"Clearing {}", cached_data.generic_string());
1565 fs::remove_all(cached_data, ec);
1566 fs::create_directories(cached_data, ec);
1568 APPLOG_TRACE(
"Copying {} -> {}", config_dir.generic_string(), cached_data.generic_string());
1569 fs::copy(config_dir, cached_data, fs::copy_options::recursive, ec);
1575 jobs[
"Deploying Mono..."] = job;
1576 jobs_seq.emplace_back(job);
1595 const std::string runtime_dir = dotnet::managed_runtime_dir();
1597 fs::path dst = params.deploy_location /
"data" /
"engine" / runtime_dir;
1600 fs::remove_all(dst, ec);
1601 fs::create_directories(dst, ec);
1603 APPLOG_TRACE(
"Copying {} -> {}", src.generic_string(), dst.generic_string());
1604 fs::copy(src, dst, fs::copy_options::recursive, ec);
1611 fs::path dotnet_root = dotnet::get_core_assembly_path();
1616 int preferred_major = version_major(dotnet::get_dotnet_version());
1619 pick_highest_version_dir(dotnet_root /
"host" /
"fxr", preferred_major);
1620 fs::path shared_src =
1621 pick_highest_version_dir(dotnet_root /
"shared" /
"Microsoft.NETCore.App",
1624 if(fxr_src.empty() || shared_src.empty())
1626 APPLOG_WARNING(
"Deploying .NET - could not locate hostfxr/shared framework "
1627 "under {}; the deployed game will require an installed .NET "
1629 dotnet_root.generic_string());
1633 fs::path runtime_dst = params.deploy_location /
"data" /
"engine" /
"dotnet";
1635 APPLOG_TRACE(
"Clearing {}", runtime_dst.generic_string());
1636 fs::remove_all(runtime_dst, ec);
1638 fs::path fxr_dst = runtime_dst /
"host" /
"fxr" / fxr_src.filename();
1639 fs::path shared_dst =
1640 runtime_dst /
"shared" /
"Microsoft.NETCore.App" / shared_src.filename();
1642 fs::create_directories(fxr_dst, ec);
1643 fs::create_directories(shared_dst, ec);
1646 fxr_src.generic_string(),
1647 fxr_dst.generic_string());
1648 fs::copy(fxr_src, fxr_dst, fs::copy_options::recursive, ec);
1651 shared_src.generic_string(),
1652 shared_dst.generic_string());
1653 fs::copy(shared_src, shared_dst, fs::copy_options::recursive, ec);
1660 jobs[
"Deploying .NET..."] = job;
1661 jobs_seq.emplace_back(job);
1665 tpp::when_all(std::begin(jobs_seq), std::end(jobs_seq))
1666 .then(tpp::this_thread::get_id(),
1667 [params, executable_path](
auto f)
1669 if(params.deploy_and_run)
1671 run_project(executable_path);
1675 fs::show_in_graphical_env(params.deploy_location);
1692 fs::create_directories(workspace_folder, err);
1695 formats.emplace_back(std::vector<std::string>{
".meta"});
1696 formats.emplace_back(std::vector<std::string>{
".asset"});
1697 formats.emplace_back(std::vector<std::string>{
".manifest"});
1698 formats.emplace_back(std::vector<std::string>{
".temp"});
1705 auto workspace_file = workspace_folder / fmt::format(
"{}-workspace.code-workspace", project_name);
1706 generate_workspace_file(workspace_file.string(), formats,
editor_settings);
1714#if DOTNETPP_BACKEND_MONO
1715 generate_csproj_legacy(source_path, {engine_dep}, output_path, project_name);
1717 generate_csproj(source_path, {engine_dep}, output_path, project_name);
1726 auto vscode_exe = pm.get_editor_settings().external_tools.vscode_executable;
1728 [vscode_exe, project_name, file, line]()
1730 auto external_tool = vscode_exe;
1731 if(external_tool.empty())
1733 external_tool = get_vscode_executable();
1736 static const char* tool =
"[Visual Studio Code]";
1737 static const char* setup_hint =
"Edit -> Editor Settings -> External Tools";
1739 if(external_tool.empty())
1742 APPLOG_ERROR(
"To configure {} visit : {}", tool, setup_hint);
1745 auto workspace_key = fmt::format(
"app:/.vscode/{}-workspace.code-workspace", project_name);
1749 {workspace_path.string(),
"-g", fmt::format(
"{}:{}", file.string(), line)});
1751 if(result.retcode != 0)
1753 APPLOG_ERROR(
"Cannot open external tool {} for file {}", tool, external_tool.string(), file.string());
1754 APPLOG_ERROR(
"To configure {} visit : {}", tool, setup_hint);
1765 for(
auto& asset : shaders)
1780 for(
auto& asset : textures)
1795 for(
auto& asset : meshes)
1811 for(
auto& asset :
assets)
1820 for(
auto& asset :
assets)
1836 for(
auto& asset : scripts)
1850 for(
auto& asset :
assets)
1864 if(!scn || !scn->registry)
1877 if(play.is_active())
1882 if(scripting.has_compilation_errors())
1886 *
error =
"All compiler errors must be fixed before you can enter Play Mode!";
1906 if(play.is_splash())
1908 info.
phase =
"splash";
1910 else if(play.is_simulation_running())
1912 info.
phase =
"running";
1914 else if(play.is_active())
1916 info.
phase =
"active";
1920 info.
phase =
"inactive";
1927 if(active && !can_enter_play(ctx,
error))
1938 if(!play.is_active() && !can_enter_play(ctx,
error))
1942 play.
toggle(ctx, allow_splash);
1949 if(!play.is_active())
1953 *
error =
"Play mode is not active";
1964 if(!play.is_active())
1968 *
error =
"Play mode is not active";
1972 if(!play.is_paused())
1976 *
error =
"Play mode must be paused to skip a frame";
1988 if(
auto* active = em.try_get_active_selection_as<entt::handle>())
1992 for(
const auto&
handle : em.try_get_selections_as_copy<entt::handle>())
2003 const std::vector<std::string>& entity_ids,
2005 std::string*
error) ->
bool
2009 if(!scn || !scn->registry)
2013 *
error =
"No active scene";
2022 for(
const auto&
id : entity_ids)
2029 *
error =
"Entity not found: " +
id;
2050 level::level_enum min_level,
2052 uint64_t after_id) -> std::vector<log_query_entry>
2058 auto snapshot = ctx.
get_cached<
hub>().get_panels().get_console_log_panel().snapshot_logs(min_level,
2061 std::vector<log_query_entry> out;
2062 out.reserve(snapshot.size());
2063 for(
auto&
entry : snapshot)
2072 out.push_back(std::move(item));
2078 const std::string& entity_id,
2079 bool include_components,
2080 std::string*
error) -> std::string
2084 if(!scn || !scn->registry)
2088 *
error =
"No active scene";
2093 if(entity_id.empty())
2095 if(
auto* active = em.try_get_active_selection_as<entt::handle>())
2103 *
error =
"No entity_id provided and no active entity selection";
2115 *
error =
"Entity not found: " + entity_id;
2121 if(!include_components)
2126 std::string escaped;
2127 escaped.reserve(components.size() + 8);
2128 for(
char c : components)
2152 if(!summary.empty() && summary.back() ==
'}')
2155 summary +=
",\"components_serialized\":\"" + escaped +
"\"}";
2166 *
error =
"Hub is not available";
2170 auto& panel = ctx.
get_cached<
hub>().get_panels().get_scene_panel();
2171 panel.set_visible(
true);
2182 *
error =
"Hub is not available";
2186 auto& panel = ctx.
get_cached<
hub>().get_panels().get_game_panel();
2187 panel.set_visible(
true);
2198 *
error =
"Renderer is not available";
2207 *
error =
"Main window is not available";
2211 auto& window = main_window->get_window();
2212 if(!window.is_open())
2216 *
error =
"Main window is not open";
2220 if(window.is_minimized())
2226 window.request_focus();
2231 const std::vector<std::string>& paths,
2232 const fs::path& target_path,
2233 bool async) -> std::vector<import_files_item>
2236 std::vector<import_files_item>
items;
2237 items.reserve(paths.size());
2239 fs::create_directories(target_path, ec);
2240 auto copy_one = [](
const fs::path& source,
const fs::path& dest,
bool is_directory) ->
bool
2245 fs::copy(source, dest, fs::copy_options::recursive | fs::copy_options::overwrite_existing, err);
2248 APPLOG_ERROR(
"Failed to import directory {}, error: {}", source.string(), err.message());
2256 APPLOG_ERROR(
"Failed to import file {}, error: {}", source.string(), err.message());
2261 for(
const auto& path : paths)
2264 fs::path source = fs::path(path).make_preferred();
2265 fs::path
filename = source.filename();
2266 fs::path dest = target_path /
filename;
2268 item.dest_path = dest.generic_string();
2269 item.is_directory = fs::is_directory(source, ec);
2271 if(!protocol.empty())
2273 item.dest_key = protocol.generic_string();
2278 auto job = ts.pool->schedule(
"Importing " +
filename.extension().string(),
2283 item.future = job.share();
2287 const bool ok = copy_one(source, dest, item.is_directory);
2288 item.future = tpp::make_ready_future<bool>(
bool(
ok)).share();
2290 items.push_back(std::move(item));
2296 std::chrono::milliseconds timeout) ->
bool
2298 const auto deadline = std::chrono::steady_clock::now() + timeout;
2300 for(
auto& item :
items)
2302 if(!item.future.valid())
2307 const auto remaining = std::chrono::duration_cast<std::chrono::milliseconds>(
2308 deadline - std::chrono::steady_clock::now());
2309 if(remaining.count() <= 0)
2314 const auto status = item.future.wait_for(remaining);
2315 if(status != std::future_status::ready)
2320 if(!item.future.get())
static void resume()
Resumes all watchers.
static void pause()
Pauses all watchers.
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.
Manages assets, including loading, unloading, and storage.
auto get_all_assets(const std::string &group) const -> std::vector< std::string >
Gets all assets.
auto get_assets(const std::string &group={}) const -> std::vector< asset_handle< T > >
Gets all assets in a specified group.
auto get_asset(const std::string &key, load_flags flags=load_flags::standard, load_mode mode=load_mode::immediate) -> asset_handle< T >
Gets an asset by its key.
static void show(std::function< void(defaults::scene_preset)> on_preset_selected)
Request the create scene modal to open.
static void cancel_if_pending()
Dismiss a pending create-scene modal without invoking the callback.
Main class representing a 3D mesh with support for different LODs, submeshes, and skinning.
auto get_project_editor_settings() -> project_editor_settings &
auto get_name() const -> const std::string &
void close_project(rtti::context &ctx)
static auto mark_all_dirty(scene &scn, bool force_full_first_frame=false) -> size_t
Flags every reflection probe in the scene for rebuild.
defaults::scene_preset preset
#define APPLOG_WARNING(...)
#define APPLOG_ERROR(...)
#define APPLOG_TRACE(...)
const fs::path * filename
ModalResult
Modal result flags for message box buttons.
auto ShowSaveConfirmation(const std::string &title, const std::string &message, std::function< void(ModalResult)> callback) -> std::shared_ptr< MsgBox >
Show a save confirmation dialog with Save/Don't Save/Cancel buttons.
NOTIFY_INLINE void PushNotification(const ImGuiToast &toast)
Insert a new toast in the list.
auto get_suported_formats< gfx::shader >() -> const std::vector< std::string > &
auto get_all_formats() -> const std::vector< std::vector< std::string > > &
auto get_format(bool include_dot=true) -> std::string
auto get_compiled_directory_no_slash(const std::string &prefix={}) -> std::string
auto is_format(const std::string &ex) -> bool
auto get_compiled_directory(const std::string &prefix={}) -> std::string
auto get_suported_formats() -> const std::vector< std::string > &
auto get_suported_formats_with_wildcard() -> std::vector< std::string >
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 convert_to_protocol(const path &_path)
Oposite of the resolve_protocol this function tries to convert to protocol path from an absolute one.
void end(encoder *_encoder)
auto to_lower(const std::string &str) -> std::string
auto call(const std::vector< std::string > &args_array, const std::vector< std::string > &environment_array={}) -> call_result
auto atomic_save_to_file(const fs::path &key, const asset_handle< T > &obj) -> bool
auto atomic_copy_file(const fs::path &src, const fs::path &dst, fs::error_code &ec) noexcept -> bool
auto generate_uuid() -> hpp::uuid
auto entity_id_string(entt::handle entity) -> std::string
Stable id string for MCP/editor tooling (UUID preferred).
auto find_entity_by_id(scene &scn, const std::string &id) -> entt::handle
Resolve an entity by UUID string or integral entt id.
auto entity_components_serialized(entt::handle entity) -> std::string
Full associative serialization of serializeable components (scene-file format).
auto entity_to_summary_json(entt::handle entity, int depth, int max_depth) -> std::string
JSON summary: transform, component pretty-names, optional children.
std::vector< math::vec3 > start
Thread-safe handle to an asset.
static void create_scene_from_preset(rtti::context &ctx, scene &scn, scene_preset preset)
Creates a 3D scene from a quality preset.
scene_preset
Quality presets for new scene creation (low = less expensive, high = more expensive).
Manages the entity-component-system (ECS) operations for the ACE framework.
void unload_scene()
Unloads the current scene.
auto get_active_scene(rtti::context &ctx) -> scene *
void clear(bool clear_unsaved=true)
void clear_unsaved_changes()
void queue_action(const std::string &name, const std::function< void()> &action)
static auto close_project(rtti::context &ctx) -> bool
static void run_project(const fs::path &executable_path)
static auto can_enter_play(rtti::context &ctx, std::string *error=nullptr) -> bool
static auto load_scene_from_asset(rtti::context &ctx, const asset_handle< scene_prefab > &asset, std::string *error=nullptr) -> bool
Non-modal scene load (shared by File menu + MCP). Clears edit state, loads asset, syncs prefabs,...
static auto skip_play_frame(rtti::context &ctx, std::string *error=nullptr) -> bool
static auto import_files(rtti::context &ctx, const std::vector< std::string > &paths, const fs::path &target_path, bool async=true) -> std::vector< import_files_item >
Copy external files/folders into target_path (content-browser Import parity).
static void open_workspace_on_file(const fs::path &file, int line=0)
static void recompile_shaders(const std::string &group="")
static void recompile_scripts(const std::string &group="")
static auto save_scene_to_path(rtti::context &ctx, const fs::path &path, bool update_source=true, bool show_notification=true) -> bool
Atomic-save active scene to path/key. When update_source is true, sets scene.source and project opene...
static void recompile_ui(const std::string &group="")
static auto open_scene(rtti::context &ctx) -> bool
static auto open_scene_from_asset(rtti::context &ctx, const asset_handle< scene_prefab > &asset) -> bool
static auto request_main_window_focus(rtti::context &ctx, std::string *error=nullptr) -> bool
Focus/raise the OS main window so asset watcher and similar focus-gated work can run (e....
static auto set_play_active(rtti::context &ctx, bool active, bool allow_splash=true, std::string *error=nullptr) -> bool
static auto get_play_state(rtti::context &ctx) -> play_state_info
static void clear_selection(rtti::context &ctx)
static void recompile_textures(const std::string &group="")
static auto focus_scene_panel(rtti::context &ctx, std::string *error=nullptr) -> bool
static auto set_selection(rtti::context &ctx, const std::vector< std::string > &entity_ids, bool add=false, std::string *error=nullptr) -> bool
static auto prompt_save_scene(rtti::context &ctx, const std::function< void()> &on_continue) -> bool
static auto get_recent_logs(rtti::context &ctx, level::level_enum min_level, size_t max_count, uint64_t after_id=0) -> std::vector< log_query_entry >
static auto inspect_entity(rtti::context &ctx, const std::string &entity_id, bool include_components, std::string *error=nullptr) -> std::string
static void recompile_all(const std::string &group="")
static auto focus_game_panel(rtti::context &ctx, std::string *error=nullptr) -> bool
static auto save_scene(rtti::context &ctx) -> bool
static auto new_scene(rtti::context &ctx) -> bool
static auto set_play_paused(rtti::context &ctx, bool paused, std::string *error=nullptr) -> bool
static auto reload_project(rtti::context &ctx) -> bool
static auto save_scene_as(rtti::context &ctx) -> bool
static auto rebuild_reflection_probes(rtti::context &ctx, bool force_full_first_frame=true) -> size_t
Flags every reflection probe across all loaded scenes for rebuild.
static auto toggle_play(rtti::context &ctx, bool allow_splash=true, std::string *error=nullptr) -> bool
static auto deploy_project(rtti::context &ctx, const deploy_settings ¶ms) -> std::map< std::string, tpp::shared_future< void > >
static auto wait_import_jobs(std::vector< import_files_item > &items, std::chrono::milliseconds timeout) -> bool
Block until all import copy jobs complete or timeout elapses.
static void recompile_meshes(const std::string &group="")
static auto new_scene_from_preset(rtti::context &ctx, defaults::scene_preset preset) -> bool
Non-modal new scene from preset (shared by create-scene modal + MCP). Cancels any pending create-scen...
static auto can_deploy_project(rtti::context &ctx, const deploy_settings ¶ms) -> bool
static void generate_script_workspace()
static auto get_selection(rtti::context &ctx) -> selection_info
static auto context() -> rtti::context &
One async content-browser-style import job (external path -> project folder).
Owns play-mode state and orchestrates the splash -> running lifecycle.
void toggle(rtti::context &ctx, bool allow_splash=true)
void set_paused(rtti::context &ctx, bool paused)
void skip_next_frame(rtti::context &ctx)
bool is_simulation_running
Represents a scene-specific prefab. Inherits from the generic prefab structure.
Represents a scene in the ACE framework, managing entities and their relationships.
asset_handle< scene_prefab > source
The source prefab asset handle for the scene.
auto load_from(const asset_handle< scene_prefab > &pfb, bool call_callbacks=true) -> bool
Loads a scene from a prefab asset.
static auto get_all_scenes() -> const std::vector< scene * > &
static auto get_scene(entt::handle entity) -> scene *
Gets the scene from an entity handle.
static auto find_dotnet_paths(const rtti::context &ctx) -> dotnet::compiler_paths
static auto get_lib_compiled_key(const std::string &protocol) -> std::string
std::vector< std::string > entity_ids
std::string active_entity_id
asset_handle< scene_prefab > startup_scene
struct unravel::settings::standalone_settings standalone
Represents a UI style sheet asset (CSS/RCSS document).
Represents a UI visual tree asset (HTML/RML document).
std::vector< GitHubAsset > assets