world.cpp 17 KB

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