瀏覽代碼

Use separate entry point for data compilation

Daniele Bartolini 9 年之前
父節點
當前提交
012eb20a45

+ 8 - 45
src/device/console_api.cpp

@@ -15,7 +15,7 @@
 
 
 namespace crown
 namespace crown
 {
 {
-static void console_command_script(ConsoleServer& /*cs*/, TCPSocket /*client*/, const char* json)
+static void console_command_script(ConsoleServer& /*cs*/, TCPSocket /*client*/, const char* json, void* /*user_data*/)
 {
 {
 	TempAllocator4096 ta;
 	TempAllocator4096 ta;
 	JsonObject obj(ta);
 	JsonObject obj(ta);
@@ -27,7 +27,7 @@ static void console_command_script(ConsoleServer& /*cs*/, TCPSocket /*client*/,
 	device()->_lua_environment->execute_string(script.c_str());
 	device()->_lua_environment->execute_string(script.c_str());
 }
 }
 
 
-static void console_command_reload(ConsoleServer& /*cs*/, TCPSocket /*client*/, const char* json)
+static void console_command_reload(ConsoleServer& /*cs*/, TCPSocket /*client*/, const char* json, void* /*user_data*/)
 {
 {
 	TempAllocator4096 ta;
 	TempAllocator4096 ta;
 	JsonObject obj(ta);
 	JsonObject obj(ta);
@@ -43,59 +43,22 @@ static void console_command_reload(ConsoleServer& /*cs*/, TCPSocket /*client*/,
 	logi("Reloaded resource '%s.%s'", name.c_str(), type.c_str());
 	logi("Reloaded resource '%s.%s'", name.c_str(), type.c_str());
 }
 }
 
 
-static void console_command_pause(ConsoleServer& /*cs*/, TCPSocket /*client*/, const char* /*json*/)
+static void console_command_pause(ConsoleServer& /*cs*/, TCPSocket /*client*/, const char* /*json*/, void* /*user_data*/)
 {
 {
 	device()->pause();
 	device()->pause();
 }
 }
 
 
-static void console_command_unpause(ConsoleServer& /*cs*/, TCPSocket /*client*/, const char* /*json*/)
+static void console_command_unpause(ConsoleServer& /*cs*/, TCPSocket /*client*/, const char* /*json*/, void* /*user_data*/)
 {
 {
 	device()->unpause();
 	device()->unpause();
 }
 }
 
 
-static void console_command_compile(ConsoleServer& cs, TCPSocket client, const char* json)
-{
-	TempAllocator4096 ta;
-	JsonObject obj(ta);
-	DynamicString id(ta);
-	DynamicString data_dir(ta);
-	DynamicString platform(ta);
-
-	sjson::parse(json, obj);
-	sjson::parse_string(obj["id"], id);
-	sjson::parse_string(obj["data_dir"], data_dir);
-	sjson::parse_string(obj["platform"], platform);
-
-	{
-		TempAllocator512 ta;
-		StringStream ss(ta);
-		ss << "{\"type\":\"compile\",\"id\":\"" << id.c_str() << "\",\"start\":true}";
-		cs.send(client, string_stream::c_str(ss));
-	}
-
-	logi("Compiling '%s'", id.c_str());
-	bool succ = device()->_data_compiler->compile(data_dir.c_str(), platform.c_str());
-
-	if (succ)
-		logi("Compiled '%s'", id.c_str());
-	else
-		loge("Error while compiling '%s'", id.c_str());
-
-	{
-		TempAllocator512 ta;
-		StringStream ss(ta);
-		ss << "{\"type\":\"compile\",\"id\":\"" << id.c_str() << "\",\"success\":" << (succ ? "true" : "false") << "}";
-		cs.send(client, string_stream::c_str(ss));
-	}
-}
-
 void load_console_api(ConsoleServer& cs)
 void load_console_api(ConsoleServer& cs)
 {
 {
-	cs.register_command("script",  console_command_script);
-	cs.register_command("reload",  console_command_reload);
-	cs.register_command("pause",   console_command_pause);
-	cs.register_command("unpause", console_command_unpause);
-	cs.register_command("compile", console_command_compile);
+	cs.register_command("script",  console_command_script, NULL);
+	cs.register_command("reload",  console_command_reload, NULL);
+	cs.register_command("pause",   console_command_pause, NULL);
+	cs.register_command("unpause", console_command_unpause, NULL);
 }
 }
 
 
 } // namespace crown
 } // namespace crown

+ 37 - 9
src/device/console_server.cpp

@@ -4,9 +4,9 @@
  */
  */
 
 
 #include "console_server.h"
 #include "console_server.h"
+#include "hash_map.h"
 #include "json_object.h"
 #include "json_object.h"
 #include "sjson.h"
 #include "sjson.h"
-#include "sort_map.h"
 #include "string_id.h"
 #include "string_id.h"
 #include "string_stream.h"
 #include "string_stream.h"
 #include "temp_allocator.h"
 #include "temp_allocator.h"
@@ -142,24 +142,52 @@ void ConsoleServer::process(TCPSocket client, const char* json)
 	JsonObject obj(ta);
 	JsonObject obj(ta);
 	sjson::parse(json, obj);
 	sjson::parse(json, obj);
 
 
-	CommandFunction cmd = sort_map::get(_commands
+	Command cmd;
+	cmd.function = NULL;
+	cmd.user_data = NULL;
+
+	cmd = hash_map::get(_commands
 		, sjson::parse_string_id(obj["type"])
 		, sjson::parse_string_id(obj["type"])
-		, (CommandFunction)NULL
+		, cmd
 		);
 		);
 
 
-	if (cmd)
-		cmd(*this, client, json);
+	if (cmd.function)
+		cmd.function(*this, client, json, cmd.user_data);
 	else
 	else
 		error(client, "Unknown command");
 		error(client, "Unknown command");
 }
 }
 
 
