Bläddra i källkod

Notify clients about source directory changes

Daniele Bartolini 9 år sedan
förälder
incheckning
e4326e7a4b

+ 3 - 5
src/device/device.cpp

@@ -285,6 +285,8 @@ void Device::run()
 	_console_server = CE_NEW(_allocator, ConsoleServer)(default_allocator());
 	load_console_api(*_console_server);
 
+	_console_server->listen(_device_options._server ? CROWN_DEFAULT_COMPILER_PORT : _device_options._console_port, _device_options._wait_console);
+
 	namespace cor = config_resource_internal;
 	namespace ftr = font_resource_internal;
 	namespace lur = lua_resource_internal;
@@ -306,7 +308,7 @@ void Device::run()
 #if CROWN_PLATFORM_LINUX || CROWN_PLATFORM_WINDOWS
 	if (_device_options._do_compile || _device_options._server)
 	{
-		_data_compiler = CE_NEW(_allocator, DataCompiler)();
+		_data_compiler = CE_NEW(_allocator, DataCompiler)(*_console_server);
 		_data_compiler->register_compiler(RESOURCE_TYPE_CONFIG,           RESOURCE_VERSION_CONFIG,           cor::compile);
 		_data_compiler->register_compiler(RESOURCE_TYPE_FONT,             RESOURCE_VERSION_FONT,             ftr::compile);
 		_data_compiler->register_compiler(RESOURCE_TYPE_LEVEL,            RESOURCE_VERSION_LEVEL,            lvr::compile);
@@ -336,8 +338,6 @@ void Device::run()
 
 		if (_device_options._server)
 		{
-			_console_server->listen(CROWN_DEFAULT_COMPILER_PORT, false);
-
 			while (true)
 			{
 				_console_server->update();
@@ -356,8 +356,6 @@ void Device::run()
 
 	if (do_continue)
 	{
-		_console_server->listen(_device_options._console_port, _device_options._wait_console);
-
 #if CROWN_PLATFORM_ANDROID
 		_bundle_filesystem = CE_NEW(_allocator, FilesystemApk)(default_allocator(), const_cast<AAssetManager*>((AAssetManager*)_device_options._asset_manager));
 #else

+ 129 - 2
src/resource/data_compiler.cpp

@@ -17,6 +17,7 @@
 #include "path.h"
 #include "sjson.h"
 #include "sort_map.h"
+#include "string_stream.h"
 #include "temp_allocator.h"
 #include "vector.h"
 #include <setjmp.h>
@@ -52,15 +53,22 @@ public:
 	}
 };
 
-DataCompiler::DataCompiler()
-	: _source_fs(default_allocator())
+DataCompiler::DataCompiler(ConsoleServer& cs)
+	: _console_server(&cs)
+	, _source_fs(default_allocator())
 	, _source_dirs(default_allocator())
 	, _compilers(default_allocator())
 	, _files(default_allocator())
 	, _globs(default_allocator())
+	, _file_monitor(default_allocator())
 {
 }
 
+DataCompiler::~DataCompiler()
+{
+	_file_monitor.stop();
+}
+
 void DataCompiler::add_file(const char* path)
 {
 	for (u32 gg = 0; gg < vector::size(_globs); ++gg)
@@ -73,6 +81,67 @@ void DataCompiler::add_file(const char* path)
 	DynamicString str(ta);
 	str.set(path, strlen32(path));
 	vector::push_back(_files, str);
+
+	StringStream ss(ta);
+	ss << "{\"type\":\"add_file\",\"path\":\"" << str.c_str() << "\"}";
+	_console_server->send(string_stream::c_str(ss));
+}
+
+void DataCompiler::add_tree(const char* path)
+{
+	TempAllocator512 ta;
+	DynamicString source_dir(ta);
+	source_dir = map::get(_source_dirs, source_dir, source_dir);
+
+	_source_fs.set_prefix(source_dir.c_str());
+	DataCompiler::scan_source_dir(source_dir.c_str(), path);
+
+	StringStream ss(ta);
+	ss << "{\"type\":\"add_tree\",\"path\":\"" << path << "\"}";
+	_console_server->send(string_stream::c_str(ss));
+}
+
+void DataCompiler::remove_file(const char* path)
+{
+	for (u32 i = 0; i < vector::size(_files); ++i)
+	{
+		if (_files[i] == path)
+		{
+			_files[i] = _files[vector::size(_files) - 1];
+			vector::pop_back(_files);
+
+			TempAllocator512 ta;
+			StringStream ss(ta);
+			ss << "{\"type\":\"remove_file\",\"path\":\"" << path << "\"}";
+			_console_server->send(string_stream::c_str(ss));
+			return;
+		}
+	}
+}
+
+void DataCompiler::remove_tree(const char* path)
+{
+	TempAllocator512 ta;
+	StringStream ss(ta);
+	ss << "{\"type\":\"remove_tree\",\"path\":\"" << path << "\"}";
+	_console_server->send(string_stream::c_str(ss));
+
+	for (u32 i = 0; i < vector::size(_files);)
+	{
+		if (_files[i].has_prefix(path))
+		{
+			TempAllocator512 ta;
+			StringStream ss(ta);
+			ss << "{\"type\":\"remove_file\",\"path\":\"" << _files[i].c_str() << "\"}";
+			_console_server->send(string_stream::c_str(ss));
+
+			_files[i] = _files[vector::size(_files) - 1];
+			vector::pop_back(_files);
+			continue;
+		}
+
+		++i;
+	}
 }
 
 bool DataCompiler::can_compile(StringId64 type)
@@ -283,6 +352,8 @@ void DataCompiler::scan()
 
 		scan_source_dir(cur->pair.first.c_str(), "");
 	}
+
+	_file_monitor.start(map::begin(_source_dirs)->pair.second.c_str(), true, filemonitor_callback, this);
 }
 
 bool DataCompiler::compile(const char* bundle_dir, const char* platform)
