world.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. /*
  2. * Copyright (c) 2012-2018 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/dbartolini/crown/blob/master/LICENSE
  4. */
  5. #include "core/containers/hash_map.h"
  6. #include "core/error/error.h"
  7. #include "core/math/matrix4x4.h"
  8. #include "core/math/vector3.h"
  9. #include "core/math/vector4.h"
  10. #include "core/memory/temp_allocator.h"
  11. #include "lua/lua_environment.h"
  12. #include "resource/resource_manager.h"
  13. #include "resource/unit_resource.h"
  14. #include "world/animation_state_machine.h"
  15. #include "world/debug_line.h"
  16. #include "world/gui.h"
  17. #include "world/level.h"
  18. #include "world/physics_world.h"
  19. #include "world/render_world.h"
  20. #include "world/scene_graph.h"
  21. #include "world/script_world.h"
  22. #include "world/sound_world.h"
  23. #include "world/unit_manager.h"
  24. #include "world/world.h"
  25. namespace crown
  26. {
  27. World::World(Allocator& a, ResourceManager& rm, ShaderManager& sm, MaterialManager& mm, UnitManager& um, LuaEnvironment& env)
  28. : _marker(WORLD_MARKER)
  29. , _allocator(&a)
  30. , _resource_manager(&rm)
  31. , _shader_manager(&sm)
  32. , _material_manager(&mm)
  33. , _lua_environment(&env)
  34. , _unit_manager(&um)
  35. , _lines(NULL)
  36. , _scene_graph(NULL)
  37. , _render_world(NULL)
  38. , _physics_world(NULL)
  39. , _sound_world(NULL)
  40. , _animation_state_machine(NULL)
  41. , _units(a)
  42. , _camera(a)
  43. , _camera_map(a)
  44. , _events(a)
  45. , _gui_buffer(sm)
  46. {
  47. _lines = create_debug_line(true);
  48. _scene_graph = CE_NEW(*_allocator, SceneGraph)(*_allocator, um);
  49. _render_world = CE_NEW(*_allocator, RenderWorld)(*_allocator, rm, sm, mm, um);
  50. _physics_world = CE_NEW(*_allocator, PhysicsWorld)(*_allocator, rm, um, *_lines);
  51. _sound_world = CE_NEW(*_allocator, SoundWorld)(*_allocator);
  52. _script_world = CE_NEW(*_allocator, ScriptWorld)(*_allocator, um, rm, env, *this);
  53. _animation_state_machine = CE_NEW(*_allocator, AnimationStateMachine)(*_allocator, rm, um);
  54. _gui_buffer.create();
  55. list::init_head(_guis);
  56. list::init_head(_levels);
  57. _node.next = NULL;
  58. _node.prev = NULL;
  59. }
  60. World::~World()
  61. {
  62. // Destroy loaded levels
  63. ListNode* cur;
  64. ListNode* tmp;
  65. list_for_each_safe(cur, tmp, &_levels)
  66. {
  67. Level* level = (Level*)container_of(cur, Level, _node);
  68. CE_DELETE(*_allocator, level);
  69. }
  70. // Destroy units
  71. for (u32 i = 0; i < array::size(_units); ++i)
  72. _unit_manager->destroy(_units[i]);
  73. // Destroy subsystems
  74. CE_DELETE(*_allocator, _animation_state_machine);
  75. CE_DELETE(*_allocator, _script_world);
  76. CE_DELETE(*_allocator, _sound_world);
  77. CE_DELETE(*_allocator, _physics_world);
  78. CE_DELETE(*_allocator, _render_world);
  79. CE_DELETE(*_allocator, _scene_graph);
  80. destroy_debug_line(*_lines);
  81. _marker = 0;
  82. }
  83. UnitId World::spawn_unit(StringId64 name, const Vector3& pos, const Quaternion& rot)
  84. {
  85. const UnitResource* ur = (const UnitResource*)_resource_manager->get(RESOURCE_TYPE_UNIT, name);
  86. UnitId id = _unit_manager->create();
  87. spawn_units(*this, *ur, pos, rot, &id);
  88. return id;
  89. }
  90. UnitId World::spawn_empty_unit()
  91. {
  92. UnitId id = _unit_manager->create();
  93. array::push_back(_units, id);
  94. post_unit_spawned_event(id);
  95. return id;
  96. }
  97. void World::destroy_unit(UnitId id)
  98. {
  99. _unit_manager->destroy(id);
  100. for (u32 i = 0, n = array::size(_units); i < n; ++i)
  101. {
  102. if (_units[i] == id)
  103. {
  104. _units[i] = _units[n - 1];
  105. array::pop_back(_units);
  106. break;
  107. }
  108. }
  109. post_unit_destroyed_event(id);
  110. }
  111. u32 World::num_units() const
  112. {
  113. return array::size(_units);
  114. }
  115. void World::units(Array<UnitId>& units) const
  116. {
  117. array::reserve(units, array::size(_units));
  118. array::push(units, array::begin(_units), array::size(_units));
  119. }
  120. void World::update_animations(f32 dt)
  121. {
  122. _animation_state_machine->update(dt);
  123. }
  124. void World::update_scene(f32 dt)
  125. {
  126. // Process animation events
  127. {
  128. EventStream& events = _animation_state_machine->_events;
  129. const u32 size = array::size(events);
  130. u32 read = 0;
  131. while (read < size)
  132. {
  133. const EventHeader* eh = (EventHeader*)&events[read];
  134. const char* data = (char*)&eh[1];
  135. read += sizeof(*eh) + eh->size;
  136. switch (eh->type)
  137. {
  138. case 0:
  139. {
  140. const SpriteFrameChangeEvent& ptev = *(SpriteFrameChangeEvent*)data;
  141. _render_world->sprite_set_frame(ptev.unit, ptev.frame_num);
  142. }
  143. break;
  144. default:
  145. CE_FATAL("Unknown event type");
  146. break;
  147. }
  148. }
  149. array::clear(events);
  150. }
  151. TempAllocator4096 ta;
  152. Array<UnitId> changed_units(ta);
  153. Array<Matrix4x4> changed_world(ta);
  154. _scene_graph->get_changed(changed_units, changed_world);
  155. _physics_world->update_actor_world_poses(array::begin(changed_units)
  156. , array::end(changed_units)
  157. , array::begin(changed_world)
  158. );
  159. _physics_world->update(dt);
  160. // Process physics events
  161. {
  162. EventStream& events = _physics_world->events();
  163. const u32 size = array::size(events);
  164. u32 read = 0;
  165. while (read < size)
  166. {
  167. const EventHeader* eh = (EventHeader*)&events[read];
  168. const char* data = (char*)&eh[1];
  169. read += sizeof(*eh) + eh->size;
  170. switch (eh->type)
  171. {
  172. case EventType::PHYSICS_TRANSFORM:
  173. {
  174. const PhysicsTransformEvent& ptev = *(PhysicsTransformEvent*)data;
  175. const TransformInstance ti = _scene_graph->instances(ptev.unit_id);
  176. const Matrix4x4 pose = matrix4x4(ptev.rotation, ptev.position);
  177. _scene_graph->set_world_pose(ti, pose);
  178. }
  179. break;
  180. case EventType::PHYSICS_COLLISION:
  181. {
  182. const PhysicsCollisionEvent& pcev = *(PhysicsCollisionEvent*)data;
  183. script_world::collision(*_script_world, pcev);
  184. }
  185. break;
  186. case EventType::PHYSICS_TRIGGER:
  187. break;
  188. default:
  189. CE_FATAL("Unknown event type");
  190. break;
  191. }
  192. }
  193. array::clear(events);
  194. }
  195. array::clear(changed_units);
  196. array::clear(changed_world);
  197. _scene_graph->get_changed(changed_units, changed_world);
  198. _scene_graph->clear_changed();
  199. _render_world->update_transforms(array::begin(changed_units)
  200. , array::end(changed_units)
  201. , array::begin(changed_world)
  202. );
  203. _sound_world->update();
  204. _gui_buffer.reset();
  205. array::clear(_events);
  206. script_world::update(*_script_world, dt);
  207. }
  208. void World::update(f32 dt)
  209. {
  210. update_animations(dt);
  211. update_scene(dt);
  212. }
  213. void World::render(const Matrix4x4& view)
  214. {
  215. _render_world->render(view);
  216. _physics_world->debug_draw();
  217. _render_world->debug_draw(*_lines);
  218. _lines->submit();
  219. _lines->reset();
  220. }
  221. CameraInstance World::camera_create(UnitId id, const CameraDesc& cd, const Matrix4x4& /*tr*/)
  222. {
  223. Camera camera;
  224. camera.unit = id;
  225. camera.projection_type = (ProjectionType::Enum)cd.type;
  226. camera.fov = cd.fov;
  227. camera.near_range = cd.near_range;
  228. camera.far_range = cd.far_range;
  229. const u32 last = array::size(_camera);
  230. array::push_back(_camera, camera);
  231. hash_map::set(_camera_map, id, last);
  232. return camera_make_instance(last);
  233. }
  234. void World::camera_destroy(UnitId unit, CameraInstance /*ci*/)
  235. {
  236. CameraInstance i = camera_instances(unit);
  237. const u32 last = array::size(_camera) - 1;
  238. const UnitId u = _camera[i.i].unit;
  239. const UnitId last_u = _camera[last].unit;
  240. _camera[i.i] = _camera[last];
  241. hash_map::set(_camera_map, last_u, i.i);
  242. hash_map::remove(_camera_map, u);
  243. }
  244. CameraInstance World::camera_instances(UnitId id)
  245. {
  246. return camera_make_instance(hash_map::get(_camera_map, id, UINT32_MAX));
  247. }
  248. void World::camera_set_projection_type(UnitId unit, ProjectionType::Enum type)
  249. {
  250. CameraInstance i = camera_instances(unit);
  251. _camera[i.i].projection_type = type;
  252. }
  253. ProjectionType::Enum World::camera_projection_type(UnitId unit)
  254. {
  255. CameraInstance i = camera_instances(unit);
  256. return _camera[i.i].projection_type;
  257. }
  258. Matrix4x4 World::camera_projection_matrix(UnitId unit)
  259. {
  260. CameraInstance i = camera_instances(unit);
  261. Camera& cam = _camera[i.i];
  262. Matrix4x4 projection;
  263. switch (cam.projection_type)
  264. {
  265. case ProjectionType::ORTHOGRAPHIC:
  266. orthographic(projection
  267. , -cam.half_size * cam.aspect
  268. , cam.half_size * cam.aspect
  269. , -cam.half_size
  270. , cam.half_size
  271. , cam.near_range
  272. , cam.far_range
  273. );
  274. break;
  275. case ProjectionType::PERSPECTIVE:
  276. perspective(projection
  277. , cam.fov
  278. , cam.aspect
  279. , cam.near_range
  280. , cam.far_range
  281. );
  282. break;
  283. default:
  284. CE_FATAL("Unknown projection type");
  285. break;
  286. }
  287. return projection;
  288. }
  289. Matrix4x4 World::camera_view_matrix(UnitId unit)
  290. {
  291. CameraInstance i = camera_instances(unit);
  292. Matrix4x4 view = _scene_graph->world_pose(_camera[i.i].unit);
  293. invert(view);
  294. return view;
  295. }
  296. f32 World::camera_fov(UnitId unit)
  297. {
  298. CameraInstance i = camera_instances(unit);
  299. return _camera[i.i].fov;
  300. }
  301. void World::camera_set_fov(UnitId unit, f32 fov)
  302. {
  303. CameraInstance i = camera_instances(unit);
  304. _camera[i.i].fov = fov;
  305. }
  306. void World::camera_set_aspect(UnitId unit, f32 aspect)
  307. {
  308. CameraInstance i = camera_instances(unit);
  309. _camera[i.i].aspect = aspect;
  310. }
  311. f32 World::camera_near_clip_distance(UnitId unit)
  312. {
  313. CameraInstance i = camera_instances(unit);
  314. return _camera[i.i].near_range;
  315. }
  316. void World::camera_set_near_clip_distance(UnitId unit, f32 near)
  317. {
  318. CameraInstance i = camera_instances(unit);
  319. _camera[i.i].near_range = near;
  320. }
  321. f32 World::camera_far_clip_distance(UnitId unit)
  322. {
  323. CameraInstance i = camera_instances(unit);
  324. return _camera[i.i].far_range;
  325. }
  326. void World::camera_set_far_clip_distance(UnitId unit, f32 far)
  327. {
  328. CameraInstance i = camera_instances(unit);
  329. _camera[i.i].far_range = far;
  330. }
  331. void World::camera_set_orthographic_size(UnitId unit, f32 half_size)
  332. {
  333. CameraInstance i = camera_instances(unit);
  334. _camera[i.i].half_size = half_size;
  335. }
  336. void World::camera_set_viewport_metrics(UnitId unit, u16 x, u16 y, u16 width, u16 height)
  337. {
  338. CameraInstance i = camera_instances(unit);
  339. _camera[i.i].view_x = x;
  340. _camera[i.i].view_y = y;
  341. _camera[i.i].view_width = width;
  342. _camera[i.i].view_height = height;
  343. }
  344. Vector3 World::camera_screen_to_world(UnitId unit, const Vector3& pos)
  345. {
  346. CameraInstance i = camera_instances(unit);
  347. const Camera& c = _camera[i.i];
  348. Matrix4x4 projection = camera_projection_matrix(unit);
  349. Matrix4x4 world_inv = _scene_graph->world_pose(c.unit);
  350. invert(world_inv);
  351. Matrix4x4 mvp = world_inv * projection;
  352. invert(mvp);
  353. Vector4 ndc;
  354. ndc.x = (2.0f * (pos.x - 0.0f)) / c.view_width - 1.0f;
  355. ndc.y = (2.0f * (c.view_height - pos.y)) / c.view_height - 1.0f;
  356. ndc.z = (2.0f * pos.z) - 1.0f;
  357. ndc.w = 1.0f;
  358. Vector4 tmp = ndc * mvp;
  359. tmp *= 1.0f / tmp.w;
  360. return vector3(tmp.x, tmp.y, tmp.z);
  361. }
  362. Vector3 World::camera_world_to_screen(UnitId unit, const Vector3& pos)
  363. {
  364. CameraInstance i = camera_instances(unit);
  365. const Camera& c = _camera[i.i];
  366. Matrix4x4 projection = camera_projection_matrix(unit);
  367. Matrix4x4 world_inv = _scene_graph->world_pose(c.unit);
  368. invert(world_inv);
  369. Vector4 xyzw;
  370. xyzw.x = pos.x;
  371. xyzw.y = pos.y;
  372. xyzw.z = pos.z;
  373. xyzw.w = 1.0f;
  374. Vector4 clip = xyzw * (world_inv * projection);
  375. Vector4 ndc;
  376. ndc.x = clip.x / clip.w;
  377. ndc.y = clip.y / clip.w;
  378. Vector3 screen;
  379. screen.x = (c.view_x + c.view_width * (ndc.x + 1.0f)) / 2.0f;
  380. screen.y = (c.view_y + c.view_height * (1.0f - ndc.y)) / 2.0f;
  381. screen.z = 0.0f;
  382. return screen;
  383. }
  384. SoundInstanceId World::play_sound(const SoundResource& sr, const bool loop, const f32 volume, const Vector3& pos, const f32 range)
  385. {
  386. return _sound_world->play(sr, loop, volume, range, pos);
  387. }
  388. SoundInstanceId World::play_sound(StringId64 name, const bool loop, const f32 volume, const Vector3& pos, const f32 range)
  389. {
  390. const SoundResource* sr = (const SoundResource*)_resource_manager->get(RESOURCE_TYPE_SOUND, name);
  391. return play_sound(*sr, loop, volume, pos, range);
  392. }
  393. void World::stop_sound(SoundInstanceId id)
  394. {
  395. _sound_world->stop(id);
  396. }
  397. void World::link_sound(SoundInstanceId /*id*/, UnitId /*unit*/, s32 /*node*/)
  398. {
  399. CE_FATAL("Not implemented yet");
  400. }
  401. void World::set_listener_pose(const Matrix4x4& pose)
  402. {
  403. _sound_world->set_listener_pose(pose);
  404. }
  405. void World::set_sound_position(SoundInstanceId id, const Vector3& pos)
  406. {
  407. _sound_world->set_sound_positions(1, &id, &pos);
  408. }
  409. void World::set_sound_range(SoundInstanceId id, f32 range)
  410. {
  411. _sound_world->set_sound_ranges(1, &id, &range);
  412. }
  413. void World::set_sound_volume(SoundInstanceId id, f32 vol)
  414. {
  415. _sound_world->set_sound_volumes(1, &id, &vol);
  416. }
  417. DebugLine* World::create_debug_line(bool depth_test)
  418. {
  419. return CE_NEW(*_allocator, DebugLine)(*_shader_manager, depth_test);
  420. }
  421. void World::destroy_debug_line(DebugLine& line)
  422. {
  423. CE_DELETE(*_allocator, &line);
  424. }
  425. Gui* World::create_screen_gui()
  426. {
  427. Gui* gui = CE_NEW(*_allocator, Gui)(_gui_buffer, *_resource_manager
  428. , *_shader_manager
  429. , *_material_manager
  430. );
  431. list::add(gui->_node, _guis);
  432. return gui;
  433. }
  434. void World::destroy_gui(Gui& gui)
  435. {
  436. list::remove(gui._node);
  437. CE_DELETE(*_allocator, &gui);
  438. }
  439. Level* World::load_level(StringId64 name, const Vector3& pos, const Quaternion& rot)
  440. {
  441. const LevelResource* lr = (const LevelResource*)_resource_manager->get(RESOURCE_TYPE_LEVEL, name);
  442. Level* level = CE_NEW(*_allocator, Level)(*_allocator, *_unit_manager, *this, *lr);
  443. level->load(pos, rot);
  444. list::add(level->_node, _levels);
  445. post_level_loaded_event();
  446. return level;
  447. }
  448. void World::post_unit_spawned_event(UnitId id)
  449. {
  450. UnitSpawnedEvent ev;
  451. ev.unit = id;
  452. event_stream::write(_events, EventType::UNIT_SPAWNED, ev);
  453. }
  454. void World::post_unit_destroyed_event(UnitId id)
  455. {
  456. UnitDestroyedEvent ev;
  457. ev.unit = id;
  458. event_stream::write(_events, EventType::UNIT_DESTROYED, ev);
  459. }
  460. void World::post_level_loaded_event()
  461. {
  462. LevelLoadedEvent ev;
  463. event_stream::write(_events, EventType::LEVEL_LOADED, ev);
  464. }
  465. void spawn_units(World& w, const UnitResource& ur, const Vector3& pos, const Quaternion& rot, const UnitId* unit_lookup)
  466. {
  467. SceneGraph* scene_graph = w._scene_graph;
  468. RenderWorld* render_world = w._render_world;
  469. PhysicsWorld* physics_world = w._physics_world;
  470. ScriptWorld* script_world = w._script_world;
  471. AnimationStateMachine* animation_state_machine = w._animation_state_machine;
  472. const ComponentData* component = (ComponentData*)(&ur + 1);
  473. for (u32 cc = 0; cc < ur.num_component_types; ++cc, component = (ComponentData*)((char*)component + component->size + sizeof(*component)))
  474. {
  475. const u32* unit_index = (const u32*)(component + 1);
  476. const char* data = (const char*)(unit_index + component->num_instances);
  477. if (component->type == COMPONENT_TYPE_TRANSFORM)
  478. {
  479. const TransformDesc* td = (const TransformDesc*)data;
  480. for (u32 i = 0, n = component->num_instances; i < n; ++i, ++td)
  481. {
  482. Matrix4x4 matrix = matrix4x4(rot, pos);
  483. Matrix4x4 matrix_res = matrix4x4(td->rotation, td->position);
  484. scene_graph->create(unit_lookup[unit_index[i]], matrix_res*matrix);
  485. }
  486. }
  487. else if (component->type == COMPONENT_TYPE_CAMERA)
  488. {
  489. const CameraDesc* cd = (const CameraDesc*)data;
  490. for (u32 i = 0, n = component->num_instances; i < n; ++i, ++cd)
  491. {
  492. w.camera_create(unit_lookup[unit_index[i]], *cd, MATRIX4X4_IDENTITY);
  493. }
  494. }
  495. else if (component->type == COMPONENT_TYPE_COLLIDER)
  496. {
  497. const ColliderDesc* cd = (const ColliderDesc*)data;
  498. for (u32 i = 0, n = component->num_instances; i < n; ++i)
  499. {
  500. physics_world->collider_create(unit_lookup[unit_index[i]], cd);
  501. cd = (ColliderDesc*)((char*)(cd + 1) + cd->size);
  502. }
  503. }
  504. else if (component->type == COMPONENT_TYPE_ACTOR)
  505. {
  506. const ActorResource* ar = (const ActorResource*)data;
  507. for (u32 i = 0, n = component->num_instances; i < n; ++i, ++ar)
  508. {
  509. Matrix4x4 tm = scene_graph->world_pose(unit_lookup[unit_index[i]]);
  510. physics_world->actor_create(unit_lookup[unit_index[i]], ar, tm);
  511. }
  512. }
  513. else if (component->type == COMPONENT_TYPE_MESH_RENDERER)
  514. {
  515. const MeshRendererDesc* mrd = (const MeshRendererDesc*)data;
  516. for (u32 i = 0, n = component->num_instances; i < n; ++i, ++mrd)
  517. {
  518. Matrix4x4 tm = scene_graph->world_pose(unit_lookup[unit_index[i]]);
  519. render_world->mesh_create(unit_lookup[unit_index[i]], *mrd, tm);
  520. }
  521. }
  522. else if (component->type == COMPONENT_TYPE_SPRITE_RENDERER)
  523. {
  524. const SpriteRendererDesc* srd = (const SpriteRendererDesc*)data;
  525. for (u32 i = 0, n = component->num_instances; i < n; ++i, ++srd)
  526. {
  527. Matrix4x4 tm = scene_graph->world_pose(unit_lookup[unit_index[i]]);
  528. render_world->sprite_create(unit_lookup[unit_index[i]], *srd, tm);
  529. }
  530. }
  531. else if (component->type == COMPONENT_TYPE_LIGHT)
  532. {
  533. const LightDesc* ld = (const LightDesc*)data;
  534. for (u32 i = 0, n = component->num_instances; i < n; ++i, ++ld)
  535. {
  536. Matrix4x4 tm = scene_graph->world_pose(unit_lookup[unit_index[i]]);
  537. render_world->light_create(unit_lookup[unit_index[i]], *ld, tm);
  538. }
  539. }
  540. else if (component->type == COMPONENT_TYPE_SCRIPT)
  541. {
  542. const ScriptDesc* sd = (const ScriptDesc*)data;
  543. for (u32 i = 0, n = component->num_instances; i < n; ++i, ++sd)
  544. {
  545. script_world::create(*script_world, unit_lookup[unit_index[i]], *sd);
  546. }
  547. }
  548. else if (component->type == COMPONENT_TYPE_ANIMATION_STATE_MACHINE)
  549. {
  550. const AnimationStateMachineDesc* asmd = (const AnimationStateMachineDesc*)data;
  551. for (u32 i = 0, n = component->num_instances; i < n; ++i, ++asmd)
  552. {
  553. animation_state_machine->create(unit_lookup[unit_index[i]], *asmd);
  554. }
  555. }
  556. else
  557. {
  558. CE_FATAL("Unknown component type");
  559. }
  560. }
  561. for (u32 i = 0; i < ur.num_units; ++i)
  562. array::push_back(w._units, unit_lookup[i]);
  563. // Post events
  564. for (u32 i = 0; i < ur.num_units; ++i)
  565. w.post_unit_spawned_event(unit_lookup[i]);
  566. }
  567. } // namespace crown