-void ConsoleServer::register_command(const char* type, CommandFunction cmd)
+void ConsoleServer::register_command(const char* type, CommandFunction function, void* user_data)
 {
 {
 	CE_ENSURE(NULL != type);
 	CE_ENSURE(NULL != type);
-	CE_ENSURE(NULL != cmd);
+	CE_ENSURE(NULL != function);
+
+	Command cmd;
+	cmd.function = function;
+	cmd.user_data = user_data;
+
+	hash_map::set(_commands, StringId32(type), cmd);
+}
+
+namespace console_server_globals
+{
+	ConsoleServer* _console_server = NULL;
+
+	void init()
+	{
+		_console_server = CE_NEW(default_allocator(), ConsoleServer)(default_allocator());
+	}
 
 
-	sort_map::set(_commands, StringId32(type), cmd);
-	sort_map::sort(_commands);
+	void shutdown()
+	{
+		_console_server->shutdown();
+		CE_DELETE(default_allocator(), _console_server);
+	}
+}
+
+ConsoleServer* console_server()
+{
+	return console_server_globals::_console_server;
 }
 }
 
 
 } // namespace crown
 } // namespace crown

+ 19 - 3
src/device/console_server.h

@@ -8,6 +8,7 @@
 #include "container_types.h"
 #include "container_types.h"
 #include "socket.h"
 #include "socket.h"
 #include "string_types.h"
 #include "string_types.h"
+#include "hash_map.h"
 
 
 namespace crown
 namespace crown
 {
 {
@@ -16,11 +17,17 @@ namespace crown
 /// @ingroup Device
 /// @ingroup Device
 class ConsoleServer
 class ConsoleServer
 {
 {
-	typedef void (*CommandFunction)(ConsoleServer& cs, TCPSocket client, const char* json);
+	typedef void (*CommandFunction)(ConsoleServer& cs, TCPSocket client, const char* json, void* user_data);
+
+	struct Command
+	{
+		CommandFunction function;
+		void* user_data;
+	};
 
 
 	TCPSocket _server;
 	TCPSocket _server;
 	Vector<TCPSocket> _clients;
 	Vector<TCPSocket> _clients;
-	SortMap<StringId32, CommandFunction> _commands;
+	HashMap<StringId32, Command> _commands;
 
 
 	void add_client(TCPSocket socket);
 	void add_client(TCPSocket socket);
 	void process(TCPSocket client, const char* json);
 	void process(TCPSocket client, const char* json);
@@ -52,7 +59,16 @@ public:
 	void success(TCPSocket client, const char* msg);
 	void success(TCPSocket client, const char* msg);
 
 
 	/// Registers the command @a type.
 	/// Registers the command @a type.
-	void register_command(const char* type, CommandFunction cmd);
+	void register_command(const char* type, CommandFunction cmd, void* user_data);
 };
 };
 
 
+namespace console_server_globals
+{
+	void init();
+
+	void shutdown();
+} // namespace console_server_globals
+
+ConsoleServer* console_server();
+
 } // namespace crown
 } // namespace crown

+ 159 - 244
src/device/device.cpp

@@ -9,7 +9,7 @@
 #include "config_resource.h"
 #include "config_resource.h"
 #include "console_api.h"
 #include "console_api.h"
 #include "console_server.h"
 #include "console_server.h"
-#include "data_compiler.h"
+#include "console_server.h"
 #include "device.h"
 #include "device.h"
 #include "device_event_queue.h"
 #include "device_event_queue.h"
 #include "file.h"
 #include "file.h"
@@ -144,8 +144,6 @@ Device::Device(const DeviceOptions& opts)
 	: _allocator(default_allocator(), MAX_SUBSYSTEMS_HEAP)
 	: _allocator(default_allocator(), MAX_SUBSYSTEMS_HEAP)
 	, _device_options(opts)
 	, _device_options(opts)
 	, _boot_config(default_allocator())
 	, _boot_config(default_allocator())
-	, _console_server(NULL)
-	, _data_compiler(NULL)
 	, _bundle_filesystem(NULL)
 	, _bundle_filesystem(NULL)
 	, _last_log(NULL)
 	, _last_log(NULL)
 	, _resource_loader(NULL)
 	, _resource_loader(NULL)