@@ -298,6 +369,8 @@ bool DataCompiler::compile(const char* bundle_dir, const char* platform)
 	if (!bundle_fs.exists(CROWN_TEMP_DIRECTORY))
 		bundle_fs.create_directory(CROWN_TEMP_DIRECTORY);
 
+	std::sort(vector::begin(_files), vector::end(_files));
+
 	// Compile all changed resources
 	for (u32 i = 0; i < vector::size(_files); ++i)
 	{
@@ -339,4 +412,58 @@ u32 DataCompiler::version(StringId64 type)
 	return sort_map::get(_compilers, type, ResourceTypeData()).version;
 }
 
+void DataCompiler::filemonitor_callback(FileMonitorEvent::Enum fme, bool is_dir, const char* path, const char* path_renamed)
+{
+	TempAllocator512 ta;
+	DynamicString resource_name(ta);
+	DynamicString resource_name_renamed(ta);
+	DynamicString source_dir(ta);
+
+	source_dir            = map::get(_source_dirs, source_dir, source_dir);
+	resource_name         = &path[source_dir.length()+1]; // FIXME: add path::relative()
+	resource_name_renamed = path_renamed ? &path_renamed[source_dir.length()+1] : "";
+
+	switch (fme)
+	{
+	case FileMonitorEvent::CREATED:
+		if (!is_dir)
+			add_file(resource_name.c_str());
+		else
+			add_tree(resource_name.c_str());
+		break;
+
+	case FileMonitorEvent::DELETED:
+		if (!is_dir)
+			remove_file(resource_name.c_str());
+		else
+			remove_tree(resource_name.c_str());
+		break;
+
+	case FileMonitorEvent::RENAMED:
+		if (!is_dir)
+		{
+			remove_file(resource_name.c_str());
+			add_file(resource_name_renamed.c_str());
+		}
+		else
+		{
+			remove_tree(resource_name.c_str());
+			add_tree(resource_name_renamed.c_str());
+		}
+		break;
+
+	case FileMonitorEvent::CHANGED:
+		break;
+
+	default:
+		CE_ASSERT(false, "Unknown FileMonitorEvent: %d", fme);
+		break;
+	}
+}
+
+void DataCompiler::filemonitor_callback(void* thiz, FileMonitorEvent::Enum fme, bool is_dir, const char* path_original, const char* path_modified)
+{
+	((DataCompiler*)thiz)->filemonitor_callback(fme, is_dir, path_original, path_modified);
+}
+
 } // namespace crown

