Unravel Engine C++ Reference
Loading...
Searching...
No Matches
project_manager.cpp
Go to the documentation of this file.
1#include "project_manager.h"
9
14#include <engine/ecs/ecs.h>
15#include <engine/events.h>
21
22// must be below all
24
25#include <filesystem/watcher.h>
26#include <graphics/graphics.h>
27#include <logging/logging.h>
30
31namespace unravel
32{
33
34namespace
35{
36fs::path app_deploy_cfg = "app:/deploy/deploy.cfg";
37fs::path app_deploy_file = "deploy/deploy.cfg";
38fs::path app_settings_cfg = "app:/settings/settings.cfg";
39fs::path editor_cfg = fs::persistent_path() / "unravel" / "editor.cfg";
40
41} // namespace
42
44{
46 {
50 project_settings_ = {};
51 deploy_settings_ = {};
52 }
53
54 ctx.remove<settings>();
55
56 auto& scr = ctx.get_cached<script_system>();
57 scr.unload_app_domain();
58
59 auto& em = ctx.get_cached<editing_manager>();
60 em.clear();
61
62 auto& tm = ctx.get_cached<thumbnail_manager>();
64
65 auto& ec = ctx.get_cached<ecs>();
66 ec.unload_scene();
67
68 set_name({});
69
70 auto& aw = ctx.get_cached<asset_watcher>();
71 aw.unwatch_assets(ctx, "app:/");
72}
73
74auto project_manager::open_project(rtti::context& ctx, const fs::path& project_path) -> bool
75{
76 close_project(ctx);
77
78 fs::error_code err;
79 if(!fs::exists(project_path, err))
80 {
81 APPLOG_ERROR("Project directory doesn't exist {0}", project_path.string());
82 return false;
83 }
84
85 APPLOG_TRACE("Opening project directory {0}", project_path.string());
86
87 fs::add_path_protocol("app", project_path);
88
89 {
90 fs::error_code err;
91 fs::create_directories(fs::resolve_protocol(ex::get_data_directory("app")), err);
92 fs::create_directories(fs::resolve_protocol(ex::get_compiled_directory("app")), err);
93 fs::create_directories(fs::resolve_protocol(ex::get_meta_directory("app")), err);
94 fs::create_directories(fs::resolve_protocol("app:/settings"), err);
95 fs::create_directories(fs::resolve_protocol("app:/deploy"), err);
96
97 }
98
99 set_name(project_path.filename().string());
100
101 save_editor_settings();
102
103
105
106
107 auto& aw = ctx.get_cached<asset_watcher>();
108 aw.watch_assets(ctx, "app:/");
109
110 auto& scr = ctx.get_cached<script_system>();
111 scr.load_app_domain(ctx, true);
112
113 load_project_settings();
114 save_project_settings(ctx);
115
116 load_deploy_settings();
117 save_deploy_settings();
118
119
120 auto scn = project_settings_.standalone.startup_scene;
121
122 if(scn)
123 {
125 {
127 }
128 }
129 else
130 {
132 }
133
134 return true;
135}
136
138{
139 load_from_file(fs::resolve_protocol(app_settings_cfg).string(), project_settings_);
140}
141
143{
144 asset_writer::atomic_save_to_file(fs::resolve_protocol(app_settings_cfg).string(), project_settings_);
145
146 ctx.add<settings>(project_settings_);
147}
148
150{
151 load_from_file(fs::resolve_protocol(app_deploy_cfg).string(), deploy_settings_);
152
153 fs::error_code ec;
154 if(!fs::exists(deploy_settings_.deploy_location, ec))
155 {
156 deploy_settings_.deploy_location.clear();
157 }
158}
159
161{
162 asset_writer::atomic_save_to_file(fs::resolve_protocol(app_deploy_cfg).string(), deploy_settings_);
163}
164
165void project_manager::create_project(rtti::context& ctx, const fs::path& project_path)
166{
167 fs::error_code err;
168 if(fs::exists(project_path, err) && !fs::is_empty(project_path, err))
169 {
170 APPLOG_ERROR("Project directory already exists and is not empty {0}", project_path.string());
171 return;
172 }
173
174 fs::create_directories(project_path, err);
175
176 if(err)
177 {
178 APPLOG_ERROR("Failed to create project directory {0}", project_path.string());
179 return;
180 }
181
182 fs::add_path_protocol("app", project_path);
183
184 open_project(ctx, project_path);
185}
186
187void project_manager::fixup_editor_settings_on_save()
188{
189 // fixup recent_projects
190 if(has_open_project())
191 {
192 auto& rp = editor_settings_.projects.recent_projects;
193 auto project_path = fs::resolve_protocol("app:/");
194 if(std::find_if(std::begin(rp),
195 std::end(rp),
196 [&](const auto& prj)
197 {
198 return project_path.generic_string() == prj;
199 }) == std::end(rp))
200 {
201 rp.emplace_back(std::move(project_path));
202 }
203
204 std::sort(std::begin(rp),
205 std::end(rp),
206 [](const auto& lhs_path, const auto& rhs_path)
207 {
208 fs::error_code ec;
209 auto lhs_time = fs::last_write_time(lhs_path / app_deploy_file, ec);
210 auto rhs_time = fs::last_write_time(rhs_path / app_deploy_file, ec);
211
212 return lhs_time > rhs_time;
213 });
214 }
215}
216void project_manager::fixup_editor_settings_on_load()
217{
218 fs::error_code err;
219
220 // fixup recent_projects
221 {
222 auto& items = editor_settings_.projects.recent_projects;
223 auto iter = std::begin(items);
224 while(iter != items.end())
225 {
226 auto& item = *iter;
227
228 if(!fs::exists(item, err))
229 {
230 iter = items.erase(iter);
231 }
232 else
233 {
234 ++iter;
235 }
236 }
237 }
238}
239
241{
242 fs::error_code err;
243 const fs::path config = editor_cfg;
244 if(!fs::exists(config, err))
245 {
247 }
248 else
249 {
250 APPLOG_INFO("Loading editor settings {}", config.string());
251 if(load_from_file(config.string(), editor_settings_))
252 {
253 fixup_editor_settings_on_load();
254 }
255 }
256}
257
259{
260 fixup_editor_settings_on_save();
261
262 fs::error_code err;
263 fs::create_directories(editor_cfg.parent_path(), err);
264
265 const fs::path config = editor_cfg;
266 asset_writer::atomic_save_to_file(config.string(), editor_settings_);
267}
268
269auto project_manager::get_name() const -> const std::string&
270{
271 return project_name_;
272}
273
274void project_manager::set_name(const std::string& name)
275{
276 project_name_ = name;
277}
278
280{
281 return project_settings_;
282}
283
285{
286 return deploy_settings_;
287}
288
290{
291 return editor_settings_;
292}
293
295{
296 return !get_name().empty();
297}
298
300{
302
303 auto& scripting = ctx.get_cached<script_system>();
304 scripting.set_debug_config(editor_settings_.debugger.ip,
305 editor_settings_.debugger.port,
306 editor_settings_.debugger.loglevel);
307
308 auto& ev = ctx.get_cached<events>();
309 ev.on_script_recompile.connect(sentinel_,
310 -1000,
311 [this](rtti::context& ctx, const std::string& protocol, uint64_t version)
312 {
313 if(protocol == "app" && has_open_project())
314 {
316 }
317 });
318
319 parser.set_optional<std::string>("p", "project", "", "Project folder to open.");
320
321}
322
323auto project_manager::init(rtti::context& ctx, const cmd_line::parser& parser) -> bool
324{
325 APPLOG_TRACE("{}::{}", hpp::type_name_str(*this), __func__);
326
327 std::string project;
328 if(parser.try_get("project", project) && !project.empty())
329 {
330 if(project == "recent")
331 {
332 const auto& items = editor_settings_.projects.recent_projects;
333 if(!items.empty())
334 {
335 fs::path project_path = items.front();
336 return open_project(ctx, project_path);
337 }
338 }
339 else
340 {
341 fs::path project_path = project;
342 return open_project(ctx, project_path);
343 }
344 }
345
346 return true;
347}
348
350{
351 APPLOG_TRACE("{}::{}", hpp::type_name_str(*this), __func__);
352
353 close_project(ctx);
354
355 return true;
356}
357
362} // namespace unravel
void set_optional(const std::string &name, const std::string &alternative, T defaultValue, const std::string &description="", bool dominant=false)
Definition parser.h:303
void watch_assets(rtti::context &ctx, const std::string &protocol, bool wait=false)
void unwatch_assets(rtti::context &ctx, const std::string &protocol)
auto init(rtti::context &ctx, const cmd_line::parser &parser) -> bool
auto get_deploy_settings() -> deploy_settings &
project_manager(rtti::context &ctx, cmd_line::parser &parser)
void set_name(const std::string &name)
auto has_open_project() const -> bool
auto get_editor_settings() -> editor_settings &
auto open_project(rtti::context &ctx, const fs::path &project_path) -> bool
auto deinit(rtti::context &ctx) -> bool
void create_project(rtti::context &ctx, const fs::path &project_path)
auto get_settings() -> settings &
void save_project_settings(rtti::context &ctx)
auto get_name() const -> const std::string &
void close_project(rtti::context &ctx)
std::string name
Definition hub.cpp:27
#define APPLOG_ERROR(...)
Definition logging.h:20
#define APPLOG_INFO(...)
Definition logging.h:18
#define APPLOG_TRACE(...)
Definition logging.h:17
auto get_data_directory(const std::string &prefix={}) -> std::string
auto get_compiled_directory(const std::string &prefix={}) -> std::string
auto get_meta_directory(const std::string &prefix={}) -> std::string
bool add_path_protocol(const std::string &protocol, const path &dir)
Allows us to map a protocol to a specific directory. A path protocol gives the caller the ability to ...
path resolve_protocol(const path &_path)
Given the specified path/filename, resolve the final full filename. This will be based on either the ...
auto atomic_save_to_file(const fs::path &key, const asset_handle< T > &obj) -> bool
void load_from_file(const std::string &absolute_path, animation_clip &obj)
auto get_cached() -> T &
Definition context.hpp:49
auto add(Args &&... args) -> T &
Definition context.hpp:16
void remove()
Definition context.hpp:78
fs::path deploy_location
Definition deploy.h:11
Manages the entity-component-system (ECS) operations for the ACE framework.
Definition ecs.h:12
void unload_scene()
Unloads the current scene.
Definition ecs.cpp:25
static auto open_scene_from_asset(rtti::context &ctx, const asset_handle< scene_prefab > &asset) -> bool
static auto new_scene(rtti::context &ctx) -> bool
static void generate_script_workspace()
std::vector< fs::path > recent_projects
Definition settings.h:26
struct unravel::editor_settings::projects_settings projects
struct unravel::editor_settings::debugger_settings debugger
hpp::event< void(rtti::context &, const std::string &protocol, uint64_t version)> on_script_recompile
Definition events.h:36
void set_debug_config(const std::string &address, uint32_t port, uint32_t loglevel)
auto load_app_domain(rtti::context &ctx, bool recompile) -> bool