@@ -282,10 +280,10 @@ bool Device::process_events(s16& mouse_x, s16& mouse_y, s16& mouse_last_x, s16&
 
 
 void Device::run()
 void Device::run()
 {
 {
-	_console_server = CE_NEW(_allocator, ConsoleServer)(default_allocator());
-	load_console_api(*_console_server);
+	console_server_globals::init();
+	load_console_api(*console_server());
 
 
-	_console_server->listen(_device_options._server ? CROWN_DEFAULT_COMPILER_PORT : _device_options._console_port, _device_options._wait_console);
+	console_server()->listen(_device_options._console_port, _device_options._wait_console);
 
 
 	namespace cor = config_resource_internal;
 	namespace cor = config_resource_internal;
 	namespace ftr = font_resource_internal;
 	namespace ftr = font_resource_internal;
@@ -303,248 +301,192 @@ void Device::run()
 	namespace txr = texture_resource_internal;
 	namespace txr = texture_resource_internal;
 	namespace utr = unit_resource_internal;
 	namespace utr = unit_resource_internal;
 
 
-	bool do_continue = true;
-
-#if CROWN_PLATFORM_LINUX || CROWN_PLATFORM_WINDOWS
-	if (_device_options._do_compile || _device_options._server)
+#if CROWN_PLATFORM_ANDROID
+	_bundle_filesystem = CE_NEW(_allocator, FilesystemApk)(default_allocator(), const_cast<AAssetManager*>((AAssetManager*)_device_options._asset_manager));
+#else
+	const char* data_dir = _device_options._data_dir.c_str();
+	if (!data_dir)
 	{
 	{
-		_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);
-		_data_compiler->register_compiler(RESOURCE_TYPE_MATERIAL,         RESOURCE_VERSION_MATERIAL,         mtr::compile);
-		_data_compiler->register_compiler(RESOURCE_TYPE_MESH,             RESOURCE_VERSION_MESH,             mhr::compile);
-		_data_compiler->register_compiler(RESOURCE_TYPE_PACKAGE,          RESOURCE_VERSION_PACKAGE,          pkr::compile);
-		_data_compiler->register_compiler(RESOURCE_TYPE_PHYSICS,          RESOURCE_VERSION_PHYSICS,          phr::compile);
-		_data_compiler->register_compiler(RESOURCE_TYPE_PHYSICS_CONFIG,   RESOURCE_VERSION_PHYSICS_CONFIG,   pcr::compile);
-		_data_compiler->register_compiler(RESOURCE_TYPE_SCRIPT,           RESOURCE_VERSION_SCRIPT,           lur::compile);
-		_data_compiler->register_compiler(RESOURCE_TYPE_SHADER,           RESOURCE_VERSION_SHADER,           shr::compile);
-		_data_compiler->register_compiler(RESOURCE_TYPE_SOUND,            RESOURCE_VERSION_SOUND,            sdr::compile);
-		_data_compiler->register_compiler(RESOURCE_TYPE_SPRITE,           RESOURCE_VERSION_SPRITE,           spr::compile);
-		_data_compiler->register_compiler(RESOURCE_TYPE_SPRITE_ANIMATION, RESOURCE_VERSION_SPRITE_ANIMATION, sar::compile);
-		_data_compiler->register_compiler(RESOURCE_TYPE_TEXTURE,          RESOURCE_VERSION_TEXTURE,          txr::compile);
-		_data_compiler->register_compiler(RESOURCE_TYPE_UNIT,             RESOURCE_VERSION_UNIT,             utr::compile);
-
-		_data_compiler->map_source_dir("", _device_options._source_dir.c_str());
-
-		if (_device_options._map_source_dir_name)
-		{
-			_data_compiler->map_source_dir(_device_options._map_source_dir_name
-				, _device_options._map_source_dir_prefix.c_str()
-				);
-		}
+		char buf[1024];
+		data_dir = os::getcwd(buf, sizeof(buf));
+	}
+	_bundle_filesystem = CE_NEW(_allocator, FilesystemDisk)(default_allocator());
+	((FilesystemDisk*)_bundle_filesystem)->set_prefix(data_dir);
+	if (!_bundle_filesystem->exists(data_dir))
+		_bundle_filesystem->create_directory(data_dir);
 
 
-		_data_compiler->scan();
+	_last_log = _bundle_filesystem->open(CROWN_LAST_LOG, FileOpenMode::WRITE);
+#endif // CROWN_PLATFORM_ANDROID
 
 
-		if (_device_options._server)
-		{
-			while (true)
-			{
-				_console_server->update();
-				os::sleep(60);
-			}
-		}
-		else
+	logi("Initializing Crown Engine %s...", version());
+
+	profiler_globals::init();
+
+	_resource_loader  = CE_NEW(_allocator, ResourceLoader)(*_bundle_filesystem);
+	_resource_manager = CE_NEW(_allocator, ResourceManager)(*_resource_loader);
+	_resource_manager->register_type(RESOURCE_TYPE_SCRIPT,           lur::load, lur::unload, NULL,        NULL        );
+	_resource_manager->register_type(RESOURCE_TYPE_TEXTURE,          txr::load, txr::unload, txr::online, txr::offline);
+	_resource_manager->register_type(RESOURCE_TYPE_MESH,             mhr::load, mhr::unload, mhr::online, mhr::offline);
+	_resource_manager->register_type(RESOURCE_TYPE_SOUND,            sdr::load, sdr::unload, NULL,        NULL        );
+	_resource_manager->register_type(RESOURCE_TYPE_UNIT,             utr::load, utr::unload, NULL,        NULL        );
+	_resource_manager->register_type(RESOURCE_TYPE_SPRITE,           spr::load, spr::unload, NULL,        NULL        );
+	_resource_manager->register_type(RESOURCE_TYPE_PACKAGE,          pkr::load, pkr::unload, NULL,        NULL        );
+	_resource_manager->register_type(RESOURCE_TYPE_PHYSICS,          phr::load, phr::unload, NULL,        NULL        );
+	_resource_manager->register_type(RESOURCE_TYPE_MATERIAL,         mtr::load, mtr::unload, mtr::online, mtr::offline);
+	_resource_manager->register_type(RESOURCE_TYPE_PHYSICS_CONFIG,   pcr::load, pcr::unload, NULL,        NULL        );
+	_resource_manager->register_type(RESOURCE_TYPE_FONT,             ftr::load, ftr::unload, NULL,        NULL        );
+	_resource_manager->register_type(RESOURCE_TYPE_LEVEL,            lvr::load, lvr::unload, NULL,        NULL        );
+	_resource_manager->register_type(RESOURCE_TYPE_SHADER,           shr::load, shr::unload, shr::online, shr::offline);
+	_resource_manager->register_type(RESOURCE_TYPE_SPRITE_ANIMATION, sar::load, sar::unload, NULL,        NULL        );
+	_resource_manager->register_type(RESOURCE_TYPE_CONFIG,           cor::load, cor::unload, NULL,        NULL        );
+
+	// Read config
+	{
+		TempAllocator512 ta;
+		DynamicString boot_dir(ta);
+
+		if (_device_options._boot_dir != NULL)
 		{
 		{
-			const char* data_dir = _device_options._data_dir.c_str();
-			const char* platform = _device_options._platform;
-			do_continue = _data_compiler->compile(data_dir, platform);
-			do_continue = do_continue && _device_options._do_continue;
+			boot_dir += _device_options._boot_dir;
+			boot_dir += '/';
 		}
 		}
+		boot_dir += CROWN_BOOT_CONFIG;
+
+		const StringId64 config_name(boot_dir.c_str());
+		_resource_manager->load(RESOURCE_TYPE_CONFIG, config_name);
+		_resource_manager->flush();
+		_boot_config.parse((const char*)_resource_manager->get(RESOURCE_TYPE_CONFIG, config_name));
+		_resource_manager->unload(RESOURCE_TYPE_CONFIG, config_name);
 	}
 	}
-#endif // CROWN_PLATFORM_LINUX || CROWN_PLATFORM_WINDOWS
 
 
-	if (do_continue)
-	{
-#if CROWN_PLATFORM_ANDROID
-		_bundle_filesystem = CE_NEW(_allocator, FilesystemApk)(default_allocator(), const_cast<AAssetManager*>((AAssetManager*)_device_options._asset_manager));
-#else
-		const char* data_dir = _device_options._data_dir.c_str();
-		if (!data_dir)
-		{
-			char buf[1024];
-			data_dir = os::getcwd(buf, sizeof(buf));
-		}
-		_bundle_filesystem = CE_NEW(_allocator, FilesystemDisk)(default_allocator());
-		((FilesystemDisk*)_bundle_filesystem)->set_prefix(data_dir);
-		if (!_bundle_filesystem->exists(data_dir))
-			_bundle_filesystem->create_directory(data_dir);
+	// Init all remaining subsystems
+	_bgfx_allocator = CE_NEW(_allocator, BgfxAllocator)(default_allocator());
+	_bgfx_callback  = CE_NEW(_allocator, BgfxCallback)();
+
+	_display = display::create(_allocator);
+	_window = window::create(_allocator);
+	_window->open(_device_options._window_x
+		, _device_options._window_y
+		, _boot_config.window_w
+		, _boot_config.window_h
+		, _device_options._parent_window
+		);
+	_window->set_title(_boot_config.window_title.c_str());
+	_window->set_fullscreen(_boot_config.fullscreen);
+	_window->bgfx_setup();
 
 
-		_last_log = _bundle_filesystem->open(CROWN_LAST_LOG, FileOpenMode::WRITE);
-#endif // CROWN_PLATFORM_ANDROID
+	bgfx::init(bgfx::RendererType::Count
+		, BGFX_PCI_ID_NONE
+		, 0
+		, _bgfx_callback
+		, _bgfx_allocator
+		);
 
 
-		logi("Initializing Crown Engine %s...", version());
-
-		profiler_globals::init();
-
-		_resource_loader  = CE_NEW(_allocator, ResourceLoader)(*_bundle_filesystem);
-		_resource_manager = CE_NEW(_allocator, ResourceManager)(*_resource_loader);
-		_resource_manager->register_type(RESOURCE_TYPE_SCRIPT,           lur::load, lur::unload, NULL,        NULL        );
-		_resource_manager->register_type(RESOURCE_TYPE_TEXTURE,          txr::load, txr::unload, txr::online, txr::offline);
-		_resource_manager->register_type(RESOURCE_TYPE_MESH,             mhr::load, mhr::unload, mhr::online, mhr::offline);
-		_resource_manager->register_type(RESOURCE_TYPE_SOUND,            sdr::load, sdr::unload, NULL,        NULL        );
-		_resource_manager->register_type(RESOURCE_TYPE_UNIT,             utr::load, utr::unload, NULL,        NULL        );
-		_resource_manager->register_type(RESOURCE_TYPE_SPRITE,           spr::load, spr::unload, NULL,        NULL        );
-		_resource_manager->register_type(RESOURCE_TYPE_PACKAGE,          pkr::load, pkr::unload, NULL,        NULL        );
-		_resource_manager->register_type(RESOURCE_TYPE_PHYSICS,          phr::load, phr::unload, NULL,        NULL        );
-		_resource_manager->register_type(RESOURCE_TYPE_MATERIAL,         mtr::load, mtr::unload, mtr::online, mtr::offline);
-		_resource_manager->register_type(RESOURCE_TYPE_PHYSICS_CONFIG,   pcr::load, pcr::unload, NULL,        NULL        );
-		_resource_manager->register_type(RESOURCE_TYPE_FONT,             ftr::load, ftr::unload, NULL,        NULL        );
-		_resource_manager->register_type(RESOURCE_TYPE_LEVEL,            lvr::load, lvr::unload, NULL,        NULL        );
-		_resource_manager->register_type(RESOURCE_TYPE_SHADER,           shr::load, shr::unload, shr::online, shr::offline);
-		_resource_manager->register_type(RESOURCE_TYPE_SPRITE_ANIMATION, sar::load, sar::unload, NULL,        NULL        );
-		_resource_manager->register_type(RESOURCE_TYPE_CONFIG,           cor::load, cor::unload, NULL,        NULL        );
-
-		// Read config
-		{
-			TempAllocator512 ta;
-			DynamicString boot_dir(ta);
+	_shader_manager   = CE_NEW(_allocator, ShaderManager)(default_allocator());
+	_material_manager = CE_NEW(_allocator, MaterialManager)(default_allocator(), *_resource_manager);
+	_input_manager    = CE_NEW(_allocator, InputManager)(default_allocator());
+	_unit_manager     = CE_NEW(_allocator, UnitManager)(default_allocator());
+	_lua_environment  = CE_NEW(_allocator, LuaEnvironment)();
 
 
-			if (_device_options._boot_dir != NULL)
-			{
-				boot_dir += _device_options._boot_dir;
-				boot_dir += '/';
-			}
-			boot_dir += CROWN_BOOT_CONFIG;
+	audio_globals::init();
+	physics_globals::init(_allocator);
 
 
-			const StringId64 config_name(boot_dir.c_str());
-			_resource_manager->load(RESOURCE_TYPE_CONFIG, config_name);
-			_resource_manager->flush();
-			_boot_config.parse((const char*)_resource_manager->get(RESOURCE_TYPE_CONFIG, config_name));
-			_resource_manager->unload(RESOURCE_TYPE_CONFIG, config_name);
-		}
+	ResourcePackage* boot_package = create_resource_package(_boot_config.boot_package_name);
+	boot_package->load();
+	boot_package->flush();
 
 
-		// Init all remaining subsystems
-		_bgfx_allocator = CE_NEW(_allocator, BgfxAllocator)(default_allocator());
-		_bgfx_callback  = CE_NEW(_allocator, BgfxCallback)();
-
-		_display = display::create(_allocator);
-		_window = window::create(_allocator);
-		_window->open(_device_options._window_x
-			, _device_options._window_y
-			, _boot_config.window_w
-			, _boot_config.window_h
-			, _device_options._parent_window
-			);
-		_window->set_title(_boot_config.window_title.c_str());
-		_window->set_fullscreen(_boot_config.fullscreen);
-		_window->bgfx_setup();
-
-		bgfx::init(bgfx::RendererType::Count
-			, BGFX_PCI_ID_NONE
-			, 0
-			, _bgfx_callback
-			, _bgfx_allocator
-			);
-
-		_shader_manager   = CE_NEW(_allocator, ShaderManager)(default_allocator());
-		_material_manager = CE_NEW(_allocator, MaterialManager)(default_allocator(), *_resource_manager);
-		_input_manager    = CE_NEW(_allocator, InputManager)(default_allocator());
-		_unit_manager     = CE_NEW(_allocator, UnitManager)(default_allocator());
-		_lua_environment  = CE_NEW(_allocator, LuaEnvironment)();
-
-		audio_globals::init();
-		physics_globals::init(_allocator);
-
-		ResourcePackage* boot_package = create_resource_package(_boot_config.boot_package_name);
-		boot_package->load();
-		boot_package->flush();
-
-		_lua_environment->load_libs();
-		_lua_environment->execute((LuaResource*)_resource_manager->get(RESOURCE_TYPE_SCRIPT, _boot_config.boot_script_name));
-		_lua_environment->call_global("init", 0);
-
-		logi("Engine initialized");
-
-		s16 mouse_x = 0;
-		s16 mouse_y = 0;
-		s16 mouse_last_x = 0;
-		s16 mouse_last_y = 0;
-
-		s64 last_time = os::clocktime();
-		s64 curr_time;
-
-		while (!process_events(mouse_x, mouse_y, mouse_last_x, mouse_last_y, _boot_config.vsync) && !_quit)
-		{
-			curr_time = os::clocktime();
-			const s64 time = curr_time - last_time;
-			last_time = curr_time;
-			const f64 freq = (f64)os::clockfrequency();
-			_last_delta_time = f32(time * (1.0 / freq));
-			_time_since_start += _last_delta_time;
+	_lua_environment->load_libs();
+	_lua_environment->execute((LuaResource*)_resource_manager->get(RESOURCE_TYPE_SCRIPT, _boot_config.boot_script_name));
+	_lua_environment->call_global("init", 0);
 
 
-			profiler_globals::clear();
-			_console_server->update();
+	logi("Engine initialized");
 
 
-			RECORD_FLOAT("device.dt", _last_delta_time);
-			RECORD_FLOAT("device.fps", 1.0f/_last_delta_time);
+	s16 mouse_x = 0;
+	s16 mouse_y = 0;
+	s16 mouse_last_x = 0;
+	s16 mouse_last_y = 0;
 
 
-			if (!_paused)
-			{
-				_resource_manager->complete_requests();
+	s64 last_time = os::clocktime();
+	s64 curr_time;
 
 
-				{
-					const s64 t0 = os::clocktime();
-					_lua_environment->call_global("update", 1, ARGUMENT_FLOAT, last_delta_time());
-					const s64 t1 = os::clocktime();
-					RECORD_FLOAT("lua.update", f32((t1 - t0)*(1.0 / freq)));
-				}
-				{
-					const s64 t0 = os::clocktime();
-					_lua_environment->call_global("render", 1, ARGUMENT_FLOAT, last_delta_time());
-					const s64 t1 = os::clocktime();
-					RECORD_FLOAT("lua.render", f32((t1 - t0)*(1.0 / freq)));
-				}
+	while (!process_events(mouse_x, mouse_y, mouse_last_x, mouse_last_y, _boot_config.vsync) && !_quit)
+	{
+		curr_time = os::clocktime();
+		const s64 time = curr_time - last_time;
+		last_time = curr_time;
+		const f64 freq = (f64)os::clockfrequency();
+		_last_delta_time = f32(time * (1.0 / freq));
+		_time_since_start += _last_delta_time;
+
+		profiler_globals::clear();
+		console_server()->update();
+
+		RECORD_FLOAT("device.dt", _last_delta_time);
+		RECORD_FLOAT("device.fps", 1.0f/_last_delta_time);
+
+		if (!_paused)
+		{
+			_resource_manager->complete_requests();
+
+			{
+				const s64 t0 = os::clocktime();
+				_lua_environment->call_global("update", 1, ARGUMENT_FLOAT, last_delta_time());
+				const s64 t1 = os::clocktime();
+				RECORD_FLOAT("lua.update", f32((t1 - t0)*(1.0 / freq)));
 			}
 			}
+			{
+				const s64 t0 = os::clocktime();
+				_lua_environment->call_global("render", 1, ARGUMENT_FLOAT, last_delta_time());
+				const s64 t1 = os::clocktime();
+				RECORD_FLOAT("lua.render", f32((t1 - t0)*(1.0 / freq)));
+			}
+		}
 
 
-			_input_manager->update();
+		_input_manager->update();
 
 
-			const bgfx::Stats* stats = bgfx::getStats();
-			RECORD_FLOAT("bgfx.gpu_time", f32(f64(stats->gpuTimeEnd - stats->gpuTimeBegin)*1000.0/stats->gpuTimerFreq));
-			RECORD_FLOAT("bgfx.cpu_time", f32(f64(stats->cpuTimeEnd - stats->cpuTimeBegin)*1000.0/stats->cpuTimerFreq));
+		const bgfx::Stats* stats = bgfx::getStats();
+		RECORD_FLOAT("bgfx.gpu_time", f32(f64(stats->gpuTimeEnd - stats->gpuTimeBegin)*1000.0/stats->gpuTimerFreq));
+		RECORD_FLOAT("bgfx.cpu_time", f32(f64(stats->cpuTimeEnd - stats->cpuTimeBegin)*1000.0/stats->cpuTimerFreq));
 
 
-			bgfx::frame();
-			profiler_globals::flush();
+		bgfx::frame();
+		profiler_globals::flush();
 
 
-			_lua_environment->reset_temporaries();
+		_lua_environment->reset_temporaries();
 
 
-			_frame_count++;
-		}
+		_frame_count++;
+	}
 
 
-		_lua_environment->call_global("shutdown", 0);
+	_lua_environment->call_global("shutdown", 0);
 
 
-		boot_package->unload();
-		destroy_resource_package(*boot_package);
+	boot_package->unload();
+	destroy_resource_package(*boot_package);
 
 
-		physics_globals::shutdown(_allocator);
-		audio_globals::shutdown();
+	physics_globals::shutdown(_allocator);
+	audio_globals::shutdown();
 
 
-		CE_DELETE(_allocator, _lua_environment);
-		CE_DELETE(_allocator, _unit_manager);
-		CE_DELETE(_allocator, _input_manager);
-		CE_DELETE(_allocator, _material_manager);
-		CE_DELETE(_allocator, _shader_manager);
-		CE_DELETE(_allocator, _resource_manager);
-		CE_DELETE(_allocator, _resource_loader);
+	CE_DELETE(_allocator, _lua_environment);
+	CE_DELETE(_allocator, _unit_manager);
+	CE_DELETE(_allocator, _input_manager);
+	CE_DELETE(_allocator, _material_manager);
+	CE_DELETE(_allocator, _shader_manager);
+	CE_DELETE(_allocator, _resource_manager);
+	CE_DELETE(_allocator, _resource_loader);
 
 
-		bgfx::shutdown();
-		_window->close();
-		window::destroy(_allocator, *_window);
-		display::destroy(_allocator, *_display);
-		CE_DELETE(_allocator, _bgfx_callback);
-		CE_DELETE(_allocator, _bgfx_allocator);
+	bgfx::shutdown();
+	_window->close();
+	window::destroy(_allocator, *_window);
+	display::destroy(_allocator, *_display);
+	CE_DELETE(_allocator, _bgfx_callback);
+	CE_DELETE(_allocator, _bgfx_allocator);
 
 
-		if (_last_log)
-			_bundle_filesystem->close(*_last_log);
+	if (_last_log)
+		_bundle_filesystem->close(*_last_log);
 
 
-		CE_DELETE(_allocator, _bundle_filesystem);
+	CE_DELETE(_allocator, _bundle_filesystem);
 
 
-		profiler_globals::shutdown();
-	}
+	profiler_globals::shutdown();
 
 
-	CE_DELETE(_allocator, _data_compiler);
-	_console_server->shutdown();
-	CE_DELETE(_allocator, _console_server);
+	console_server_globals::shutdown();
 
 
 	_allocator.clear();
 	_allocator.clear();
 }
 }