+ 15 - 2
src/resource/data_compiler.h

@@ -6,7 +6,9 @@
 #pragma once
 
 #include "compiler_types.h"
+#include "console_server.h"
 #include "container_types.h"
+#include "file_monitor.h"
 #include "filesystem_disk.h"
 
 namespace crown
@@ -21,21 +23,32 @@ class DataCompiler
 		CompileFunction compiler;
 	};
 
+	ConsoleServer* _console_server;
 	FilesystemDisk _source_fs;
 	Map<DynamicString, DynamicString> _source_dirs;
 	SortMap<StringId64, ResourceTypeData> _compilers;
 	Vector<DynamicString> _files;
 	Vector<DynamicString> _globs;
+	FileMonitor _file_monitor;
 
 	void add_file(const char* path);
+	void add_tree(const char* path);
+	void remove_file(const char* path);
+	void remove_tree(const char* path);
+
+	void scan_source_dir(const char* prefix, const char* path);
+
 	bool can_compile(StringId64 type);
 	void compile(StringId64 type, const char* path, CompileOptions& opts);
-	void scan_source_dir(const char* prefix, const char* path);
 	bool compile(FilesystemDisk& bundle_fs, const char* type, const char* name, const char* platform);
 
+	void filemonitor_callback(FileMonitorEvent::Enum fme, bool is_dir, const char* path, const char* path_renamed);
+	static void filemonitor_callback(void* thiz, FileMonitorEvent::Enum fme, bool is_dir, const char* path_original, const char* path_modified);
+
 public:
 
-	DataCompiler();
+	DataCompiler(ConsoleServer& cs);
+	~DataCompiler();
 
 	void map_source_dir(const char* name, const char* source_dir);
 	void source_dir(const char* resource_name, DynamicString& source_dir);

+ 14 - 4
tools/level_editor/level_editor.vala

@@ -409,6 +409,18 @@ namespace Crown
 				{
 					_console_view.log((string)msg["message"], (string)msg["severity"]);
 				}
+				else if (msg_type == "add_file")
+				{
+					string path = (string)msg["path"];
+
+					_project.add_file(path);
+				}
+				else if (msg_type == "remove_file")
+				{
+					string path = (string)msg["path"];
+
+					_project.remove_file(path);
+				}
 				else if (msg_type == "compile")
 				{
 					Guid id = Guid.parse((string)msg["id"]);
@@ -548,6 +560,7 @@ namespace Crown
 				"--source-dir", _project.source_dir(),
 				"--map-source-dir", "core", _project.toolchain_dir(),
 				"--server",
+				"--wait-console",
 				null
 			};
 
@@ -960,10 +973,7 @@ namespace Crown
 		private void on_import_end()
 		{
 			_resource_compiler.compile.begin(_project.data_dir(), _project.platform(), (obj, res) => {
-				if (_resource_compiler.compile.end(res))
-				{
-					_project.scan_source_dir();
-				}
+				_resource_compiler.compile.end(res);
 			});
 		}
 

+ 21 - 39
tools/level_editor/project.vala

@@ -17,6 +17,7 @@ namespace Crown
 		private string _platform;
 
 		private Database _files;
+		private HashMap<string, Guid?> _map;
 
 		public signal void changed();
 