@@ -674,39 +616,12 @@ void Device::reload(StringId64 type, StringId64 name)
 
 
 void Device::log(const char* msg, LogSeverity::Enum severity)
 void Device::log(const char* msg, LogSeverity::Enum severity)
 {
 {
-	static const char* s_severity_map[] = { "info", "warning", "error" };
-	CE_STATIC_ASSERT(countof(s_severity_map) == LogSeverity::COUNT);
-
 	if (_last_log)
 	if (_last_log)
 	{
 	{
 		_last_log->write(msg, strlen32(msg));
 		_last_log->write(msg, strlen32(msg));
 		_last_log->write("\n", 1);
 		_last_log->write("\n", 1);
 		_last_log->flush();
 		_last_log->flush();
 	}
 	}
-
-	if (_console_server)
-	{
-		TempAllocator4096 ta;
-		StringStream json(ta);
-
-		json << "{\"type\":\"message\",";
-		json << "\"severity\":\"";
-		json << s_severity_map[severity];
-		json << "\",";
-		json << "\"message\":\"";
-
-		// Sanitize msg
-		for (; *msg; msg++)
-		{
-			if (*msg == '"' || *msg == '\\')
-				json << "\\";
-			json << *msg;
-		}
-
-		json << "\"}";
-
-		_console_server->send(string_stream::c_str(json));
-	}
 }
 }
 
 
 char _buffer[sizeof(Device)];
 char _buffer[sizeof(Device)];

+ 0 - 3
src/device/device.h

@@ -9,7 +9,6 @@
 #include "boot_config.h"
 #include "boot_config.h"
 #include "compiler_types.h"
 #include "compiler_types.h"
 #include "config.h"
 #include "config.h"
-#include "console_server.h"
 #include "container_types.h"
 #include "container_types.h"
 #include "device_options.h"
 #include "device_options.h"
 #include "display.h"
 #include "display.h"
@@ -40,8 +39,6 @@ struct Device
 
 
 	const DeviceOptions& _device_options;
 	const DeviceOptions& _device_options;
 	BootConfig _boot_config;
 	BootConfig _boot_config;
-	ConsoleServer* _console_server;
-	DataCompiler* _data_compiler;
 	Filesystem* _bundle_filesystem;
 	Filesystem* _bundle_filesystem;
 	File* _last_log;
 	File* _last_log;
 	ResourceLoader* _resource_loader;
 	ResourceLoader* _resource_loader;

+ 30 - 0
src/device/log.cpp

@@ -3,11 +3,13 @@
  * License: https://github.com/taylor001/crown/blob/master/LICENSE
  * License: https://github.com/taylor001/crown/blob/master/LICENSE
  */
  */
 
 
+#include "console_server.h"
 #include "device.h"
 #include "device.h"
 #include "log.h"
 #include "log.h"
 #include "mutex.h"
 #include "mutex.h"
 #include "os.h"
 #include "os.h"
 #include "platform.h"
 #include "platform.h"