@@ -28,6 +29,7 @@ namespace Crown
 			_platform = "linux";
 
 			_files = new Database();
+			_map = new HashMap<string, Guid?>();
 		}
 
 		public void load(string source_dir, string toolchain_dir, string data_dir)
@@ -35,8 +37,6 @@ namespace Crown
 			_source_dir    = File.new_for_path(source_dir);
 			_toolchain_dir = File.new_for_path(toolchain_dir);
 			_data_dir      = File.new_for_path(data_dir);
-
-			scan_source_dir();
 		}
 
 		public string source_dir()
@@ -64,48 +64,32 @@ namespace Crown
 			return _files;
 		}
 
-		public void scan_source_dir()
+		public void add_file(string path)
 		{
-			_files.reset();
-			list_directory_entries(_source_dir);
+			string name = path.substring(0, path.last_index_of("."));
+			string type = path.substring(path.last_index_of(".") + 1);
+
+			Guid id = Guid.new_guid();
+			_files.create(id);
+			_files.set_property(id, "path", path);
+			_files.set_property(id, "type", type);
+			_files.set_property(id, "name", name);
+			_files.add_to_set(GUID_ZERO, "data", id);
+
+			_map[path] = id;
+
 			changed();
 		}
 
-		private void list_directory_entries(File dir, Cancellable? cancellable = null) throws Error
+		public void remove_file(string path)
 		{
-			FileEnumerator enumerator = dir.enumerate_children(GLib.FileAttribute.STANDARD_NAME
-				, FileQueryInfoFlags.NOFOLLOW_SYMLINKS
-				, cancellable
-				);
+			Guid id = _map[path];
+			_files.remove_from_set(GUID_ZERO, "data", id);
+			_files.destroy(id);
 
-			FileInfo info = null;
-			while (!cancellable.is_cancelled() && ((info = enumerator.next_file (cancellable)) != null))
-			{
-				if (info.get_file_type () == FileType.DIRECTORY)
-				{
-					File subdir = dir.resolve_relative_path (info.get_name());
-					list_directory_entries(subdir, cancellable);
-				}
-				else
-				{
-					string path     = dir.get_path() + "/" + info.get_name();
-					string path_rel = _source_dir.get_relative_path(File.new_for_path(path));
-					string name     = path_rel.substring(0, path_rel.last_index_of("."));
-					string type     = path_rel.substring(path_rel.last_index_of(".") + 1);
-
-					Guid id = Guid.new_guid();
-					_files.create(id);
-					_files.set_property(id, "path", path);
-					_files.set_property(id, "type", type);
-					_files.set_property(id, "name", name);
-					_files.add_to_set(GUID_ZERO, "data", id);
-				}
-			}
+			_map.unset(path);
 
-			if (cancellable.is_cancelled ())
-			{
-				throw new IOError.CANCELLED("Operation was cancelled");
-			}
+			changed();
 		}
 
 		public void import_sprites(SList<string> filenames, string destination_dir)
@@ -330,7 +314,6 @@ namespace Crown
 
 				string dst_dir_rel    = _source_dir.get_relative_path(File.new_for_path(destination_dir));
 				string basename       = file_src.get_basename();
-				string basename_noext = basename.substring(0, basename.last_index_of_char('.'));
 				string dst_noext      = file_dst.get_path().substring(0, file_dst.get_path().last_index_of_char('.'));
 
 				if (!filename_i.has_suffix(".wav"))
@@ -354,7 +337,6 @@ namespace Crown
 
 				string dst_dir_rel    = _source_dir.get_relative_path(File.new_for_path(destination_dir));
 				string basename       = file_src.get_basename();
-				string basename_noext = basename.substring(0, basename.last_index_of_char('.'));
 				string dst_noext      = file_dst.get_path().substring(0, file_dst.get_path().last_index_of_char('.'));
 
 				if (!filename_i.has_suffix(".png"))