+#include "string_stream.h"
 #include "string_utils.h"
 #include "string_utils.h"
 #include "temp_allocator.h"
 #include "temp_allocator.h"
 
 
@@ -46,6 +48,34 @@ namespace log_internal
 #endif
 #endif
 		os::log("\n");
 		os::log("\n");
 
 
+		if (console_server())
+		{
+			static const char* s_severity_map[] = { "info", "warning", "error" };
+			CE_STATIC_ASSERT(countof(s_severity_map) == LogSeverity::COUNT);
+
+			TempAllocator4096 ta;
+			StringStream json(ta);
+
+			json << "{\"type\":\"message\",";
+			json << "\"severity\":\"";
+			json << s_severity_map[sev];
+			json << "\",";
+			json << "\"message\":\"";
+
+			// Sanitize buf
+			const char* ch = buf;
+			for (; *ch; ch++)
+			{
+				if (*ch == '"' || *ch == '\\')
+					json << "\\";
+				json << *ch;
+			}
+
+			json << "\"}";
+
+			console_server()->send(string_stream::c_str(json));
+		}
+
 		if (device())
 		if (device())
 			device()->log(buf, sev);
 			device()->log(buf, sev);
 	}
 	}

+ 12 - 5
src/device/main_linux.cpp

@@ -9,6 +9,7 @@
 
 
 #include "array.h"
 #include "array.h"
 #include "command_line.h"
 #include "command_line.h"
+#include "data_compiler.h"
 #include "device.h"
 #include "device.h"
 #include "device_event_queue.h"
 #include "device_event_queue.h"
 #include "display.h"
 #include "display.h"
@@ -16,16 +17,16 @@
 #include "thread.h"
 #include "thread.h"
 #include "unit_tests.h"
 #include "unit_tests.h"
 #include "window.h"
 #include "window.h"
+#include <X11/XKBlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/Xrandr.h>
 #include <bgfx/bgfxplatform.h>
 #include <bgfx/bgfxplatform.h>
 #include <fcntl.h>  // O_RDONLY, ...
 #include <fcntl.h>  // O_RDONLY, ...
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h> // memset
 #include <string.h> // memset
 #include <unistd.h> // close
 #include <unistd.h> // close
-#include <X11/extensions/Xrandr.h>
-#include <X11/Xatom.h>
-#include <X11/XKBlib.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
 
 
 namespace crown
 namespace crown
 {
 {
@@ -752,6 +753,12 @@ int main(int argc, char** argv)
 		return EXIT_SUCCESS;
 		return EXIT_SUCCESS;
 	}
 	}
 #endif // CROWN_BUILD_UNIT_TESTS
 #endif // CROWN_BUILD_UNIT_TESTS
+	if (cl.has_argument("compile") || cl.has_argument("server"))
+	{
+		if (main_data_compiler(argc, argv) != EXIT_SUCCESS || !cl.has_argument("continue"))
+			return EXIT_FAILURE;
+	}
+
 	InitMemoryGlobals m;
 	InitMemoryGlobals m;
 	CE_UNUSED(m);
 	CE_UNUSED(m);
 
 

+ 14 - 6
src/device/main_windows.cpp

@@ -8,6 +8,7 @@
 #if CROWN_PLATFORM_WINDOWS
 #if CROWN_PLATFORM_WINDOWS
 
 
 #include "command_line.h"
 #include "command_line.h"
+#include "data_compiler.h"
 #include "device.h"
 #include "device.h"
 #include "device_event_queue.h"
 #include "device_event_queue.h"
 #include "thread.h"
 #include "thread.h"
@@ -706,6 +707,13 @@ struct InitMemoryGlobals
 int main(int argc, char** argv)
 int main(int argc, char** argv)
 {
 {
 	using namespace crown;
 	using namespace crown;
+
+	WSADATA wsdata;
+	int err = WSAStartup(MAKEWORD(2, 2), &wsdata);
+	CE_ASSERT(err == 0, "WSAStartup: error = %d", err);
+	CE_UNUSED(wsdata);
+	CE_UNUSED(err);
+
 #if CROWN_BUILD_UNIT_TESTS
 #if CROWN_BUILD_UNIT_TESTS
 	CommandLine cl(argc, (const char**)argv);
 	CommandLine cl(argc, (const char**)argv);
 	if (cl.has_argument("run-unit-tests"))
 	if (cl.has_argument("run-unit-tests"))
@@ -714,15 +722,15 @@ int main(int argc, char** argv)
 		return EXIT_SUCCESS;
 		return EXIT_SUCCESS;
 	}
 	}
 #endif // CROWN_BUILD_UNIT_TESTS
 #endif // CROWN_BUILD_UNIT_TESTS
+	if (cl.has_argument("compile") || cl.has_argument("server"))
+	{
+		if (main_data_compiler(argc, argv) != EXIT_SUCCESS || !cl.has_argument("continue"))
+			return EXIT_FAILURE;
+	}
+
 	InitMemoryGlobals m;
 	InitMemoryGlobals m;
 	CE_UNUSED(m);
 	CE_UNUSED(m);
 
 
-	WSADATA wsdata;
-	int err = WSAStartup(MAKEWORD(2, 2), &wsdata);
-	CE_ASSERT(err == 0, "WSAStartup: error = %d", err);
-	CE_UNUSED(wsdata);
-	CE_UNUSED(err);
-
 	int ec = EXIT_SUCCESS;
 	int ec = EXIT_SUCCESS;
 
 
 	DeviceOptions opts(default_allocator(), argc, (const char**)argv);
 	DeviceOptions opts(default_allocator(), argc, (const char**)argv);

+ 1 - 1
src/lua/lua_api.cpp

@@ -2668,7 +2668,7 @@ static int device_console_send(lua_State* L)
 	StringStream json(alloc);
 	StringStream json(alloc);
 	lua_dump_table(L, 1, json);
 	lua_dump_table(L, 1, json);
 
 
-	device()->_console_server->send(string_stream::c_str(json));
+	console_server()->send(string_stream::c_str(json));
 	return 0;
 	return 0;
 }
 }
 
 

+ 153 - 0
src/resource/data_compiler.cpp

@@ -22,6 +22,24 @@
 #include "vector.h"
 #include "vector.h"
 #include <setjmp.h>
 #include <setjmp.h>
 
 
+#include "resource_types.h"
+#include "config_resource.h"
+#include "font_resource.h"
+#include "lua_resource.h"
+#include "level_resource.h"
+#include "mesh_resource.h"
+#include "material_resource.h"
+#include "physics_resource.h"
+#include "package_resource.h"
+#include "sound_resource.h"
+#include "shader_resource.h"
+#include "sprite_resource.h"
+#include "texture_resource.h"
+#include "unit_resource.h"
+#include "device_options.h"
+#include "console_api.h"
+#include "json_object.h"
+
 namespace crown
 namespace crown
 {
 {
 class LineReader
 class LineReader
@@ -53,6 +71,42 @@ public:
 	}
 	}
 };
 };
 
 
+static void console_command_compile(ConsoleServer& cs, TCPSocket client, const char* json, void* user_data)
+{
+	TempAllocator4096 ta;
+	JsonObject obj(ta);
+	DynamicString id(ta);
+	DynamicString data_dir(ta);
+	DynamicString platform(ta);
+
+	sjson::parse(json, obj);
+	sjson::parse_string(obj["id"], id);
+	sjson::parse_string(obj["data_dir"], data_dir);
+	sjson::parse_string(obj["platform"], platform);
+
+	{
+		TempAllocator512 ta;
+		StringStream ss(ta);
+		ss << "{\"type\":\"compile\",\"id\":\"" << id.c_str() << "\",\"start\":true}";
+		cs.send(client, string_stream::c_str(ss));
+	}
+
+	logi("Compiling '%s'", id.c_str());
+	bool succ = ((DataCompiler*)user_data)->compile(data_dir.c_str(), platform.c_str());
+
+	if (succ)
+		logi("Compiled '%s'", id.c_str());
+	else
+		loge("Error while compiling '%s'", id.c_str());
+
+	{
+		TempAllocator512 ta;
+		StringStream ss(ta);
+		ss << "{\"type\":\"compile\",\"id\":\"" << id.c_str() << "\",\"success\":" << (succ ? "true" : "false") << "}";
+		cs.send(client, string_stream::c_str(ss));
+	}
+}
+
 DataCompiler::DataCompiler(ConsoleServer& cs)
 DataCompiler::DataCompiler(ConsoleServer& cs)
 	: _console_server(&cs)
 	: _console_server(&cs)
 	, _source_fs(default_allocator())
 	, _source_fs(default_allocator())
@@ -62,6 +116,7 @@ DataCompiler::DataCompiler(ConsoleServer& cs)
 	, _globs(default_allocator())
 	, _globs(default_allocator())
 	, _file_monitor(default_allocator())
 	, _file_monitor(default_allocator())
 {
 {
+	cs.register_command("compile", console_command_compile, this);
 }
 }
 
 
 DataCompiler::~DataCompiler()
 DataCompiler::~DataCompiler()
@@ -466,4 +521,102 @@ void DataCompiler::filemonitor_callback(void* thiz, FileMonitorEvent::Enum fme,
 	((DataCompiler*)thiz)->filemonitor_callback(fme, is_dir, path_original, path_modified);
 	((DataCompiler*)thiz)->filemonitor_callback(fme, is_dir, path_original, path_modified);
 }
 }
 
 
+struct InitMemoryGlobals
+{
+	InitMemoryGlobals()
+	{
+		crown::memory_globals::init();
+	}
+
+	~InitMemoryGlobals()
+	{
+		crown::memory_globals::shutdown();
+	}
+};
+
+int main_data_compiler(int argc, char** argv)
+{
+	InitMemoryGlobals m;
+	CE_UNUSED(m);
+
+	DeviceOptions opts(default_allocator(), argc, (const char**)argv);
+	if (opts.parse() == EXIT_FAILURE)
+		return EXIT_FAILURE;
+
+	DataCompiler* _data_compiler = NULL;
+
+	console_server_globals::init();
+	load_console_api(*console_server());
+
+	console_server()->listen(CROWN_DEFAULT_COMPILER_PORT, opts._wait_console);
+
+	namespace cor = config_resource_internal;
+	namespace ftr = font_resource_internal;
+	namespace lur = lua_resource_internal;
+	namespace lvr = level_resource_internal;
+	namespace mhr = mesh_resource_internal;
+	namespace mtr = material_resource_internal;
+	namespace pcr = physics_config_resource_internal;
+	namespace phr = physics_resource_internal;
+	namespace pkr = package_resource_internal;
+	namespace sar = sprite_animation_resource_internal;
+	namespace sdr = sound_resource_internal;
+	namespace shr = shader_resource_internal;
+	namespace spr = sprite_resource_internal;
+	namespace txr = texture_resource_internal;
+	namespace utr = unit_resource_internal;
+
+	bool success = false;
+
+	if (opts._do_compile || opts._server)
+	{
+		_data_compiler = CE_NEW(default_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);
+		_data_compiler->register_compiler(RESOURCE_TYPE_MATERIAL,         RESOURCE_VERSION_MATERIAL,         mtr::compile);
+		_data_compiler->register_compiler(RESOURCE_TYPE_MESH,             RESOURCE_VERSION_MESH,             mhr::compile);
+		_data_compiler->register_compiler(RESOURCE_TYPE_PACKAGE,          RESOURCE_VERSION_PACKAGE,          pkr::compile);
+		_data_compiler->register_compiler(RESOURCE_TYPE_PHYSICS,          RESOURCE_VERSION_PHYSICS,          phr::compile);
+		_data_compiler->register_compiler(RESOURCE_TYPE_PHYSICS_CONFIG,   RESOURCE_VERSION_PHYSICS_CONFIG,   pcr::compile);
+		_data_compiler->register_compiler(RESOURCE_TYPE_SCRIPT,           RESOURCE_VERSION_SCRIPT,           lur::compile);
+		_data_compiler->register_compiler(RESOURCE_TYPE_SHADER,           RESOURCE_VERSION_SHADER,           shr::compile);
+		_data_compiler->register_compiler(RESOURCE_TYPE_SOUND,            RESOURCE_VERSION_SOUND,            sdr::compile);
+		_data_compiler->register_compiler(RESOURCE_TYPE_SPRITE,           RESOURCE_VERSION_SPRITE,           spr::compile);
+		_data_compiler->register_compiler(RESOURCE_TYPE_SPRITE_ANIMATION, RESOURCE_VERSION_SPRITE_ANIMATION, sar::compile);
+		_data_compiler->register_compiler(RESOURCE_TYPE_TEXTURE,          RESOURCE_VERSION_TEXTURE,          txr::compile);
+		_data_compiler->register_compiler(RESOURCE_TYPE_UNIT,             RESOURCE_VERSION_UNIT,             utr::compile);
+
+		_data_compiler->map_source_dir("", opts._source_dir.c_str());
+
+		if (opts._map_source_dir_name)
+		{
+			_data_compiler->map_source_dir(opts._map_source_dir_name
+				, opts._map_source_dir_prefix.c_str()
+				);
+		}
+
+		_data_compiler->scan();
+
+		if (opts._server)
+		{
+			while (true)
+			{
+				console_server()->update();
+				os::sleep(60);
+			}
+		}
+		else
+		{
+			success = _data_compiler->compile(opts._data_dir.c_str(), opts._platform);
+		}
+	}
+
+	CE_DELETE(default_allocator(), _data_compiler);
+
+	console_server_globals::shutdown();
+
+	return success ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
 } // namespace crown
 } // namespace crown

+ 2 - 0
src/resource/data_compiler.h

@@ -69,4 +69,6 @@ public:
 	u32 version(StringId64 type);
 	u32 version(StringId64 type);
 };
 };
 
 
+int main_data_compiler(int argc, char** argv);
+
 } // namespace crown
 } // namespace crown