| Function | Hits |
|---|---|
| 1 | |
| ECS_COMBINE:144 | 0 |
| ECS_IS_PAIR:149 | 4 |
| ECS_GENERATION_INC:153 | 1 |
| ECS_ENTITY_T_LO:168 | 4 |
| ECS_GENERATION:172 | 5 |
| ECS_ENTITY_T_HI:176 | 0 |
| ECS_PAIR:180 | 186 |
| ECS_PAIR_FIRST:187 | 0 |
| ECS_PAIR_SECOND:191 | 0 |
| entity_index_try_get_any:195 | 17 |
| entity_index_try_get:208 | 1 |
| entity_index_try_get_fast:222 | 0 |
| entity_index_is_alive:232 | 0 |
| entity_index_get_alive:236 | 0 |
| ecs_get_alive:244 | 0 |
| entity_index_new_id:267 | 0 |
| ecs_pair_first:288 | 4 |
| ecs_pair_second:293 | 5 |
| query_match:298 | 0 |
| find_observers:321 | 0 |
| archetype_move:330 | 1822 |
| archetype_append:390 | 0 |
| new_entity:400 | 0 |
| entity_move:411 | 0 |
| hash:425 | 0 |
| fetch:429 | 0 |
| world_get:440 | 734 |
| world_has_one_inline:471 | 0 |
| world_has:487 | 80 |
| world_target:509 | 1440 |
| ECS_ID_IS_WILDCARD:541 | 0 |
| id_record_ensure:547 | 704 |
| archetype_append_to_records:610 | 0 |
| archetype_create:635 | 987 |
| world_entity:700 | 66852 |
| world_parent:704 | 1 |
| archetype_ensure:708 | 0 |
| find_insert:722 | 0 |
| find_archetype_with:734 | 0 |
| find_archetype_without:752 | 22 |
| archetype_init_edge:769 | 0 |
| archetype_ensure_edge:780 | 0 |
| init_edge_for_add:794 | 0 |
| init_edge_for_remove:811 | 0 |
| create_edge_for_add:834 | 0 |
| create_edge_for_remove:845 | 0 |
| archetype_traverse_add:856 | 1 |
| archetype_traverse_remove:872 | 1 |
| world_add:889 | 19316 |
| world_set:921 | 2775 |
| world_component:973 | 121 |
| world_remove:985 | 298 |
| archetype_fast_delete_last:1010 | 0 |
| archetype_fast_delete:1018 | 0 |
| archetype_delete:1027 | 58 |
| world_clear:1066 | 0 |
| archetype_disconnect_edge:1166 | 0 |
| archetype_remove_edge:1177 | 0 |
| archetype_clear_edges:1182 | 22 |
| archetype_destroy:1215 | 2 |
| world_cleanup:1251 | 1 |
| world_delete:1272 | 65539 |
| world_contains:1448 | 145 |
| NOOP:1452 | 0 |
| query_iter_init:1463 | 26 |
| world_query_iter_next:1529 | 556 |
| world_query_iter_next:1555 | 7 |
| world_query_iter_next:1582 | 0 |
| world_query_iter_next:1610 | 2 |
| world_query_iter_next:1639 | 0 |
| world_query_iter_next:1669 | 0 |
| world_query_iter_next:1700 | 0 |
| world_query_iter_next:1732 | 0 |
| world_query_iter_next:1766 | 2 |
| query_iter:1800 | 20 |
| query_without:1808 | 6 |
| query_with:1838 | 1 |
| query_archetypes:1872 | 5 |
| query_cached:1876 | 6 |
| on_create_callback:1926 | 4 |
| on_delete_callback:1930 | 1 |
| cached_query_iter:1943 | 11 |
| world_query_iter_next:2003 | 11 |
| world_query_iter_next:2029 | 8 |
| world_query_iter_next:2056 | 0 |
| world_query_iter_next:2084 | 0 |
| world_query_iter_next:2113 | 0 |
| world_query_iter_next:2143 | 0 |
| world_query_iter_next:2174 | 0 |
| world_query_iter_next:2206 | 0 |
| world_query_iter_next:2240 | 0 |
| world_query:2297 | 33 |
| world_each:2357 | 2 |
| 12 | |
| world_children:2391 | 2 |
| 0 | |
| world_new:2441 | 73 |
| Line | Hits | Code |
|---|---|---|
| 1 | N/A | --!optimize 2 | >
| 2 | N/A | --!native | >
| 3 | N/A | --!strict | >
| 4 | N/A | --draft 4 | >
| 5 | N/A | > |
| 6 | 0 | type i53 = number |
| 7 | 0 | type i24 = number |
| 8 | N/A | > |
| 9 | 0 | type Ty = { i53 } |
| 10 | 0 | type ArchetypeId = number |
| 11 | N/A | > |
| 12 | 0 | type Column = { any } |
| 13 | N/A | > |
| 14 | 0 | type Map |
| 15 | N/A | > |
| 16 | 0 | type ecs_graph_edge_t = { |
| 17 | 0 | from: ecs_archetype_t, |
| 18 | 0 | to: ecs_archetype_t?, |
| 19 | 0 | id: number, |
| 20 | 0 | prev: ecs_graph_edge_t?, |
| 21 | 0 | next: ecs_graph_edge_t?, |
| 22 | 0 | } |
| 23 | N/A | > |
| 24 | 0 | type ecs_graph_edges_t = Map |
| 25 | N/A | > |
| 26 | 0 | type ecs_graph_node_t = { |
| 27 | 0 | add: ecs_graph_edges_t, |
| 28 | 0 | remove: ecs_graph_edges_t, |
| 29 | 0 | refs: ecs_graph_edge_t, |
| 30 | 0 | } |
| 31 | N/A | > |
| 32 | 0 | type ecs_archetype_t = { |
| 33 | 0 | id: number, |
| 34 | 0 | types: Ty, |
| 35 | 0 | type: string, |
| 36 | 0 | entities: { number }, |
| 37 | 0 | columns: { Column }, |
| 38 | 0 | records: { [i53]: number }, |
| 39 | 0 | counts: { [i53]: number }, |
| 40 | 0 | } & ecs_graph_node_t |
| 41 | N/A | > |
| 42 | 0 | export type Archetype = { |
| 43 | 0 | id: number, |
| 44 | 0 | types: Ty, |
| 45 | 0 | type: string, |
| 46 | 0 | entities: { number }, |
| 47 | 0 | columns: { Column }, |
| 48 | 0 | records: { [Id]: number }, |
| 49 | 0 | counts: { [Id]: number }, |
| 50 | 0 | } |
| 51 | N/A | > |
| 52 | 0 | type ecs_record_t = { |
| 53 | 0 | archetype: ecs_archetype_t, |
| 54 | 0 | row: number, |
| 55 | 0 | dense: i24, |
| 56 | 0 | } |
| 57 | N/A | > |
| 58 | 0 | type ecs_id_record_t = { |
| 59 | 0 | cache: { number }, |
| 60 | 0 | counts: { number }, |
| 61 | 0 | flags: number, |
| 62 | 0 | size: number, |
| 63 | 0 | hooks: { |
| 64 | 0 | on_add: ((entity: i53) -> ())?, |
| 65 | 0 | on_set: ((entity: i53, data: any) -> ())?, |
| 66 | 0 | on_remove: ((entity: i53) -> ())?, |
| 67 | 0 | }, |
| 68 | 0 | } |
| 69 | N/A | > |
| 70 | 0 | type ecs_id_index_t = Map |
| 71 | N/A | > |
| 72 | 0 | type ecs_archetypes_map_t = { [string]: ecs_archetype_t } |
| 73 | N/A | > |
| 74 | 0 | type ecs_archetypes_t = { ecs_archetype_t } |
| 75 | N/A | > |
| 76 | 0 | type ecs_entity_index_t = { |
| 77 | 0 | dense_array: Map |
| 78 | 0 | sparse_array: Map |
| 79 | 0 | alive_count: number, |
| 80 | 0 | max_id: number, |
| 81 | 0 | } |
| 82 | N/A | > |
| 83 | 0 | type ecs_query_data_t = { |
| 84 | 0 | compatible_archetypes: { ecs_archetype_t }, |
| 85 | 0 | ids: { i53 }, |
| 86 | 0 | filter_with: { i53 }, |
| 87 | 0 | filter_without: { i53 }, |
| 88 | 0 | next: () -> (number, ...any), |
| 89 | 0 | world: ecs_world_t, |
| 90 | 0 | } |
| 91 | N/A | > |
| 92 | 0 | type ecs_observer_t = { |
| 93 | 0 | callback: (archetype: ecs_archetype_t) -> (), |
| 94 | 0 | query: ecs_query_data_t, |
| 95 | 0 | } |
| 96 | N/A | > |
| 97 | 0 | type ecs_observable_t = Map |
| 98 | N/A | > |
| 99 | 0 | type ecs_world_t = { |
| 100 | 0 | entity_index: ecs_entity_index_t, |
| 101 | 0 | component_index: ecs_id_index_t, |
| 102 | 0 | archetypes: ecs_archetypes_t, |
| 103 | 0 | archetype_index: ecs_archetypes_map_t, |
| 104 | 0 | max_archetype_id: number, |
| 105 | 0 | max_component_id: number, |
| 106 | 0 | ROOT_ARCHETYPE: ecs_archetype_t, |
| 107 | 0 | observable: Map |
| 108 | 0 | } |
| 109 | N/A | > |
| 110 | 1 | local HI_COMPONENT_ID = _G.__JECS_HI_COMPONENT_ID or 256 |
| 111 | N/A | -- stylua: ignore start | >
| 112 | 1 | local EcsOnAdd = HI_COMPONENT_ID + 1 |
| 113 | 1 | local EcsOnRemove = HI_COMPONENT_ID + 2 |
| 114 | 1 | local EcsOnSet = HI_COMPONENT_ID + 3 |
| 115 | 1 | local EcsWildcard = HI_COMPONENT_ID + 4 |
| 116 | 1 | local EcsChildOf = HI_COMPONENT_ID + 5 |
| 117 | 1 | local EcsComponent = HI_COMPONENT_ID + 6 |
| 118 | 1 | local EcsOnDelete = HI_COMPONENT_ID + 7 |
| 119 | 1 | local EcsOnDeleteTarget = HI_COMPONENT_ID + 8 |
| 120 | 1 | local EcsDelete = HI_COMPONENT_ID + 9 |
| 121 | 1 | local EcsRemove = HI_COMPONENT_ID + 10 |
| 122 | 1 | local EcsName = HI_COMPONENT_ID + 11 |
| 123 | 1 | local EcsOnArchetypeCreate = HI_COMPONENT_ID + 12 |
| 124 | 1 | local EcsOnArchetypeDelete = HI_COMPONENT_ID + 13 |
| 125 | 1 | local EcsRest = HI_COMPONENT_ID + 14 |
| 126 | N/A | > |
| 127 | 1 | local ECS_ID_DELETE = 0b0000_0001 |
| 128 | 1 | local ECS_ID_IS_TAG = 0b0000_0010 |
| 129 | 1 | local ECS_ID_HAS_ON_ADD = 0b0000_0100 |
| 130 | 1 | local ECS_ID_HAS_ON_SET = 0b0000_1000 |
| 131 | 1 | local ECS_ID_HAS_ON_REMOVE = 0b0001_0000 |
| 132 | 1 | local ECS_ID_MASK = 0b0000_0000 |
| 133 | N/A | > |
| 134 | 1 | local ECS_ENTITY_MASK = bit32.lshift(1, 24) |
| 135 | 1 | local ECS_GENERATION_MASK = bit32.lshift(1, 16) |
| 136 | N/A | > |
| 137 | 1 | local NULL_ARRAY = table.freeze({}) |
| 138 | 1 | local ECS_INTERNAL_ERROR = [[ |
| 139 | 0 | This is an internal error, please file a bug report via the following link: |
| 140 | N/A | > |
| 141 | 0 | https://github.com/Ukendio/jecs/issues/new?template=BUG-REPORT.md |
| 142 | 0 | ]] |
| 143 | N/A | > |
| 144 | 1 | local function ECS_COMBINE(id: number, generation: number): i53 |
| 145 | 65539 | return id + (generation * ECS_ENTITY_MASK) |
| 146 | N/A | end | >
| 147 | 1 | local ECS_PAIR_OFFSET = 2^48 |
| 148 | N/A | > |
| 149 | 1 | local function ECS_IS_PAIR(e: number): boolean |
| 150 | 34 | return e > ECS_PAIR_OFFSET |
| 151 | N/A | end | >
| 152 | N/A | > |
| 153 | 1 | local function ECS_GENERATION_INC(e: i53): i53 |
| 154 | 65683 | if e > ECS_ENTITY_MASK then |
| 155 | 65540 | local id = e % ECS_ENTITY_MASK |
| 156 | 65540 | local generation = e // ECS_ENTITY_MASK |
| 157 | N/A | > |
| 158 | 65540 | local next_gen = generation + 1 |
| 159 | 65540 | if next_gen >= ECS_GENERATION_MASK then |
| 160 | 1 | return id |
| 161 | N/A | end | >
| 162 | N/A | > |
| 163 | 65539 | return ECS_COMBINE(id, next_gen) |
| 164 | N/A | end | >
| 165 | 143 | return ECS_COMBINE(e, 1) |
| 166 | N/A | end | >
| 167 | N/A | > |
| 168 | 1 | local function ECS_ENTITY_T_LO(e: i53): i24 |
| 169 | 145 | return e % ECS_ENTITY_MASK |
| 170 | N/A | end | >
| 171 | N/A | > |
| 172 | 1 | local function ECS_GENERATION(e: i53) |
| 173 | 5 | return e // ECS_ENTITY_MASK |
| 174 | N/A | end | >
| 175 | N/A | > |
| 176 | 1 | local function ECS_ENTITY_T_HI(e: i53): i24 |
| 177 | 0 | return e // ECS_ENTITY_MASK |
| 178 | N/A | end | >
| 179 | N/A | > |
| 180 | 1 | local function ECS_PAIR(pred: i53, obj: i53): i53 |
| 181 | 73 | pred %= ECS_ENTITY_MASK |
| 182 | 73 | obj %= ECS_ENTITY_MASK |
| 183 | N/A | > |
| 184 | 73 | return obj + (pred * ECS_ENTITY_MASK) + ECS_PAIR_OFFSET |
| 185 | N/A | end | >
| 186 | N/A | > |
| 187 | 1 | local function ECS_PAIR_FIRST(e: i53): i24 |
| 188 | 260 | return (e - ECS_PAIR_OFFSET) // ECS_ENTITY_MASK |
| 189 | N/A | end | >
| 190 | N/A | > |
| 191 | 1 | local function ECS_PAIR_SECOND(e: i53): i24 |
| 192 | 24 | return (e - ECS_PAIR_OFFSET) % ECS_ENTITY_MASK |
| 193 | N/A | end | >
| 194 | N/A | > |
| 195 | 1 | local function entity_index_try_get_any( |
| 196 | 0 | entity_index: ecs_entity_index_t, |
| 197 | 0 | entity: number |
| 198 | 0 | ): ecs_record_t? |
| 199 | 145 | local r = entity_index.sparse_array[ECS_ENTITY_T_LO(entity)] |
| 200 | N/A | > |
| 201 | 145 | if not r or r.dense == 0 then |
| 202 | 0 | return nil |
| 203 | N/A | end | >
| 204 | N/A | > |
| 205 | 145 | return r |
| 206 | N/A | end | >
| 207 | N/A | > |
| 208 | 1 | local function entity_index_try_get(entity_index: ecs_entity_index_t, entity: number): ecs_record_t? |
| 209 | 145 | local r = entity_index_try_get_any(entity_index, entity) |
| 210 | 145 | if r then |
| 211 | 145 | local r_dense = r.dense |
| 212 | 145 | if r_dense > entity_index.alive_count then |
| 213 | 125 | return nil |
| 214 | N/A | end | >
| 215 | 20 | if entity_index.dense_array[r_dense] ~= entity then |
| 216 | 2 | return nil |
| 217 | N/A | end | >
| 218 | N/A | end | >
| 219 | 18 | return r |
| 220 | N/A | end | >
| 221 | N/A | > |
| 222 | 1 | local function entity_index_try_get_fast(entity_index: ecs_entity_index_t, entity: number): ecs_record_t? |
| 223 | 298 | local r = entity_index.sparse_array[ECS_ENTITY_T_LO(entity)] |
| 224 | 298 | if r then |
| 225 | 298 | if entity_index.dense_array[r.dense] ~= entity then |
| 226 | 0 | return nil |
| 227 | N/A | end | >
| 228 | N/A | end | >
| 229 | 298 | return r |
| 230 | N/A | end | >
| 231 | N/A | > |
| 232 | 1 | local function entity_index_is_alive(entity_index: ecs_entity_index_t, entity: i53) |
| 233 | 145 | return entity_index_try_get(entity_index, entity) ~= nil |
| 234 | N/A | end | >
| 235 | N/A | > |
| 236 | 1 | local function entity_index_get_alive(index: ecs_entity_index_t, entity: i53): i53? |
| 237 | 24 | local r = entity_index_try_get_any(index, entity) |
| 238 | 24 | if r then |
| 239 | 24 | return index.dense_array[r.dense] |
| 240 | N/A | end | >
| 241 | 0 | return nil |
| 242 | N/A | end | >
| 243 | N/A | > |
| 244 | 1 | local function ecs_get_alive(world, entity) |
| 245 | 5 | if entity == 0 then |
| 246 | 0 | return 0 |
| 247 | N/A | end | >
| 248 | N/A | > |
| 249 | 5 | local eindex = world.entity_index |
| 250 | N/A | > |
| 251 | 5 | if entity_index_is_alive(eindex, entity) then |
| 252 | 5 | return entity |
| 253 | N/A | end | >
| 254 | N/A | > |
| 255 | 0 | if entity > ECS_ENTITY_MASK then |
| 256 | 0 | return 0 |
| 257 | N/A | end | >
| 258 | N/A | > |
| 259 | 0 | local current = entity_index_get_alive(eindex, entity) |
| 260 | 0 | if not current or not entity_index_is_alive(eindex, current) then |
| 261 | 0 | return 0 |
| 262 | N/A | end | >
| 263 | N/A | > |
| 264 | 0 | return current |
| 265 | N/A | end | >
| 266 | N/A | > |
| 267 | 1 | local function entity_index_new_id(entity_index: ecs_entity_index_t): i53 |
| 268 | 18688 | local dense_array = entity_index.dense_array |
| 269 | 18688 | local alive_count = entity_index.alive_count |
| 270 | 18688 | local max_id = entity_index.max_id |
| 271 | 18688 | if alive_count ~= max_id then |
| 272 | 0 | alive_count += 1 |
| 273 | 0 | entity_index.alive_count = alive_count |
| 274 | 0 | local id = dense_array[alive_count] |
| 275 | 0 | return id |
| 276 | N/A | end | >
| 277 | N/A | > |
| 278 | 18688 | local id = max_id + 1 |
| 279 | 18688 | entity_index.max_id = id |
| 280 | 18688 | alive_count += 1 |
| 281 | 18688 | entity_index.alive_count = alive_count |
| 282 | 18688 | dense_array[alive_count] = id |
| 283 | 18688 | entity_index.sparse_array[id] = { dense = alive_count } :: ecs_record_t |
| 284 | N/A | > |
| 285 | 18688 | return id |
| 286 | N/A | end | >
| 287 | N/A | > |
| 288 | 1 | local function ecs_pair_first(world: ecs_world_t, e: i53) |
| 289 | 4 | local pred = ECS_PAIR_FIRST(e) |
| 290 | 4 | return ecs_get_alive(world, pred) |
| 291 | N/A | end | >
| 292 | N/A | > |
| 293 | 1 | local function ecs_pair_second(world: ecs_world_t, e: i53) |
| 294 | 5 | local obj = ECS_PAIR_SECOND(e) |
| 295 | 5 | return ecs_get_alive(world, obj) |
| 296 | N/A | end | >
| 297 | N/A | > |
| 298 | 1 | local function query_match(query: ecs_query_data_t, |
| 299 | 0 | archetype: ecs_archetype_t) |
| 300 | 2 | local records = archetype.records |
| 301 | 2 | local with = query.filter_with |
| 302 | N/A | > |
| 303 | 2 | for _, id in with do |
| 304 | 4 | if not records[id] then |
| 305 | 1 | return false |
| 306 | N/A | end | >
| 307 | N/A | end | >
| 308 | N/A | > |
| 309 | 1 | local without = query.filter_without |
| 310 | 1 | if without then |
| 311 | 1 | for _, id in without do |
| 312 | 1 | if records[id] then |
| 313 | 0 | return false |
| 314 | N/A | end | >
| 315 | N/A | end | >
| 316 | N/A | end | >
| 317 | N/A | > |
| 318 | 1 | return true |
| 319 | N/A | end | >
| 320 | N/A | > |
| 321 | 1 | local function find_observers(world: ecs_world_t, event: i53, |
| 322 | 0 | component: i53): { ecs_observer_t }? |
| 323 | 113 | local cache = world.observable[event] |
| 324 | 113 | if not cache then |
| 325 | 110 | return nil |
| 326 | N/A | end | >
| 327 | 3 | return cache[component] :: any |
| 328 | N/A | end | >
| 329 | N/A | > |
| 330 | 1 | local function archetype_move( |
| 331 | 0 | entity_index: ecs_entity_index_t, |
| 332 | 0 | to: ecs_archetype_t, |
| 333 | 0 | dst_row: i24, |
| 334 | 0 | from: ecs_archetype_t, |
| 335 | 0 | src_row: i24 |
| 336 | 0 | ) |
| 337 | 1822 | local src_columns = from.columns |
| 338 | 1822 | local dst_columns = to.columns |
| 339 | 1822 | local dst_entities = to.entities |
| 340 | 1822 | local src_entities = from.entities |
| 341 | N/A | > |
| 342 | 1822 | local last = #src_entities |
| 343 | 1822 | local id_types = from.types |
| 344 | 1822 | local records = to.records |
| 345 | N/A | > |
| 346 | 1822 | for i, column in src_columns do |
| 347 | 2251 | if column == NULL_ARRAY then |
| 348 | 0 | continue |
| 349 | N/A | end | >
| 350 | N/A | -- Retrieves the new column index from the source archetype's record from each component | >
| 351 | N/A | -- We have to do this because the columns are tightly packed and indexes may not correspond to each other. | >
| 352 | 1739 | local tr = records[id_types[i]] |
| 353 | N/A | > |
| 354 | N/A | -- Sometimes target column may not exist, e.g. when you remove a component. | >
| 355 | 1739 | if tr then |
| 356 | 1446 | dst_columns[tr][dst_row] = column[src_row] |
| 357 | N/A | end | >
| 358 | N/A | > |
| 359 | N/A | -- If the entity is the last row in the archetype then swapping it would be meaningless. | >
| 360 | 1739 | if src_row ~= last then |
| 361 | N/A | -- Swap rempves columns to ensure there are no holes in the archetype. | >
| 362 | 95 | column[src_row] = column[last] |
| 363 | N/A | end | >
| 364 | 1739 | column[last] = nil |
| 365 | N/A | end | >
| 366 | N/A | > |
| 367 | 1822 | local moved = #src_entities |
| 368 | N/A | > |
| 369 | N/A | -- Move the entity from the source to the destination archetype. | >
| 370 | N/A | -- Because we have swapped columns we now have to update the records | >
| 371 | N/A | -- corresponding to the entities' rows that were swapped. | >
| 372 | 1822 | local e1 = src_entities[src_row] |
| 373 | 1822 | local e2 = src_entities[moved] |
| 374 | N/A | > |
| 375 | 1822 | if src_row ~= moved then |
| 376 | 461 | src_entities[src_row] = e2 |
| 377 | N/A | end | >
| 378 | N/A | > |
| 379 | 1822 | src_entities[moved] = nil :: any |
| 380 | 1822 | dst_entities[dst_row] = e1 |
| 381 | N/A | > |
| 382 | 1822 | local sparse_array = entity_index.sparse_array |
| 383 | N/A | > |
| 384 | 1822 | local record1 = sparse_array[ECS_ENTITY_T_LO(e1)] |
| 385 | 1822 | local record2 = sparse_array[ECS_ENTITY_T_LO(e2)] |
| 386 | 1822 | record1.row = dst_row |
| 387 | 1822 | record2.row = src_row |
| 388 | N/A | end | >
| 389 | N/A | > |
| 390 | 1 | local function archetype_append( |
| 391 | 0 | entity: i53, |
| 392 | 0 | archetype: ecs_archetype_t |
| 393 | 0 | ): number |
| 394 | 296 | local entities = archetype.entities |
| 395 | 296 | local length = #entities + 1 |
| 396 | 296 | entities[length] = entity |
| 397 | 296 | return length |
| 398 | N/A | end | >
| 399 | N/A | > |
| 400 | 1 | local function new_entity( |
| 401 | 0 | entity: i53, |
| 402 | 0 | record: ecs_record_t, |
| 403 | 0 | archetype: ecs_archetype_t |
| 404 | 0 | ): ecs_record_t |
| 405 | 1388 | local row = archetype_append(entity, archetype) |
| 406 | 1388 | record.archetype = archetype |
| 407 | 1388 | record.row = row |
| 408 | 0 | return record |
| 409 | N/A | end | >
| 410 | N/A | > |
| 411 | 1 | local function entity_move( |
| 412 | 0 | entity_index: ecs_entity_index_t, |
| 413 | 0 | entity: i53, |
| 414 | 0 | record: ecs_record_t, |
| 415 | 0 | to: ecs_archetype_t |
| 416 | 0 | ) |
| 417 | 296 | local sourceRow = record.row |
| 418 | 296 | local from = record.archetype |
| 419 | 296 | local dst_row = archetype_append(entity, to) |
| 420 | 296 | archetype_move(entity_index, to, dst_row, from, sourceRow) |
| 421 | 296 | record.archetype = to |
| 422 | 296 | record.row = dst_row |
| 423 | N/A | end | >
| 424 | N/A | > |
| 425 | 1 | local function hash(arr: { number }): string |
| 426 | 324 | return table.concat(arr, "_") |
| 427 | N/A | end | >
| 428 | N/A | > |
| 429 | 1 | local function fetch(id: i53, records: { number }, |
| 430 | 0 | columns: { Column }, row: number): any |
| 431 | 623 | local tr = records[id] |
| 432 | N/A | > |
| 433 | 623 | if not tr then |
| 434 | 598 | return nil |
| 435 | N/A | end | >
| 436 | N/A | > |
| 437 | 25 | return columns[tr][row] |
| 438 | N/A | end | >
| 439 | N/A | > |
| 440 | 1 | local function world_get(world: ecs_world_t, entity: i53, |
| 441 | 0 | a: i53, b: i53?, c: i53?, d: i53?, e: i53?): ...any |
| 442 | 734 | local record = entity_index_try_get_fast(world.entity_index, entity) |
| 443 | 734 | if not record then |
| 444 | 75 | return nil |
| 445 | N/A | end | >
| 446 | N/A | > |
| 447 | 659 | local archetype = record.archetype |
| 448 | 659 | if not archetype then |
| 449 | 36 | return nil |
| 450 | N/A | end | >
| 451 | N/A | > |
| 452 | 623 | local records = archetype.records |
| 453 | 623 | local columns = archetype.columns |
| 454 | 623 | local row = record.row |
| 455 | N/A | > |
| 456 | 623 | local va = fetch(a, records, columns, row) |
| 457 | N/A | > |
| 458 | 623 | if not b then |
| 459 | 30 | return va |
| 460 | 593 | elseif not c then |
| 461 | 0 | return va, fetch(b, records, columns, row) |
| 462 | 593 | elseif not d then |
| 463 | 593 | return va, fetch(b, records, columns, row), fetch(c, records, columns, row) |
| 464 | 0 | elseif not e then |
| 465 | 0 | return va, fetch(b, records, columns, row), fetch(c, records, columns, row), fetch(d, records, columns, row) |
| 466 | 0 | else |
| 467 | 0 | error("args exceeded") |
| 468 | N/A | end | >
| 469 | N/A | end | >
| 470 | N/A | > |
| 471 | 1 | local function world_has_one_inline(world: ecs_world_t, entity: i53, id: i53): boolean |
| 472 | 702 | local record = entity_index_try_get_fast(world.entity_index, entity) |
| 473 | 702 | if not record then |
| 474 | 73 | return false |
| 475 | N/A | end | >
| 476 | N/A | > |
| 477 | 629 | local archetype = record.archetype |
| 478 | 629 | if not archetype then |
| 479 | 36 | return false |
| 480 | N/A | end | >
| 481 | N/A | > |
| 482 | 593 | local records = archetype.records |
| 483 | N/A | > |
| 484 | 593 | return records[id] ~= nil |
| 485 | N/A | end | >
| 486 | N/A | > |
| 487 | 1 | local function world_has(world: ecs_world_t, entity: i53, ...: i53): boolean |
| 488 | 80 | local record = entity_index_try_get_fast(world.entity_index, entity) |
| 489 | 80 | if not record then |
| 490 | 22 | return false |
| 491 | N/A | end | >
| 492 | N/A | > |
| 493 | 58 | local archetype = record.archetype |
| 494 | 58 | if not archetype then |
| 495 | 1 | return false |
| 496 | N/A | end | >
| 497 | N/A | > |
| 498 | 57 | local records = archetype.records |
| 499 | N/A | > |
| 500 | 57 | for i = 1, select("#", ...) do |
| 501 | 66 | if not records[select(i, ...)] then |
| 502 | 25 | return false |
| 503 | N/A | end | >
| 504 | N/A | end | >
| 505 | N/A | > |
| 506 | 32 | return true |
| 507 | N/A | end | >
| 508 | N/A | > |
| 509 | 1 | local function world_target(world: ecs_world_t, entity: i53, relation: i24, index: number?): i24? |
| 510 | 1440 | local nth = index or 0 |
| 511 | 1440 | local record = entity_index_try_get_fast(world.entity_index, entity) |
| 512 | 1440 | if not record then |
| 513 | 146 | return nil |
| 514 | N/A | end | >
| 515 | N/A | > |
| 516 | 1294 | local archetype = record.archetype |
| 517 | 1294 | if not archetype then |
| 518 | 72 | return nil |
| 519 | N/A | end | >
| 520 | N/A | > |
| 521 | 1222 | local r = ECS_PAIR(relation, EcsWildcard) |
| 522 | N/A | > |
| 523 | 1222 | local count = archetype.counts[r] |
| 524 | 1222 | if not count then |
| 525 | 1167 | return nil |
| 526 | N/A | end | >
| 527 | N/A | > |
| 528 | 55 | if nth >= count then |
| 529 | 5 | nth = nth + count + 1 |
| 530 | N/A | end | >
| 531 | N/A | > |
| 532 | 55 | nth = archetype.types[nth + archetype.records[r]] |
| 533 | 55 | if not nth then |
| 534 | 5 | return nil |
| 535 | N/A | end | >
| 536 | N/A | > |
| 537 | 50 | return entity_index_get_alive(world.entity_index, |
| 538 | 50 | ECS_PAIR_SECOND(nth)) |
| 539 | N/A | end | >
| 540 | N/A | > |
| 541 | 1 | local function ECS_ID_IS_WILDCARD(e: i53): boolean |
| 542 | 0 | local first = ECS_ENTITY_T_HI(e) |
| 543 | 0 | local second = ECS_ENTITY_T_LO(e) |
| 544 | 0 | return first == EcsWildcard or second == EcsWildcard |
| 545 | N/A | end | >
| 546 | N/A | > |
| 547 | 1 | local function id_record_ensure(world: ecs_world_t, id: number): ecs_id_record_t |
| 548 | 1509 | local component_index = world.component_index |
| 549 | 1509 | local entity_index = world.entity_index |
| 550 | 1509 | local idr: ecs_id_record_t = component_index[id] |
| 551 | N/A | > |
| 552 | 1509 | if not idr then |
| 553 | 704 | local flags = ECS_ID_MASK |
| 554 | 704 | local relation = id |
| 555 | 704 | local target = 0 |
| 556 | 704 | local is_pair = ECS_IS_PAIR(id) |
| 557 | 704 | if is_pair then |
| 558 | 384 | relation = entity_index_get_alive(entity_index, ECS_PAIR_FIRST(id)) :: i53 |
| 559 | 384 | assert(relation and entity_index_is_alive( |
| 560 | 384 | entity_index, relation), ECS_INTERNAL_ERROR) |
| 561 | 383 | target = entity_index_get_alive(entity_index, ECS_PAIR_SECOND(id)) :: i53 |
| 562 | 383 | assert(target and entity_index_is_alive( |
| 563 | 383 | entity_index, target), ECS_INTERNAL_ERROR) |
| 564 | N/A | end | >
| 565 | N/A | > |
| 566 | 702 | local cleanup_policy = world_target(world, relation, EcsOnDelete, 0) |
| 567 | 702 | local cleanup_policy_target = world_target(world, relation, EcsOnDeleteTarget, 0) |
| 568 | N/A | > |
| 569 | 702 | local has_delete = false |
| 570 | N/A | > |
| 571 | 702 | if cleanup_policy == EcsDelete or cleanup_policy_target == EcsDelete then |
| 572 | 21 | has_delete = true |
| 573 | N/A | end | >
| 574 | N/A | > |
| 575 | 702 | local on_add, on_set, on_remove = world_get(world, relation, EcsOnAdd, EcsOnSet, EcsOnRemove) |
| 576 | N/A | > |
| 577 | 702 | local is_tag = not world_has_one_inline(world, relation, EcsComponent) |
| 578 | N/A | > |
| 579 | 702 | if is_tag and is_pair then |
| 580 | 190 | is_tag = not world_has_one_inline(world, target, EcsComponent) |
| 581 | N/A | end | >
| 582 | N/A | > |
| 583 | 702 | flags = bit32.bor( |
| 584 | 702 | flags, |
| 585 | 702 | if on_add then ECS_ID_HAS_ON_ADD else 0, |
| 586 | 702 | if on_remove then ECS_ID_HAS_ON_REMOVE else 0, |
| 587 | 702 | if on_set then ECS_ID_HAS_ON_SET else 0, |
| 588 | 702 | if has_delete then ECS_ID_DELETE else 0, |
| 589 | 702 | if is_tag then ECS_ID_IS_TAG else 0 |
| 590 | 0 | ) |
| 591 | N/A | > |
| 592 | 702 | idr = { |
| 593 | 702 | size = 0, |
| 594 | 702 | cache = {}, |
| 595 | 702 | counts = {}, |
| 596 | 702 | flags = flags, |
| 597 | 702 | hooks = { |
| 598 | 702 | on_add = on_add, |
| 599 | 702 | on_set = on_set, |
| 600 | 702 | on_remove = on_remove, |
| 601 | 0 | }, |
| 602 | 0 | } |
| 603 | N/A | > |
| 604 | 702 | component_index[id] = idr |
| 605 | N/A | end | >
| 606 | N/A | > |
| 607 | 1507 | return idr |
| 608 | N/A | end | >
| 609 | N/A | > |
| 610 | 1 | local function archetype_append_to_records( |
| 611 | 0 | idr: ecs_id_record_t, |
| 612 | 0 | archetype: ecs_archetype_t, |
| 613 | 0 | id: i53, |
| 614 | 0 | index: number |
| 615 | 0 | ) |
| 616 | 987 | local archetype_id = archetype.id |
| 617 | 987 | local archetype_records = archetype.records |
| 618 | 987 | local archetype_counts = archetype.counts |
| 619 | 987 | local idr_columns = idr.cache |
| 620 | 987 | local idr_counts = idr.counts |
| 621 | 987 | local tr = idr_columns[archetype_id] |
| 622 | 987 | if not tr then |
| 623 | 987 | idr_columns[archetype_id] = index |
| 624 | 987 | idr_counts[archetype_id] = 1 |
| 625 | N/A | > |
| 626 | 987 | archetype_records[id] = index |
| 627 | 987 | archetype_counts[id] = 1 |
| 628 | 0 | else |
| 629 | 82 | local max_count = idr_counts[archetype_id] + 1 |
| 630 | 82 | idr_counts[archetype_id] = max_count |
| 631 | 82 | archetype_counts[id] = max_count |
| 632 | N/A | end | >
| 633 | N/A | end | >
| 634 | N/A | > |
| 635 | 1 | local function archetype_create(world: ecs_world_t, id_types: { i24 }, ty, prev: i53?): ecs_archetype_t |
| 636 | 635 | local archetype_id = (world.max_archetype_id :: number) + 1 |
| 637 | 635 | world.max_archetype_id = archetype_id |
| 638 | N/A | > |
| 639 | 635 | local length = #id_types |
| 640 | 635 | local columns = (table.create(length) :: any) :: { Column } |
| 641 | N/A | > |
| 642 | 635 | local records: { number } = {} |
| 643 | 635 | local counts: {number} = {} |
| 644 | N/A | > |
| 645 | 635 | local archetype: ecs_archetype_t = { |
| 646 | 635 | columns = columns, |
| 647 | 635 | entities = {}, |
| 648 | 635 | id = archetype_id, |
| 649 | 635 | records = records, |
| 650 | 635 | counts = counts, |
| 651 | 635 | type = ty, |
| 652 | 635 | types = id_types, |
| 653 | N/A | > |
| 654 | 635 | add = {}, |
| 655 | 635 | remove = {}, |
| 656 | 635 | refs = {} :: ecs_graph_edge_t, |
| 657 | 0 | } |
| 658 | N/A | > |
| 659 | 635 | for i, component_id in id_types do |
| 660 | 989 | local idr = id_record_ensure(world, component_id) |
| 661 | 987 | archetype_append_to_records(idr, archetype, component_id, i) |
| 662 | N/A | > |
| 663 | 987 | if ECS_IS_PAIR(component_id) then |
| 664 | 260 | local relation = ECS_PAIR_FIRST(component_id) |
| 665 | 260 | local object = ECS_PAIR_SECOND(component_id) |
| 666 | 260 | local r = ECS_PAIR(relation, EcsWildcard) |
| 667 | 260 | local idr_r = id_record_ensure(world, r) |
| 668 | 260 | archetype_append_to_records(idr_r, archetype, r, i) |
| 669 | N/A | > |
| 670 | 260 | local t = ECS_PAIR(EcsWildcard, object) |
| 671 | 260 | local idr_t = id_record_ensure(world, t) |
| 672 | 260 | archetype_append_to_records(idr_t, archetype, t, i) |
| 673 | N/A | end | >
| 674 | N/A | > |
| 675 | 987 | if bit32.band(idr.flags, ECS_ID_IS_TAG) == 0 then |
| 676 | 594 | columns[i] = {} |
| 677 | 0 | else |
| 678 | 393 | columns[i] = NULL_ARRAY |
| 679 | N/A | end | >
| 680 | N/A | end | >
| 681 | N/A | > |
| 682 | 633 | for id in records do |
| 683 | 1405 | local observer_list = find_observers(world, EcsOnArchetypeCreate, id) |
| 684 | 1405 | if not observer_list then |
| 685 | 0 | continue |
| 686 | N/A | end | >
| 687 | 8 | for _, observer in observer_list do |
| 688 | 8 | if query_match(observer.query, archetype) then |
| 689 | 4 | observer.callback(archetype) |
| 690 | N/A | end | >
| 691 | N/A | end | >
| 692 | N/A | end | >
| 693 | N/A | > |
| 694 | 633 | world.archetype_index[ty] = archetype |
| 695 | 633 | world.archetypes[archetype_id] = archetype |
| 696 | N/A | > |
| 697 | 633 | return archetype |
| 698 | N/A | end | >
| 699 | N/A | > |
| 700 | 1 | local function world_entity(world: ecs_world_t): i53 |
| 701 | 66852 | return entity_index_new_id(world.entity_index) |
| 702 | N/A | end | >
| 703 | N/A | > |
| 704 | 1 | local function world_parent(world: ecs_world_t, entity: i53) |
| 705 | 1 | return world_target(world, entity, EcsChildOf, 0) |
| 706 | N/A | end | >
| 707 | N/A | > |
| 708 | 1 | local function archetype_ensure(world: ecs_world_t, id_types): ecs_archetype_t |
| 709 | 324 | if #id_types < 1 then |
| 710 | 0 | return world.ROOT_ARCHETYPE |
| 711 | N/A | end | >
| 712 | N/A | > |
| 713 | 324 | local ty = hash(id_types) |
| 714 | 324 | local archetype = world.archetype_index[ty] |
| 715 | 324 | if archetype then |
| 716 | 0 | return archetype |
| 717 | N/A | end | >
| 718 | N/A | > |
| 719 | 324 | return archetype_create(world, id_types, ty) |
| 720 | N/A | end | >
| 721 | N/A | > |
| 722 | 1 | local function find_insert(id_types: { i53 }, toAdd: i53): number |
| 723 | 326 | for i, id in id_types do |
| 724 | 244 | if id == toAdd then |
| 725 | 2 | return -1 |
| 726 | N/A | end | >
| 727 | 242 | if id > toAdd then |
| 728 | 13 | return i |
| 729 | N/A | end | >
| 730 | N/A | end | >
| 731 | 311 | return #id_types + 1 |
| 732 | N/A | end | >
| 733 | N/A | > |
| 734 | 1 | local function find_archetype_with(world: ecs_world_t, node: ecs_archetype_t, id: i53): ecs_archetype_t |
| 735 | 326 | local id_types = node.types |
| 736 | N/A | -- Component IDs are added incrementally, so inserting and sorting | >
| 737 | N/A | -- them each time would be expensive. Instead this insertion sort can find the insertion | >
| 738 | N/A | -- point in the types array. | >
| 739 | N/A | > |
| 740 | 326 | local dst = table.clone(node.types) :: { i53 } |
| 741 | 326 | local at = find_insert(id_types, id) |
| 742 | 326 | if at == -1 then |
| 743 | N/A | -- If it finds a duplicate, it just means it is the same archetype so it can return it | >
| 744 | N/A | -- directly instead of needing to hash types for a lookup to the archetype. | >
| 745 | 2 | return node |
| 746 | N/A | end | >
| 747 | 324 | table.insert(dst, at, id) |
| 748 | N/A | > |
| 749 | 324 | return archetype_ensure(world, dst) |
| 750 | N/A | end | >
| 751 | N/A | > |
| 752 | 1 | local function find_archetype_without( |
| 753 | 0 | world: ecs_world_t, |
| 754 | 0 | node: ecs_archetype_t, |
| 755 | 0 | id: i53 |
| 756 | 0 | ): ecs_archetype_t |
| 757 | 33 | local id_types = node.types |
| 758 | 33 | local at = table.find(id_types, id) |
| 759 | 33 | if at == nil then |
| 760 | 0 | return node |
| 761 | N/A | end | >
| 762 | N/A | > |
| 763 | 33 | local dst = table.clone(id_types) |
| 764 | 33 | table.remove(dst, at) |
| 765 | N/A | > |
| 766 | 33 | return archetype_ensure(world, dst) |
| 767 | N/A | end | >
| 768 | N/A | > |
| 769 | 1 | local function archetype_init_edge( |
| 770 | 0 | archetype: ecs_archetype_t, |
| 771 | 0 | edge: ecs_graph_edge_t, |
| 772 | 0 | id: i53, |
| 773 | 0 | to: ecs_archetype_t |
| 774 | 0 | ) |
| 775 | 32 | edge.from = archetype |
| 776 | 32 | edge.to = to |
| 777 | 32 | edge.id = id |
| 778 | N/A | end | >
| 779 | N/A | > |
| 780 | 1 | local function archetype_ensure_edge( |
| 781 | 0 | world: ecs_world_t, |
| 782 | 0 | edges: ecs_graph_edges_t, |
| 783 | 0 | id: i53 |
| 784 | 0 | ): ecs_graph_edge_t |
| 785 | 296 | local edge = edges[id] |
| 786 | 296 | if not edge then |
| 787 | 32 | edge = {} :: ecs_graph_edge_t |
| 788 | 32 | edges[id] = edge |
| 789 | N/A | end | >
| 790 | N/A | > |
| 791 | 296 | return edge |
| 792 | N/A | end | >
| 793 | N/A | > |
| 794 | 1 | local function init_edge_for_add(world, archetype: ecs_archetype_t, edge: ecs_graph_edge_t, id, to: ecs_archetype_t) |
| 795 | 325 | archetype_init_edge(archetype, edge, id, to) |
| 796 | 325 | archetype_ensure_edge(world, archetype.add, id) |
| 797 | 325 | if archetype ~= to then |
| 798 | 323 | local to_refs = to.refs |
| 799 | 323 | local next_edge = to_refs.next |
| 800 | N/A | > |
| 801 | 323 | to_refs.next = edge |
| 802 | 323 | edge.prev = to_refs |
| 803 | 323 | edge.next = next_edge |
| 804 | N/A | > |
| 805 | 323 | if next_edge then |
| 806 | 0 | next_edge.prev = edge |
| 807 | N/A | end | >
| 808 | N/A | end | >
| 809 | N/A | end | >
| 810 | N/A | > |
| 811 | 1 | local function init_edge_for_remove( |
| 812 | 0 | world: ecs_world_t, |
| 813 | 0 | archetype: ecs_archetype_t, |
| 814 | 0 | edge: ecs_graph_edge_t, |
| 815 | 0 | id: number, |
| 816 | 0 | to: ecs_archetype_t |
| 817 | 0 | ) |
| 818 | 32 | archetype_init_edge(archetype, edge, id, to) |
| 819 | 32 | archetype_ensure_edge(world, archetype.remove, id) |
| 820 | 32 | if archetype ~= to then |
| 821 | 32 | local to_refs = to.refs |
| 822 | 32 | local prev_edge = to_refs.prev |
| 823 | N/A | > |
| 824 | 32 | to_refs.prev = edge |
| 825 | 32 | edge.next = to_refs |
| 826 | 32 | edge.prev = prev_edge |
| 827 | N/A | > |
| 828 | 32 | if prev_edge then |
| 829 | 2 | prev_edge.next = edge |
| 830 | N/A | end | >
| 831 | N/A | end | >
| 832 | N/A | end | >
| 833 | N/A | > |
| 834 | 1 | local function create_edge_for_add( |
| 835 | 0 | world: ecs_world_t, |
| 836 | 0 | node: ecs_archetype_t, |
| 837 | 0 | edge: ecs_graph_edge_t, |
| 838 | 0 | id: i53 |
| 839 | 0 | ): ecs_archetype_t |
| 840 | 326 | local to = find_archetype_with(world, node, id) |
| 841 | 325 | init_edge_for_add(world, node, edge, id, to) |
| 842 | 325 | return to |
| 843 | N/A | end | >
| 844 | N/A | > |
| 845 | 1 | local function create_edge_for_remove( |
| 846 | 0 | world: ecs_world_t, |
| 847 | 0 | node: ecs_archetype_t, |
| 848 | 0 | edge: ecs_graph_edge_t, |
| 849 | 0 | id: i53 |
| 850 | 0 | ): ecs_archetype_t |
| 851 | 32 | local to = find_archetype_without(world, node, id) |
| 852 | 32 | init_edge_for_remove(world, node, edge, id, to) |
| 853 | 32 | return to |
| 854 | N/A | end | >
| 855 | N/A | > |
| 856 | 1 | local function archetype_traverse_add( |
| 857 | 0 | world: ecs_world_t, |
| 858 | 0 | id: i53, |
| 859 | 0 | from: ecs_archetype_t |
| 860 | 0 | ): ecs_archetype_t |
| 861 | 2775 | from = from or world.ROOT_ARCHETYPE |
| 862 | 2775 | local edge = archetype_ensure_edge(world, from.add, id) |
| 863 | N/A | > |
| 864 | 2775 | local to = edge.to |
| 865 | 2775 | if not to then |
| 866 | 326 | to = create_edge_for_add(world, from, edge, id) |
| 867 | N/A | end | >
| 868 | N/A | > |
| 869 | 2774 | return to :: ecs_archetype_t |
| 870 | N/A | end | >
| 871 | N/A | > |
| 872 | 1 | local function archetype_traverse_remove( |
| 873 | 0 | world: ecs_world_t, |
| 874 | 0 | id: i53, |
| 875 | 0 | from: ecs_archetype_t |
| 876 | 0 | ): ecs_archetype_t |
| 877 | 296 | from = from or world.ROOT_ARCHETYPE |
| 878 | N/A | > |
| 879 | 296 | local edge = archetype_ensure_edge(world, from.remove, id) |
| 880 | N/A | > |
| 881 | 296 | local to = edge.to |
| 882 | 296 | if not to then |
| 883 | 32 | to = create_edge_for_remove(world, from, edge, id) |
| 884 | N/A | end | >
| 885 | N/A | > |
| 886 | 296 | return to :: ecs_archetype_t |
| 887 | N/A | end | >
| 888 | N/A | > |
| 889 | 1 | local function world_add( |
| 890 | 0 | world: ecs_world_t, |
| 891 | 0 | entity: i53, |
| 892 | 0 | id: i53 |
| 893 | 0 | ): () |
| 894 | 19316 | local entity_index = world.entity_index |
| 895 | 19316 | local record = entity_index_try_get_fast(entity_index, entity) |
| 896 | 19316 | if not record then |
| 897 | 0 | return |
| 898 | N/A | end | >
| 899 | N/A | > |
| 900 | 19316 | local from = record.archetype |
| 901 | 19316 | local to = archetype_traverse_add(world, id, from) |
| 902 | 19315 | if from == to then |
| 903 | 3 | return |
| 904 | N/A | end | >
| 905 | 19312 | if from then |
| 906 | 142 | entity_move(entity_index, entity, record, to) |
| 907 | 0 | else |
| 908 | 19170 | if #to.types > 0 then |
| 909 | 19170 | new_entity(entity, record, to) |
| 910 | N/A | end | >
| 911 | N/A | end | >
| 912 | N/A | > |
| 913 | 19312 | local idr = world.component_index[id] |
| 914 | 19312 | local on_add = idr.hooks.on_add |
| 915 | N/A | > |
| 916 | 19312 | if on_add then |
| 917 | 1 | on_add(entity) |
| 918 | N/A | end | >
| 919 | N/A | end | >
| 920 | N/A | > |
| 921 | 1 | local function world_set(world: ecs_world_t, entity: i53, id: i53, data: unknown): () |
| 922 | 2775 | local entity_index = world.entity_index |
| 923 | 2775 | local record = entity_index_try_get_fast(entity_index, entity) |
| 924 | 2775 | if not record then |
| 925 | 0 | return |
| 926 | N/A | end | >
| 927 | N/A | > |
| 928 | 2775 | local from: ecs_archetype_t = record.archetype |
| 929 | 2775 | local to: ecs_archetype_t = archetype_traverse_add(world, id, from) |
| 930 | 2774 | local idr = world.component_index[id] |
| 931 | 2774 | local idr_hooks = idr.hooks |
| 932 | N/A | > |
| 933 | 2774 | if from == to then |
| 934 | N/A | -- If the archetypes are the same it can avoid moving the entity | >
| 935 | N/A | -- and just set the data directly. | >
| 936 | 2 | local tr = to.records[id] |
| 937 | 2 | local column = from.columns[tr] |
| 938 | 2 | column[record.row] = data |
| 939 | 2 | local on_set = idr_hooks.on_set |
| 940 | 2 | if on_set then |
| 941 | 0 | on_set(entity, data) |
| 942 | N/A | end | >
| 943 | N/A | > |
| 944 | 2 | return |
| 945 | N/A | end | >
| 946 | N/A | > |
| 947 | 2772 | if from then |
| 948 | N/A | -- If there was a previous archetype, then the entity needs to move the archetype | >
| 949 | 1384 | entity_move(entity_index, entity, record, to) |
| 950 | 0 | else |
| 951 | 1388 | if #to.types > 0 then |
| 952 | N/A | -- When there is no previous archetype it should create the archetype | >
| 953 | 1388 | new_entity(entity, record, to) |
| 954 | N/A | end | >
| 955 | N/A | end | >
| 956 | N/A | > |
| 957 | 2772 | local tr = to.records[id] |
| 958 | 2772 | local column = to.columns[tr] |
| 959 | N/A | > |
| 960 | 2772 | column[record.row] = data |
| 961 | N/A | > |
| 962 | 2765 | local on_add = idr_hooks.on_add |
| 963 | 2765 | if on_add then |
| 964 | 0 | on_add(entity) |
| 965 | N/A | end | >
| 966 | N/A | > |
| 967 | 2765 | local on_set = idr_hooks.on_set |
| 968 | 2765 | if on_set then |
| 969 | 1 | on_set(entity, data) |
| 970 | N/A | end | >
| 971 | N/A | end | >
| 972 | N/A | > |
| 973 | 1 | local function world_component(world: World): i53 |
| 974 | 121 | local id = (world.max_component_id :: number) + 1 |
| 975 | 121 | if id > HI_COMPONENT_ID then |
| 976 | N/A | -- IDs are partitioned into ranges because component IDs are not nominal, | >
| 977 | N/A | -- so it needs to error when IDs intersect into the entity range. | >
| 978 | 0 | error("Too many components, consider using world:entity() instead to create components.") |
| 979 | N/A | end | >
| 980 | 121 | world.max_component_id = id |
| 981 | N/A | > |
| 982 | 121 | return id |
| 983 | N/A | end | >
| 984 | N/A | > |
| 985 | 1 | local function world_remove(world: ecs_world_t, entity: i53, id: i53) |
| 986 | 298 | local entity_index = world.entity_index |
| 987 | 298 | local record = entity_index_try_get_fast(entity_index, entity) |
| 988 | 298 | if not record then |
| 989 | 0 | return |
| 990 | N/A | end | >
| 991 | 298 | local from = record.archetype |
| 992 | N/A | > |
| 993 | 298 | if not from then |
| 994 | 1 | return |
| 995 | N/A | end | >
| 996 | N/A | > |
| 997 | 297 | if from.records[id] then |
| 998 | 296 | local idr = world.component_index[id] |
| 999 | 296 | local on_remove = idr.hooks.on_remove |
| 1000 | 296 | if on_remove then |
| 1001 | 3 | on_remove(entity) |
| 1002 | N/A | end | >
| 1003 | N/A | > |
| 1004 | 296 | local to = archetype_traverse_remove(world, id, record.archetype) |
| 1005 | N/A | > |
| 1006 | 296 | entity_move(entity_index, entity, record, to) |
| 1007 | N/A | end | >
| 1008 | N/A | end | >
| 1009 | N/A | > |
| 1010 | 1 | local function archetype_fast_delete_last(columns: { Column }, column_count: number, types: { i53 }, entity: i53) |
| 1011 | 76 | for i, column in columns do |
| 1012 | 153 | if column ~= NULL_ARRAY then |
| 1013 | 135 | column[column_count] = nil |
| 1014 | N/A | end | >
| 1015 | N/A | end | >
| 1016 | N/A | end | >
| 1017 | N/A | > |
| 1018 | 1 | local function archetype_fast_delete(columns: { Column }, column_count: number, row, types, entity) |
| 1019 | 58 | for i, column in columns do |
| 1020 | 109 | if column ~= NULL_ARRAY then |
| 1021 | 103 | column[row] = column[column_count] |
| 1022 | 103 | column[column_count] = nil |
| 1023 | N/A | end | >
| 1024 | N/A | end | >
| 1025 | N/A | end | >
| 1026 | N/A | > |
| 1027 | 1 | local function archetype_delete(world: ecs_world_t, archetype: ecs_archetype_t, row: number) |
| 1028 | 134 | local entity_index = world.entity_index |
| 1029 | 134 | local component_index = world.component_index |
| 1030 | 134 | local columns = archetype.columns |
| 1031 | 134 | local id_types = archetype.types |
| 1032 | 134 | local entities = archetype.entities |
| 1033 | 134 | local column_count = #entities |
| 1034 | 134 | local last = #entities |
| 1035 | 134 | local move = entities[last] |
| 1036 | N/A | -- We assume first that the entity is the last in the archetype | >
| 1037 | 134 | local delete = move |
| 1038 | N/A | > |
| 1039 | 134 | if row ~= last then |
| 1040 | 58 | local record_to_move = entity_index_try_get_any(entity_index, move) |
| 1041 | 58 | if record_to_move then |
| 1042 | 58 | record_to_move.row = row |
| 1043 | N/A | end | >
| 1044 | N/A | > |
| 1045 | 58 | delete = entities[row] |
| 1046 | 58 | entities[row] = move |
| 1047 | N/A | end | >
| 1048 | N/A | > |
| 1049 | 134 | for _, id in id_types do |
| 1050 | 262 | local idr = component_index[id] |
| 1051 | 262 | local on_remove = idr.hooks.on_remove |
| 1052 | 262 | if on_remove then |
| 1053 | 3 | on_remove(delete) |
| 1054 | N/A | end | >
| 1055 | N/A | end | >
| 1056 | N/A | > |
| 1057 | 134 | entities[last] = nil :: any |
| 1058 | N/A | > |
| 1059 | 134 | if row == last then |
| 1060 | 76 | archetype_fast_delete_last(columns, column_count, id_types, delete) |
| 1061 | 0 | else |
| 1062 | 58 | archetype_fast_delete(columns, column_count, row, id_types, delete) |
| 1063 | N/A | end | >
| 1064 | N/A | end | >
| 1065 | N/A | > |
| 1066 | 1 | local function world_clear(world: ecs_world_t, entity: i53) |
| 1067 | 6 | local entity_index = world.entity_index |
| 1068 | 6 | local component_index = world.component_index |
| 1069 | 6 | local archetypes = world.archetypes |
| 1070 | 6 | local tgt = ECS_PAIR(EcsWildcard, entity) |
| 1071 | 6 | local idr_t = component_index[tgt] |
| 1072 | 6 | local idr = component_index[entity] |
| 1073 | 6 | local rel = ECS_PAIR(entity, EcsWildcard) |
| 1074 | 6 | local idr_r = component_index[rel] |
| 1075 | N/A | > |
| 1076 | 6 | if idr then |
| 1077 | 4 | local count = 0 |
| 1078 | 4 | local queue = {} |
| 1079 | 4 | for archetype_id in idr.cache do |
| 1080 | 11 | local idr_archetype = archetypes[archetype_id] |
| 1081 | 11 | local entities = idr_archetype.entities |
| 1082 | 11 | local n = #entities |
| 1083 | 11 | count += n |
| 1084 | 11 | table.move(entities, 1, n, #queue + 1, queue) |
| 1085 | N/A | end | >
| 1086 | 4 | for _, e in queue do |
| 1087 | 8 | world_remove(world, e, entity) |
| 1088 | N/A | end | >
| 1089 | N/A | end | >
| 1090 | N/A | > |
| 1091 | 6 | if idr_t then |
| 1092 | 0 | local queue |
| 1093 | 0 | local ids |
| 1094 | N/A | > |
| 1095 | 0 | local count = 0 |
| 1096 | 0 | local archetype_ids = idr_t.cache |
| 1097 | 0 | for archetype_id in archetype_ids do |
| 1098 | 0 | local idr_t_archetype = archetypes[archetype_id] |
| 1099 | 0 | local idr_t_types = idr_t_archetype.types |
| 1100 | 0 | local entities = idr_t_archetype.entities |
| 1101 | 0 | local removal_queued = false |
| 1102 | N/A | > |
| 1103 | 0 | for _, id in idr_t_types do |
| 1104 | 0 | if not ECS_IS_PAIR(id) then |
| 1105 | 0 | continue |
| 1106 | N/A | end | >
| 1107 | 0 | local object = entity_index_get_alive( |
| 1108 | 0 | entity_index, ECS_PAIR_SECOND(id)) |
| 1109 | 0 | if object ~= entity then |
| 1110 | 0 | continue |
| 1111 | N/A | end | >
| 1112 | 0 | if not ids then |
| 1113 | 0 | ids = {} |
| 1114 | N/A | end | >
| 1115 | 0 | ids[id] = true |
| 1116 | 0 | removal_queued = true |
| 1117 | N/A | end | >
| 1118 | N/A | > |
| 1119 | 0 | if not removal_queued then |
| 1120 | 0 | continue |
| 1121 | N/A | end | >
| 1122 | N/A | > |
| 1123 | 0 | if not queue then |
| 1124 | 0 | queue = {} |
| 1125 | N/A | end | >
| 1126 | N/A | > |
| 1127 | 0 | local n = #entities |
| 1128 | 0 | table.move(entities, 1, n, count + 1, queue) |
| 1129 | 0 | count += n |
| 1130 | N/A | end | >
| 1131 | N/A | > |
| 1132 | 0 | for id in ids do |
| 1133 | 0 | for _, child in queue do |
| 1134 | 0 | world_remove(world, child, id) |
| 1135 | N/A | end | >
| 1136 | N/A | end | >
| 1137 | N/A | end | >
| 1138 | N/A | > |
| 1139 | 6 | if idr_r then |
| 1140 | 1 | local count = 0 |
| 1141 | 1 | local archetype_ids = idr_r.cache |
| 1142 | 1 | local ids = {} |
| 1143 | 1 | local queue = {} |
| 1144 | 1 | for archetype_id in archetype_ids do |
| 1145 | 2 | local idr_r_archetype = archetypes[archetype_id] |
| 1146 | 2 | local entities = idr_r_archetype.entities |
| 1147 | 2 | local tr = idr_r_archetype.records[rel] |
| 1148 | 2 | local tr_count = idr_r_archetype.counts[rel] |
| 1149 | 2 | local types = idr_r_archetype.types |
| 1150 | 2 | for i = tr, tr + tr_count - 1 do |
| 1151 | 2 | ids[types[i]] = true |
| 1152 | N/A | end | >
| 1153 | 2 | local n = #entities |
| 1154 | 2 | table.move(entities, 1, n, count + 1, queue) |
| 1155 | 2 | count += n |
| 1156 | N/A | end | >
| 1157 | N/A | > |
| 1158 | 1 | for _, e in queue do |
| 1159 | 3 | for id in ids do |
| 1160 | 3 | world_remove(world, e, id) |
| 1161 | N/A | end | >
| 1162 | N/A | end | >
| 1163 | N/A | end | >
| 1164 | N/A | end | >
| 1165 | N/A | > |
| 1166 | 1 | local function archetype_disconnect_edge(edge: ecs_graph_edge_t) |
| 1167 | 22 | local edge_next = edge.next |
| 1168 | 22 | local edge_prev = edge.prev |
| 1169 | 22 | if edge_next then |
| 1170 | 18 | edge_next.prev = edge_prev |
| 1171 | N/A | end | >
| 1172 | 22 | if edge_prev then |
| 1173 | 22 | edge_prev.next = edge_next |
| 1174 | N/A | end | >
| 1175 | N/A | end | >
| 1176 | N/A | > |
| 1177 | 1 | local function archetype_remove_edge(edges: ecs_graph_edges_t, id: i53, edge: ecs_graph_edge_t) |
| 1178 | 22 | archetype_disconnect_edge(edge) |
| 1179 | 22 | edges[id] = nil :: any |
| 1180 | N/A | end | >
| 1181 | N/A | > |
| 1182 | 1 | local function archetype_clear_edges(archetype: ecs_archetype_t) |
| 1183 | 36 | local add: ecs_graph_edges_t = archetype.add |
| 1184 | 36 | local remove: ecs_graph_edges_t = archetype.remove |
| 1185 | 36 | local node_refs = archetype.refs |
| 1186 | 36 | for id, edge in add do |
| 1187 | 9 | archetype_disconnect_edge(edge) |
| 1188 | 9 | add[id] = nil :: any |
| 1189 | N/A | end | >
| 1190 | 36 | for id, edge in remove do |
| 1191 | 18 | archetype_disconnect_edge(edge) |
| 1192 | 18 | remove[id] = nil :: any |
| 1193 | N/A | end | >
| 1194 | N/A | > |
| 1195 | 36 | local cur = node_refs.next |
| 1196 | 36 | while cur do |
| 1197 | 22 | local edge = cur :: ecs_graph_edge_t |
| 1198 | 22 | local next_edge = edge.next |
| 1199 | 22 | archetype_remove_edge(edge.from.add, edge.id, edge) |
| 1200 | 22 | cur = next_edge |
| 1201 | N/A | end | >
| 1202 | N/A | > |
| 1203 | 36 | cur = node_refs.prev |
| 1204 | 36 | while cur do |
| 1205 | 1 | local edge: ecs_graph_edge_t = cur |
| 1206 | 1 | local next_edge = edge.prev |
| 1207 | 1 | archetype_remove_edge(edge.from.remove, edge.id, edge) |
| 1208 | 1 | cur = next_edge |
| 1209 | N/A | end | >
| 1210 | N/A | > |
| 1211 | 36 | node_refs.next = nil |
| 1212 | 36 | node_refs.prev = nil |
| 1213 | N/A | end | >
| 1214 | N/A | > |
| 1215 | 1 | local function archetype_destroy(world: ecs_world_t, archetype: ecs_archetype_t) |
| 1216 | 37 | if archetype == world.ROOT_ARCHETYPE then |
| 1217 | 1 | return |
| 1218 | N/A | end | >
| 1219 | N/A | > |
| 1220 | 36 | local component_index = world.component_index |
| 1221 | 36 | archetype_clear_edges(archetype) |
| 1222 | 36 | local archetype_id = archetype.id |
| 1223 | 36 | world.archetypes[archetype_id] = nil :: any |
| 1224 | 36 | world.archetype_index[archetype.type] = nil :: any |
| 1225 | 36 | local records = archetype.records |
| 1226 | N/A | > |
| 1227 | 36 | for id in records do |
| 1228 | 113 | local observer_list = find_observers(world, EcsOnArchetypeDelete, id) |
| 1229 | 113 | if not observer_list then |
| 1230 | 0 | continue |
| 1231 | N/A | end | >
| 1232 | 2 | for _, observer in observer_list do |
| 1233 | 2 | if query_match(observer.query, archetype) then |
| 1234 | 1 | observer.callback(archetype) |
| 1235 | N/A | end | >
| 1236 | N/A | end | >
| 1237 | N/A | end | >
| 1238 | N/A | > |
| 1239 | 36 | for id in records do |
| 1240 | 113 | local idr = component_index[id] |
| 1241 | 113 | idr.cache[archetype_id] = nil :: any |
| 1242 | 113 | idr.counts[archetype_id] = nil |
| 1243 | 113 | idr.size -= 1 |
| 1244 | 113 | records[id] = nil :: any |
| 1245 | 113 | if idr.size == 0 then |
| 1246 | 0 | component_index[id] = nil :: any |
| 1247 | N/A | end | >
| 1248 | N/A | end | >
| 1249 | N/A | end | >
| 1250 | N/A | > |
| 1251 | 1 | local function world_cleanup(world: ecs_world_t) |
| 1252 | 1 | local archetypes = world.archetypes |
| 1253 | N/A | > |
| 1254 | 1 | for _, archetype in archetypes do |
| 1255 | 9 | if #archetype.entities == 0 then |
| 1256 | 4 | archetype_destroy(world, archetype) |
| 1257 | N/A | end | >
| 1258 | N/A | end | >
| 1259 | N/A | > |
| 1260 | 1 | local new_archetypes = table.create(#archetypes) :: { ecs_archetype_t } |
| 1261 | 1 | local new_archetype_map = {} |
| 1262 | N/A | > |
| 1263 | 1 | for index, archetype in archetypes do |
| 1264 | 6 | new_archetypes[index] = archetype |
| 1265 | 6 | new_archetype_map[archetype.type] = archetype |
| 1266 | N/A | end | >
| 1267 | N/A | > |
| 1268 | 1 | world.archetypes = new_archetypes |
| 1269 | 1 | world.archetype_index = new_archetype_map |
| 1270 | N/A | end | >
| 1271 | N/A | > |
| 1272 | 1 | local function world_delete(world: ecs_world_t, entity: i53) |
| 1273 | 65684 | local entity_index = world.entity_index |
| 1274 | 65684 | local record = entity_index_try_get(entity_index, entity) |
| 1275 | 65684 | if not record then |
| 1276 | 1 | return |
| 1277 | N/A | end | >
| 1278 | N/A | > |
| 1279 | 65683 | local archetype = record.archetype |
| 1280 | 65683 | local row = record.row |
| 1281 | N/A | > |
| 1282 | 65683 | if archetype then |
| 1283 | N/A | -- In the future should have a destruct mode for | >
| 1284 | N/A | -- deleting archetypes themselves. Maybe requires recycling | >
| 1285 | 134 | archetype_delete(world, archetype, row) |
| 1286 | N/A | end | >
| 1287 | N/A | > |
| 1288 | 65683 | local delete = entity |
| 1289 | 65683 | local component_index = world.component_index |
| 1290 | 65683 | local archetypes = world.archetypes |
| 1291 | 65683 | local tgt = ECS_PAIR(EcsWildcard, delete) |
| 1292 | 65683 | local rel = ECS_PAIR(delete, EcsWildcard) |
| 1293 | N/A | > |
| 1294 | 65683 | local idr_t = component_index[tgt] |
| 1295 | 65683 | local idr = component_index[delete] |
| 1296 | 65683 | local idr_r = component_index[rel] |
| 1297 | N/A | > |
| 1298 | 65683 | if idr then |
| 1299 | 8 | local flags = idr.flags |
| 1300 | 8 | if bit32.band(flags, ECS_ID_DELETE) ~= 0 then |
| 1301 | 1 | for archetype_id in idr.cache do |
| 1302 | 1 | local idr_archetype = archetypes[archetype_id] |
| 1303 | N/A | > |
| 1304 | 1 | local entities = idr_archetype.entities |
| 1305 | 1 | local n = #entities |
| 1306 | 1 | for i = n, 1, -1 do |
| 1307 | 2 | world_delete(world, entities[i]) |
| 1308 | N/A | end | >
| 1309 | N/A | > |
| 1310 | 1 | archetype_destroy(world, idr_archetype) |
| 1311 | N/A | end | >
| 1312 | 0 | else |
| 1313 | 7 | for archetype_id in idr.cache do |
| 1314 | 12 | local idr_archetype = archetypes[archetype_id] |
| 1315 | 12 | local entities = idr_archetype.entities |
| 1316 | 12 | local n = #entities |
| 1317 | 12 | for i = n, 1, -1 do |
| 1318 | 10 | world_remove(world, entities[i], delete) |
| 1319 | N/A | end | >
| 1320 | N/A | > |
| 1321 | 12 | archetype_destroy(world, idr_archetype) |
| 1322 | N/A | end | >
| 1323 | N/A | end | >
| 1324 | N/A | end | >
| 1325 | N/A | > |
| 1326 | 65683 | if idr_t then |
| 1327 | 13 | local children |
| 1328 | 13 | local ids |
| 1329 | N/A | > |
| 1330 | 13 | local count = 0 |
| 1331 | 13 | local archetype_ids = idr_t.cache |
| 1332 | 13 | for archetype_id in archetype_ids do |
| 1333 | 18 | local idr_t_archetype = archetypes[archetype_id] |
| 1334 | 18 | local idr_t_types = idr_t_archetype.types |
| 1335 | 18 | local entities = idr_t_archetype.entities |
| 1336 | 18 | local removal_queued = false |
| 1337 | N/A | > |
| 1338 | 18 | for _, id in idr_t_types do |
| 1339 | 34 | if not ECS_IS_PAIR(id) then |
| 1340 | 0 | continue |
| 1341 | N/A | end | >
| 1342 | 24 | local object = entity_index_get_alive( |
| 1343 | 24 | entity_index, ECS_PAIR_SECOND(id)) |
| 1344 | 24 | if object ~= delete then |
| 1345 | 0 | continue |
| 1346 | N/A | end | >
| 1347 | 20 | local id_record = component_index[id] |
| 1348 | 20 | local flags = id_record.flags |
| 1349 | 20 | local flags_delete_mask: number = bit32.band(flags, ECS_ID_DELETE) |
| 1350 | 20 | if flags_delete_mask ~= 0 then |
| 1351 | 8 | for i = #entities, 1, -1 do |
| 1352 | 15 | local child = entities[i] |
| 1353 | 15 | world_delete(world, child) |
| 1354 | N/A | end | >
| 1355 | 8 | break |
| 1356 | 0 | else |
| 1357 | 12 | if not ids then |
| 1358 | 6 | ids = {} |
| 1359 | N/A | end | >
| 1360 | 12 | ids[id] = true |
| 1361 | 12 | removal_queued = true |
| 1362 | N/A | end | >
| 1363 | N/A | end | >
| 1364 | N/A | > |
| 1365 | 18 | if not removal_queued then |
| 1366 | 0 | continue |
| 1367 | N/A | end | >
| 1368 | 10 | if not children then |
| 1369 | 6 | children = {} |
| 1370 | N/A | end | >
| 1371 | 10 | local n = #entities |
| 1372 | 10 | table.move(entities, 1, n, count + 1, children) |
| 1373 | 10 | count += n |
| 1374 | N/A | end | >
| 1375 | N/A | > |
| 1376 | 13 | if ids then |
| 1377 | 6 | for _, child in children do |
| 1378 | 17 | for id in ids do |
| 1379 | 19 | world_remove(world, child, id) |
| 1380 | N/A | end | >
| 1381 | N/A | end | >
| 1382 | N/A | end | >
| 1383 | N/A | > |
| 1384 | 13 | for archetype_id in archetype_ids do |
| 1385 | 20 | archetype_destroy(world, archetypes[archetype_id]) |
| 1386 | N/A | end | >
| 1387 | N/A | end | >
| 1388 | N/A | > |
| 1389 | 65683 | if idr_r then |
| 1390 | 0 | local archetype_ids = idr_r.cache |
| 1391 | 0 | local flags = idr_r.flags |
| 1392 | 0 | if bit32.band(flags, ECS_ID_DELETE) ~= 0 then |
| 1393 | 0 | for archetype_id in archetype_ids do |
| 1394 | 0 | local idr_r_archetype = archetypes[archetype_id] |
| 1395 | 0 | local entities = idr_r_archetype.entities |
| 1396 | 0 | local n = #entities |
| 1397 | 0 | for i = n, 1, -1 do |
| 1398 | 0 | world_delete(world, entities[i]) |
| 1399 | N/A | end | >
| 1400 | 0 | archetype_destroy(world, idr_r_archetype) |
| 1401 | N/A | end | >
| 1402 | 0 | else |
| 1403 | 0 | local children = {} |
| 1404 | 0 | local count = 0 |
| 1405 | 0 | local ids = {} |
| 1406 | 0 | for archetype_id in archetype_ids do |
| 1407 | 0 | local idr_r_archetype = archetypes[archetype_id] |
| 1408 | 0 | local entities = idr_r_archetype.entities |
| 1409 | 0 | local tr = idr_r_archetype.records[rel] |
| 1410 | 0 | local tr_count = idr_r_archetype.counts[rel] |
| 1411 | 0 | local types = idr_r_archetype.types |
| 1412 | 0 | for i = tr, tr_count - 1 do |
| 1413 | 0 | ids[types[tr]] = true |
| 1414 | N/A | end | >
| 1415 | 0 | local n = #entities |
| 1416 | 0 | table.move(entities, 1, n, count + 1, children) |
| 1417 | 0 | count += n |
| 1418 | N/A | end | >
| 1419 | N/A | > |
| 1420 | 0 | for _, child in children do |
| 1421 | 0 | for id in ids do |
| 1422 | 0 | world_remove(world, child, id) |
| 1423 | N/A | end | >
| 1424 | N/A | end | >
| 1425 | N/A | > |
| 1426 | 0 | for archetype_id in archetype_ids do |
| 1427 | 0 | archetype_destroy(world, archetypes[archetype_id]) |
| 1428 | N/A | end | >
| 1429 | N/A | end | >
| 1430 | N/A | end | >
| 1431 | N/A | > |
| 1432 | 65683 | local dense_array = entity_index.dense_array |
| 1433 | 65683 | local index_of_deleted_entity = record.dense |
| 1434 | 65683 | local index_of_last_alive_entity = entity_index.alive_count |
| 1435 | 65683 | entity_index.alive_count = index_of_last_alive_entity - 1 |
| 1436 | N/A | > |
| 1437 | 65683 | local last_alive_entity = dense_array[index_of_last_alive_entity] |
| 1438 | 65683 | local r_swap = entity_index_try_get_any(entity_index, last_alive_entity) :: ecs_record_t |
| 1439 | 65683 | r_swap.dense = index_of_deleted_entity |
| 1440 | 65683 | record.archetype = nil :: any |
| 1441 | 65683 | record.row = nil :: any |
| 1442 | 65683 | record.dense = index_of_last_alive_entity |
| 1443 | N/A | > |
| 1444 | 65683 | dense_array[index_of_deleted_entity] = last_alive_entity |
| 1445 | 65683 | dense_array[index_of_last_alive_entity] = ECS_GENERATION_INC(entity) |
| 1446 | N/A | end | >
| 1447 | N/A | > |
| 1448 | 1 | local function world_contains(world: ecs_world_t, entity): boolean |
| 1449 | 145 | return entity_index_is_alive(world.entity_index, entity) |
| 1450 | N/A | end | >
| 1451 | N/A | > |
| 1452 | 1 | local function NOOP() end |
| 1453 | N/A | > |
| 1454 | 0 | export type QueryInner = { |
| 1455 | 0 | compatible_archetypes: { Archetype }, |
| 1456 | 0 | ids: { i53 }, |
| 1457 | 0 | filter_with: { i53 }, |
| 1458 | 0 | filter_without: { i53 }, |
| 1459 | 0 | next: () -> (number, ...any), |
| 1460 | 0 | world: World, |
| 1461 | 0 | } |
| 1462 | N/A | > |
| 1463 | 1 | local function query_iter_init(query: ecs_query_data_t): () -> (number, ...any) |
| 1464 | 26 | local world_query_iter_next |
| 1465 | N/A | > |
| 1466 | 26 | local compatible_archetypes = query.compatible_archetypes |
| 1467 | 26 | local lastArchetype = 1 |
| 1468 | 26 | local archetype = compatible_archetypes[1] |
| 1469 | 26 | if not archetype then |
| 1470 | 4 | return NOOP :: () -> (number, ...any) |
| 1471 | N/A | end | >
| 1472 | 22 | local columns = archetype.columns |
| 1473 | 22 | local entities = archetype.entities |
| 1474 | 22 | local i = #entities |
| 1475 | 22 | local records = archetype.records |
| 1476 | N/A | > |
| 1477 | 22 | local ids = query.ids |
| 1478 | 22 | local A, B, C, D, E, F, G, H, I = unpack(ids) |
| 1479 | 22 | local a: Column, b: Column, c: Column, d: Column |
| 1480 | 22 | local e: Column, f: Column, g: Column, h: Column |
| 1481 | N/A | > |
| 1482 | 22 | if not B then |
| 1483 | 17 | a = columns[records[A]] |
| 1484 | 5 | elseif not C then |
| 1485 | 3 | a = columns[records[A]] |
| 1486 | 3 | b = columns[records[B]] |
| 1487 | 2 | elseif not D then |
| 1488 | 0 | a = columns[records[A]] |
| 1489 | 0 | b = columns[records[B]] |
| 1490 | 0 | c = columns[records[C]] |
| 1491 | 2 | elseif not E then |
| 1492 | 1 | a = columns[records[A]] |
| 1493 | 1 | b = columns[records[B]] |
| 1494 | 1 | c = columns[records[C]] |
| 1495 | 1 | d = columns[records[D]] |
| 1496 | 1 | elseif not F then |
| 1497 | 0 | a = columns[records[A]] |
| 1498 | 0 | b = columns[records[B]] |
| 1499 | 0 | c = columns[records[C]] |
| 1500 | 0 | d = columns[records[D]] |
| 1501 | 0 | e = columns[records[E]] |
| 1502 | 1 | elseif not G then |
| 1503 | 0 | a = columns[records[A]] |
| 1504 | 0 | b = columns[records[B]] |
| 1505 | 0 | c = columns[records[C]] |
| 1506 | 0 | d = columns[records[D]] |
| 1507 | 0 | e = columns[records[E]] |
| 1508 | 0 | f = columns[records[F]] |
| 1509 | 1 | elseif not H then |
| 1510 | 0 | a = columns[records[A]] |
| 1511 | 0 | b = columns[records[B]] |
| 1512 | 0 | c = columns[records[C]] |
| 1513 | 0 | d = columns[records[D]] |
| 1514 | 0 | e = columns[records[E]] |
| 1515 | 0 | f = columns[records[F]] |
| 1516 | 0 | g = columns[records[G]] |
| 1517 | 1 | elseif not I then |
| 1518 | 0 | a = columns[records[A]] |
| 1519 | 0 | b = columns[records[B]] |
| 1520 | 0 | c = columns[records[C]] |
| 1521 | 0 | d = columns[records[D]] |
| 1522 | 0 | e = columns[records[E]] |
| 1523 | 0 | f = columns[records[F]] |
| 1524 | 0 | g = columns[records[G]] |
| 1525 | 0 | h = columns[records[H]] |
| 1526 | N/A | end | >
| 1527 | N/A | > |
| 1528 | 22 | if not B then |
| 1529 | 17 | function world_query_iter_next(): any |
| 1530 | 556 | local entity = entities[i] |
| 1531 | 556 | while entity == nil do |
| 1532 | 26 | lastArchetype += 1 |
| 1533 | 26 | archetype = compatible_archetypes[lastArchetype] |
| 1534 | 26 | if not archetype then |
| 1535 | 18 | return nil |
| 1536 | N/A | end | >
| 1537 | N/A | > |
| 1538 | 8 | entities = archetype.entities |
| 1539 | 8 | i = #entities |
| 1540 | 8 | if i == 0 then |
| 1541 | 0 | continue |
| 1542 | N/A | end | >
| 1543 | 8 | entity = entities[i] |
| 1544 | 8 | columns = archetype.columns |
| 1545 | 8 | records = archetype.records |
| 1546 | 8 | a = columns[records[A]] |
| 1547 | N/A | end | >
| 1548 | N/A | > |
| 1549 | 538 | local row = i |
| 1550 | 538 | i -= 1 |
| 1551 | N/A | > |
| 1552 | 538 | return entity, a[row] |
| 1553 | N/A | end | >
| 1554 | 5 | elseif not C then |
| 1555 | 3 | function world_query_iter_next(): any |
| 1556 | 7 | local entity = entities[i] |
| 1557 | 7 | while entity == nil do |
| 1558 | 3 | lastArchetype += 1 |
| 1559 | 3 | archetype = compatible_archetypes[lastArchetype] |
| 1560 | 3 | if not archetype then |
| 1561 | 3 | return nil |
| 1562 | N/A | end | >
| 1563 | N/A | > |
| 1564 | 0 | entities = archetype.entities |
| 1565 | 0 | i = #entities |
| 1566 | 0 | if i == 0 then |
| 1567 | 0 | continue |
| 1568 | N/A | end | >
| 1569 | 0 | entity = entities[i] |
| 1570 | 0 | columns = archetype.columns |
| 1571 | 0 | records = archetype.records |
| 1572 | 0 | a = columns[records[A]] |
| 1573 | 0 | b = columns[records[B]] |
| 1574 | N/A | end | >
| 1575 | N/A | > |
| 1576 | 4 | local row = i |
| 1577 | 4 | i -= 1 |
| 1578 | N/A | > |
| 1579 | 4 | return entity, a[row], b[row] |
| 1580 | N/A | end | >
| 1581 | 2 | elseif not D then |
| 1582 | 0 | function world_query_iter_next(): any |
| 1583 | 0 | local entity = entities[i] |
| 1584 | 0 | while entity == nil do |
| 1585 | 0 | lastArchetype += 1 |
| 1586 | 0 | archetype = compatible_archetypes[lastArchetype] |
| 1587 | 0 | if not archetype then |
| 1588 | 0 | return nil |
| 1589 | N/A | end | >
| 1590 | N/A | > |
| 1591 | 0 | entities = archetype.entities |
| 1592 | 0 | i = #entities |
| 1593 | 0 | if i == 0 then |
| 1594 | 0 | continue |
| 1595 | N/A | end | >
| 1596 | 0 | entity = entities[i] |
| 1597 | 0 | columns = archetype.columns |
| 1598 | 0 | records = archetype.records |
| 1599 | 0 | a = columns[records[A]] |
| 1600 | 0 | b = columns[records[B]] |
| 1601 | 0 | c = columns[records[C]] |
| 1602 | N/A | end | >
| 1603 | N/A | > |
| 1604 | 0 | local row = i |
| 1605 | 0 | i -= 1 |
| 1606 | N/A | > |
| 1607 | 0 | return entity, a[row], b[row], c[row] |
| 1608 | N/A | end | >
| 1609 | 2 | elseif not E then |
| 1610 | 1 | function world_query_iter_next(): any |
| 1611 | 2 | local entity = entities[i] |
| 1612 | 2 | while entity == nil do |
| 1613 | 1 | lastArchetype += 1 |
| 1614 | 1 | archetype = compatible_archetypes[lastArchetype] |
| 1615 | 1 | if not archetype then |
| 1616 | 1 | return nil |
| 1617 | N/A | end | >
| 1618 | N/A | > |
| 1619 | 0 | entities = archetype.entities |
| 1620 | 0 | i = #entities |
| 1621 | 0 | if i == 0 then |
| 1622 | 0 | continue |
| 1623 | N/A | end | >
| 1624 | 0 | entity = entities[i] |
| 1625 | 0 | columns = archetype.columns |
| 1626 | 0 | records = archetype.records |
| 1627 | 0 | a = columns[records[A]] |
| 1628 | 0 | b = columns[records[B]] |
| 1629 | 0 | c = columns[records[C]] |
| 1630 | 0 | d = columns[records[D]] |
| 1631 | N/A | end | >
| 1632 | N/A | > |
| 1633 | 1 | local row = i |
| 1634 | 1 | i -= 1 |
| 1635 | N/A | > |
| 1636 | 1 | return entity, a[row], b[row], c[row], d[row] |
| 1637 | N/A | end | >
| 1638 | 1 | elseif not F then |
| 1639 | 0 | function world_query_iter_next(): any |
| 1640 | 0 | local entity = entities[i] |
| 1641 | 0 | while entity == nil do |
| 1642 | 0 | lastArchetype += 1 |
| 1643 | 0 | archetype = compatible_archetypes[lastArchetype] |
| 1644 | 0 | if not archetype then |
| 1645 | 0 | return nil |
| 1646 | N/A | end | >
| 1647 | N/A | > |
| 1648 | 0 | entities = archetype.entities |
| 1649 | 0 | i = #entities |
| 1650 | 0 | if i == 0 then |
| 1651 | 0 | continue |
| 1652 | N/A | end | >
| 1653 | 0 | entity = entities[i] |
| 1654 | 0 | columns = archetype.columns |
| 1655 | 0 | records = archetype.records |
| 1656 | 0 | a = columns[records[A]] |
| 1657 | 0 | b = columns[records[B]] |
| 1658 | 0 | c = columns[records[C]] |
| 1659 | 0 | d = columns[records[D]] |
| 1660 | 0 | e = columns[records[E]] |
| 1661 | N/A | end | >
| 1662 | N/A | > |
| 1663 | 0 | local row = i |
| 1664 | 0 | i -= 1 |
| 1665 | N/A | > |
| 1666 | 0 | return entity, a[row], b[row], c[row], d[row], e[row] |
| 1667 | N/A | end | >
| 1668 | 1 | elseif not G then |
| 1669 | 0 | function world_query_iter_next(): any |
| 1670 | 0 | local entity = entities[i] |
| 1671 | 0 | while entity == nil do |
| 1672 | 0 | lastArchetype += 1 |
| 1673 | 0 | archetype = compatible_archetypes[lastArchetype] |
| 1674 | 0 | if not archetype then |
| 1675 | 0 | return nil |
| 1676 | N/A | end | >
| 1677 | N/A | > |
| 1678 | 0 | entities = archetype.entities |
| 1679 | 0 | i = #entities |
| 1680 | 0 | if i == 0 then |
| 1681 | 0 | continue |
| 1682 | N/A | end | >
| 1683 | 0 | entity = entities[i] |
| 1684 | 0 | columns = archetype.columns |
| 1685 | 0 | records = archetype.records |
| 1686 | 0 | a = columns[records[A]] |
| 1687 | 0 | b = columns[records[B]] |
| 1688 | 0 | c = columns[records[C]] |
| 1689 | 0 | d = columns[records[D]] |
| 1690 | 0 | e = columns[records[E]] |
| 1691 | 0 | f = columns[records[F]] |
| 1692 | N/A | end | >
| 1693 | N/A | > |
| 1694 | 0 | local row = i |
| 1695 | 0 | i -= 1 |
| 1696 | N/A | > |
| 1697 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row] |
| 1698 | N/A | end | >
| 1699 | 1 | elseif not H then |
| 1700 | 0 | function world_query_iter_next(): any |
| 1701 | 0 | local entity = entities[i] |
| 1702 | 0 | while entity == nil do |
| 1703 | 0 | lastArchetype += 1 |
| 1704 | 0 | archetype = compatible_archetypes[lastArchetype] |
| 1705 | 0 | if not archetype then |
| 1706 | 0 | return nil |
| 1707 | N/A | end | >
| 1708 | N/A | > |
| 1709 | 0 | entities = archetype.entities |
| 1710 | 0 | i = #entities |
| 1711 | 0 | if i == 0 then |
| 1712 | 0 | continue |
| 1713 | N/A | end | >
| 1714 | 0 | entity = entities[i] |
| 1715 | 0 | columns = archetype.columns |
| 1716 | 0 | records = archetype.records |
| 1717 | 0 | a = columns[records[A]] |
| 1718 | 0 | b = columns[records[B]] |
| 1719 | 0 | c = columns[records[C]] |
| 1720 | 0 | d = columns[records[D]] |
| 1721 | 0 | e = columns[records[E]] |
| 1722 | 0 | f = columns[records[F]] |
| 1723 | 0 | g = columns[records[G]] |
| 1724 | N/A | end | >
| 1725 | N/A | > |
| 1726 | 0 | local row = i |
| 1727 | 0 | i -= 1 |
| 1728 | N/A | > |
| 1729 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row] |
| 1730 | N/A | end | >
| 1731 | 1 | elseif not I then |
| 1732 | 0 | function world_query_iter_next(): any |
| 1733 | 0 | local entity = entities[i] |
| 1734 | 0 | while entity == nil do |
| 1735 | 0 | lastArchetype += 1 |
| 1736 | 0 | archetype = compatible_archetypes[lastArchetype] |
| 1737 | 0 | if not archetype then |
| 1738 | 0 | return nil |
| 1739 | N/A | end | >
| 1740 | N/A | > |
| 1741 | 0 | entities = archetype.entities |
| 1742 | 0 | i = #entities |
| 1743 | 0 | if i == 0 then |
| 1744 | 0 | continue |
| 1745 | N/A | end | >
| 1746 | 0 | entity = entities[i] |
| 1747 | 0 | columns = archetype.columns |
| 1748 | 0 | records = archetype.records |
| 1749 | 0 | a = columns[records[A]] |
| 1750 | 0 | b = columns[records[B]] |
| 1751 | 0 | c = columns[records[C]] |
| 1752 | 0 | d = columns[records[D]] |
| 1753 | 0 | e = columns[records[E]] |
| 1754 | 0 | f = columns[records[F]] |
| 1755 | 0 | g = columns[records[G]] |
| 1756 | 0 | h = columns[records[H]] |
| 1757 | N/A | end | >
| 1758 | N/A | > |
| 1759 | 0 | local row = i |
| 1760 | 0 | i -= 1 |
| 1761 | N/A | > |
| 1762 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row], h[row] |
| 1763 | N/A | end | >
| 1764 | 0 | else |
| 1765 | 1 | local output = {} |
| 1766 | 1 | function world_query_iter_next(): any |
| 1767 | 2 | local entity = entities[i] |
| 1768 | 2 | while entity == nil do |
| 1769 | 1 | lastArchetype += 1 |
| 1770 | 1 | archetype = compatible_archetypes[lastArchetype] |
| 1771 | 1 | if not archetype then |
| 1772 | 1 | return nil |
| 1773 | N/A | end | >
| 1774 | N/A | > |
| 1775 | 0 | entities = archetype.entities |
| 1776 | 0 | i = #entities |
| 1777 | 0 | if i == 0 then |
| 1778 | 0 | continue |
| 1779 | N/A | end | >
| 1780 | 0 | entity = entities[i] |
| 1781 | 0 | columns = archetype.columns |
| 1782 | 0 | records = archetype.records |
| 1783 | N/A | end | >
| 1784 | N/A | > |
| 1785 | 1 | local row = i |
| 1786 | 1 | i -= 1 |
| 1787 | N/A | > |
| 1788 | 1 | for j, id in ids do |
| 1789 | 9 | output[j] = columns[records[id]][row] |
| 1790 | N/A | end | >
| 1791 | N/A | > |
| 1792 | 1 | return entity, unpack(output) |
| 1793 | N/A | end | >
| 1794 | N/A | end | >
| 1795 | N/A | > |
| 1796 | 22 | query.next = world_query_iter_next |
| 1797 | 22 | return world_query_iter_next |
| 1798 | N/A | end | >
| 1799 | N/A | > |
| 1800 | 1 | local function query_iter(query): () -> (number, ...any) |
| 1801 | 20 | local query_next = query.next |
| 1802 | 20 | if not query_next then |
| 1803 | 19 | query_next = query_iter_init(query) |
| 1804 | N/A | end | >
| 1805 | 20 | return query_next |
| 1806 | N/A | end | >
| 1807 | N/A | > |
| 1808 | 1 | local function query_without(query: ecs_query_data_t, ...: i53) |
| 1809 | 6 | local without = { ... } |
| 1810 | 6 | query.filter_without = without |
| 1811 | 6 | local compatible_archetypes = query.compatible_archetypes |
| 1812 | 6 | for i = #compatible_archetypes, 1, -1 do |
| 1813 | 3 | local archetype = compatible_archetypes[i] |
| 1814 | 3 | local records = archetype.records |
| 1815 | 3 | local matches = true |
| 1816 | N/A | > |
| 1817 | 3 | for _, id in without do |
| 1818 | 3 | if records[id] then |
| 1819 | 2 | matches = false |
| 1820 | 2 | break |
| 1821 | N/A | end | >
| 1822 | N/A | end | >
| 1823 | N/A | > |
| 1824 | 3 | if matches then |
| 1825 | 0 | continue |
| 1826 | N/A | end | >
| 1827 | N/A | > |
| 1828 | 2 | local last = #compatible_archetypes |
| 1829 | 2 | if last ~= i then |
| 1830 | 0 | compatible_archetypes[i] = compatible_archetypes[last] |
| 1831 | N/A | end | >
| 1832 | 2 | compatible_archetypes[last] = nil :: any |
| 1833 | N/A | end | >
| 1834 | N/A | > |
| 1835 | 6 | return query :: any |
| 1836 | N/A | end | >
| 1837 | N/A | > |
| 1838 | 1 | local function query_with(query: ecs_query_data_t, ...: i53) |
| 1839 | 1 | local compatible_archetypes = query.compatible_archetypes |
| 1840 | 1 | local with = { ... } |
| 1841 | 1 | query.filter_with = with |
| 1842 | N/A | > |
| 1843 | 1 | for i = #compatible_archetypes, 1, -1 do |
| 1844 | 0 | local archetype = compatible_archetypes[i] |
| 1845 | 0 | local records = archetype.records |
| 1846 | 0 | local matches = true |
| 1847 | N/A | > |
| 1848 | 0 | for _, id in with do |
| 1849 | 0 | if not records[id] then |
| 1850 | 0 | matches = false |
| 1851 | 0 | break |
| 1852 | N/A | end | >
| 1853 | N/A | end | >
| 1854 | N/A | > |
| 1855 | 0 | if matches then |
| 1856 | 0 | continue |
| 1857 | N/A | end | >
| 1858 | N/A | > |
| 1859 | 0 | local last = #compatible_archetypes |
| 1860 | 0 | if last ~= i then |
| 1861 | 0 | compatible_archetypes[i] = compatible_archetypes[last] |
| 1862 | N/A | end | >
| 1863 | 0 | compatible_archetypes[last] = nil :: any |
| 1864 | N/A | end | >
| 1865 | N/A | > |
| 1866 | 1 | return query :: any |
| 1867 | N/A | end | >
| 1868 | N/A | > |
| 1869 | N/A | -- Meant for directly iterating over archetypes to minimize | >
| 1870 | N/A | -- function call overhead. Should not be used unless iterating over | >
| 1871 | N/A | -- hundreds of thousands of entities in bulk. | >
| 1872 | 1 | local function query_archetypes(query) |
| 1873 | 5 | return query.compatible_archetypes |
| 1874 | N/A | end | >
| 1875 | N/A | > |
| 1876 | 1 | local function query_cached(query: ecs_query_data_t) |
| 1877 | 6 | local with = query.filter_with |
| 1878 | 6 | local ids = query.ids |
| 1879 | 6 | if with then |
| 1880 | 1 | table.move(ids, 1, #ids, #with + 1, with) |
| 1881 | 0 | else |
| 1882 | 5 | query.filter_with = ids |
| 1883 | N/A | end | >
| 1884 | N/A | > |
| 1885 | 6 | local compatible_archetypes = query.compatible_archetypes |
| 1886 | 6 | local lastArchetype = 1 |
| 1887 | N/A | > |
| 1888 | 6 | local A, B, C, D, E, F, G, H, I = unpack(ids) |
| 1889 | 6 | local a: Column, b: Column, c: Column, d: Column |
| 1890 | 6 | local e: Column, f: Column, g: Column, h: Column |
| 1891 | N/A | > |
| 1892 | 6 | local world_query_iter_next |
| 1893 | 6 | local columns: { Column } |
| 1894 | 6 | local entities: { number } |
| 1895 | 6 | local i: number |
| 1896 | 6 | local archetype: ecs_archetype_t |
| 1897 | 6 | local records: { number } |
| 1898 | 6 | local archetypes = query.compatible_archetypes |
| 1899 | N/A | > |
| 1900 | 6 | local world = query.world :: { observable: ecs_observable_t } |
| 1901 | N/A | -- Only need one observer for EcsArchetypeCreate and EcsArchetypeDelete respectively | >
| 1902 | N/A | -- because the event will be emitted for all components of that Archetype. | >
| 1903 | 6 | local observable = world.observable :: ecs_observable_t |
| 1904 | 6 | local on_create_action = observable[EcsOnArchetypeCreate] |
| 1905 | 6 | if not on_create_action then |
| 1906 | 6 | on_create_action = {} |
| 1907 | 6 | observable[EcsOnArchetypeCreate] = on_create_action |
| 1908 | N/A | end | >
| 1909 | 6 | local query_cache_on_create = on_create_action[A] |
| 1910 | 6 | if not query_cache_on_create then |
| 1911 | 6 | query_cache_on_create = {} |
| 1912 | 6 | on_create_action[A] = query_cache_on_create |
| 1913 | N/A | end | >
| 1914 | N/A | > |
| 1915 | 6 | local on_delete_action = observable[EcsOnArchetypeDelete] |
| 1916 | 6 | if not on_delete_action then |
| 1917 | 6 | on_delete_action = {} |
| 1918 | 6 | observable[EcsOnArchetypeDelete] = on_delete_action |
| 1919 | N/A | end | >
| 1920 | 6 | local query_cache_on_delete = on_delete_action[A] |
| 1921 | 6 | if not query_cache_on_delete then |
| 1922 | 6 | query_cache_on_delete = {} |
| 1923 | 6 | on_delete_action[A] = query_cache_on_delete |
| 1924 | N/A | end | >
| 1925 | N/A | > |
| 1926 | 6 | local function on_create_callback(archetype) |
| 1927 | 4 | table.insert(archetypes, archetype) |
| 1928 | N/A | end | >
| 1929 | N/A | > |
| 1930 | 6 | local function on_delete_callback(archetype) |
| 1931 | 1 | local i = table.find(archetypes, archetype) :: number |
| 1932 | 1 | local n = #archetypes |
| 1933 | 1 | archetypes[i] = archetypes[n] |
| 1934 | 1 | archetypes[n] = nil |
| 1935 | N/A | end | >
| 1936 | N/A | > |
| 1937 | 6 | local observer_for_create = { query = query, callback = on_create_callback } |
| 1938 | 6 | local observer_for_delete = { query = query, callback = on_delete_callback } |
| 1939 | N/A | > |
| 1940 | 6 | table.insert(query_cache_on_create, observer_for_create) |
| 1941 | 6 | table.insert(query_cache_on_delete, observer_for_delete) |
| 1942 | N/A | > |
| 1943 | 6 | local function cached_query_iter() |
| 1944 | 11 | lastArchetype = 1 |
| 1945 | 11 | archetype = compatible_archetypes[lastArchetype] |
| 1946 | 11 | if not archetype then |
| 1947 | 1 | return NOOP |
| 1948 | N/A | end | >
| 1949 | 10 | entities = archetype.entities |
| 1950 | 10 | i = #entities |
| 1951 | 10 | records = archetype.records |
| 1952 | 10 | columns = archetype.columns |
| 1953 | 10 | if not B then |
| 1954 | 6 | a = columns[records[A]] |
| 1955 | 4 | elseif not C then |
| 1956 | 4 | a = columns[records[A]] |
| 1957 | 4 | b = columns[records[B]] |
| 1958 | 0 | elseif not D then |
| 1959 | 0 | a = columns[records[A]] |
| 1960 | 0 | b = columns[records[B]] |
| 1961 | 0 | c = columns[records[C]] |
| 1962 | 0 | elseif not E then |
| 1963 | 0 | a = columns[records[A]] |
| 1964 | 0 | b = columns[records[B]] |
| 1965 | 0 | c = columns[records[C]] |
| 1966 | 0 | d = columns[records[D]] |
| 1967 | 0 | elseif not F then |
| 1968 | 0 | a = columns[records[A]] |
| 1969 | 0 | b = columns[records[B]] |
| 1970 | 0 | c = columns[records[C]] |
| 1971 | 0 | d = columns[records[D]] |
| 1972 | 0 | e = columns[records[E]] |
| 1973 | 0 | elseif not G then |
| 1974 | 0 | a = columns[records[A]] |
| 1975 | 0 | b = columns[records[B]] |
| 1976 | 0 | c = columns[records[C]] |
| 1977 | 0 | d = columns[records[D]] |
| 1978 | 0 | e = columns[records[E]] |
| 1979 | 0 | f = columns[records[F]] |
| 1980 | 0 | elseif not H then |
| 1981 | 0 | a = columns[records[A]] |
| 1982 | 0 | b = columns[records[B]] |
| 1983 | 0 | c = columns[records[C]] |
| 1984 | 0 | d = columns[records[D]] |
| 1985 | 0 | e = columns[records[E]] |
| 1986 | 0 | f = columns[records[F]] |
| 1987 | 0 | g = columns[records[G]] |
| 1988 | 0 | elseif not I then |
| 1989 | 0 | a = columns[records[A]] |
| 1990 | 0 | b = columns[records[B]] |
| 1991 | 0 | c = columns[records[C]] |
| 1992 | 0 | d = columns[records[D]] |
| 1993 | 0 | e = columns[records[E]] |
| 1994 | 0 | f = columns[records[F]] |
| 1995 | 0 | g = columns[records[G]] |
| 1996 | 0 | h = columns[records[H]] |
| 1997 | N/A | end | >
| 1998 | N/A | > |
| 1999 | 10 | return world_query_iter_next |
| 2000 | N/A | end | >
| 2001 | N/A | > |
| 2002 | 6 | if not B then |
| 2003 | 5 | function world_query_iter_next(): any |
| 2004 | 11 | local entity = entities[i] |
| 2005 | 11 | while entity == nil do |
| 2006 | 6 | lastArchetype += 1 |
| 2007 | 6 | archetype = compatible_archetypes[lastArchetype] |
| 2008 | 6 | if not archetype then |
| 2009 | 6 | return nil |
| 2010 | N/A | end | >
| 2011 | N/A | > |
| 2012 | 0 | entities = archetype.entities |
| 2013 | 0 | i = #entities |
| 2014 | 0 | if i == 0 then |
| 2015 | 0 | continue |
| 2016 | N/A | end | >
| 2017 | 0 | entity = entities[i] |
| 2018 | 0 | columns = archetype.columns |
| 2019 | 0 | records = archetype.records |
| 2020 | 0 | a = columns[records[A]] |
| 2021 | N/A | end | >
| 2022 | N/A | > |
| 2023 | 5 | local row = i |
| 2024 | 5 | i -= 1 |
| 2025 | N/A | > |
| 2026 | 5 | return entity, a[row] |
| 2027 | N/A | end | >
| 2028 | 1 | elseif not C then |
| 2029 | 1 | function world_query_iter_next(): any |
| 2030 | 8 | local entity = entities[i] |
| 2031 | 8 | while entity == nil do |
| 2032 | 4 | lastArchetype += 1 |
| 2033 | 4 | archetype = compatible_archetypes[lastArchetype] |
| 2034 | 4 | if not archetype then |
| 2035 | 4 | return nil |
| 2036 | N/A | end | >
| 2037 | N/A | > |
| 2038 | 0 | entities = archetype.entities |
| 2039 | 0 | i = #entities |
| 2040 | 0 | if i == 0 then |
| 2041 | 0 | continue |
| 2042 | N/A | end | >
| 2043 | 0 | entity = entities[i] |
| 2044 | 0 | columns = archetype.columns |
| 2045 | 0 | records = archetype.records |
| 2046 | 0 | a = columns[records[A]] |
| 2047 | 0 | b = columns[records[B]] |
| 2048 | N/A | end | >
| 2049 | N/A | > |
| 2050 | 4 | local row = i |
| 2051 | 4 | i -= 1 |
| 2052 | N/A | > |
| 2053 | 4 | return entity, a[row], b[row] |
| 2054 | N/A | end | >
| 2055 | 0 | elseif not D then |
| 2056 | 0 | function world_query_iter_next(): any |
| 2057 | 0 | local entity = entities[i] |
| 2058 | 0 | while entity == nil do |
| 2059 | 0 | lastArchetype += 1 |
| 2060 | 0 | archetype = compatible_archetypes[lastArchetype] |
| 2061 | 0 | if not archetype then |
| 2062 | 0 | return nil |
| 2063 | N/A | end | >
| 2064 | N/A | > |
| 2065 | 0 | entities = archetype.entities |
| 2066 | 0 | i = #entities |
| 2067 | 0 | if i == 0 then |
| 2068 | 0 | continue |
| 2069 | N/A | end | >
| 2070 | 0 | entity = entities[i] |
| 2071 | 0 | columns = archetype.columns |
| 2072 | 0 | records = archetype.records |
| 2073 | 0 | a = columns[records[A]] |
| 2074 | 0 | b = columns[records[B]] |
| 2075 | 0 | c = columns[records[C]] |
| 2076 | N/A | end | >
| 2077 | N/A | > |
| 2078 | 0 | local row = i |
| 2079 | 0 | i -= 1 |
| 2080 | N/A | > |
| 2081 | 0 | return entity, a[row], b[row], c[row] |
| 2082 | N/A | end | >
| 2083 | 0 | elseif not E then |
| 2084 | 0 | function world_query_iter_next(): any |
| 2085 | 0 | local entity = entities[i] |
| 2086 | 0 | while entity == nil do |
| 2087 | 0 | lastArchetype += 1 |
| 2088 | 0 | archetype = compatible_archetypes[lastArchetype] |
| 2089 | 0 | if not archetype then |
| 2090 | 0 | return nil |
| 2091 | N/A | end | >
| 2092 | N/A | > |
| 2093 | 0 | entities = archetype.entities |
| 2094 | 0 | i = #entities |
| 2095 | 0 | if i == 0 then |
| 2096 | 0 | continue |
| 2097 | N/A | end | >
| 2098 | 0 | entity = entities[i] |
| 2099 | 0 | columns = archetype.columns |
| 2100 | 0 | records = archetype.records |
| 2101 | 0 | a = columns[records[A]] |
| 2102 | 0 | b = columns[records[B]] |
| 2103 | 0 | c = columns[records[C]] |
| 2104 | 0 | d = columns[records[D]] |
| 2105 | N/A | end | >
| 2106 | N/A | > |
| 2107 | 0 | local row = i |
| 2108 | 0 | i -= 1 |
| 2109 | N/A | > |
| 2110 | 0 | return entity, a[row], b[row], c[row], d[row] |
| 2111 | N/A | end | >
| 2112 | 0 | elseif not F then |
| 2113 | 0 | function world_query_iter_next(): any |
| 2114 | 0 | local entity = entities[i] |
| 2115 | 0 | while entity == nil do |
| 2116 | 0 | lastArchetype += 1 |
| 2117 | 0 | archetype = compatible_archetypes[lastArchetype] |
| 2118 | 0 | if not archetype then |
| 2119 | 0 | return nil |
| 2120 | N/A | end | >
| 2121 | N/A | > |
| 2122 | 0 | entities = archetype.entities |
| 2123 | 0 | i = #entities |
| 2124 | 0 | if i == 0 then |
| 2125 | 0 | continue |
| 2126 | N/A | end | >
| 2127 | 0 | entity = entities[i] |
| 2128 | 0 | columns = archetype.columns |
| 2129 | 0 | records = archetype.records |
| 2130 | 0 | a = columns[records[A]] |
| 2131 | 0 | b = columns[records[B]] |
| 2132 | 0 | c = columns[records[C]] |
| 2133 | 0 | d = columns[records[D]] |
| 2134 | 0 | e = columns[records[E]] |
| 2135 | N/A | end | >
| 2136 | N/A | > |
| 2137 | 0 | local row = i |
| 2138 | 0 | i -= 1 |
| 2139 | N/A | > |
| 2140 | 0 | return entity, a[row], b[row], c[row], d[row], e[row] |
| 2141 | N/A | end | >
| 2142 | 0 | elseif not G then |
| 2143 | 0 | function world_query_iter_next(): any |
| 2144 | 0 | local entity = entities[i] |
| 2145 | 0 | while entity == nil do |
| 2146 | 0 | lastArchetype += 1 |
| 2147 | 0 | archetype = compatible_archetypes[lastArchetype] |
| 2148 | 0 | if not archetype then |
| 2149 | 0 | return nil |
| 2150 | N/A | end | >
| 2151 | N/A | > |
| 2152 | 0 | entities = archetype.entities |
| 2153 | 0 | i = #entities |
| 2154 | 0 | if i == 0 then |
| 2155 | 0 | continue |
| 2156 | N/A | end | >
| 2157 | 0 | entity = entities[i] |
| 2158 | 0 | columns = archetype.columns |
| 2159 | 0 | records = archetype.records |
| 2160 | 0 | a = columns[records[A]] |
| 2161 | 0 | b = columns[records[B]] |
| 2162 | 0 | c = columns[records[C]] |
| 2163 | 0 | d = columns[records[D]] |
| 2164 | 0 | e = columns[records[E]] |
| 2165 | 0 | f = columns[records[F]] |
| 2166 | N/A | end | >
| 2167 | N/A | > |
| 2168 | 0 | local row = i |
| 2169 | 0 | i -= 1 |
| 2170 | N/A | > |
| 2171 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row] |
| 2172 | N/A | end | >
| 2173 | 0 | elseif not H then |
| 2174 | 0 | function world_query_iter_next(): any |
| 2175 | 0 | local entity = entities[i] |
| 2176 | 0 | while entity == nil do |
| 2177 | 0 | lastArchetype += 1 |
| 2178 | 0 | archetype = compatible_archetypes[lastArchetype] |
| 2179 | 0 | if not archetype then |
| 2180 | 0 | return nil |
| 2181 | N/A | end | >
| 2182 | N/A | > |
| 2183 | 0 | entities = archetype.entities |
| 2184 | 0 | i = #entities |
| 2185 | 0 | if i == 0 then |
| 2186 | 0 | continue |
| 2187 | N/A | end | >
| 2188 | 0 | entity = entities[i] |
| 2189 | 0 | columns = archetype.columns |
| 2190 | 0 | records = archetype.records |
| 2191 | 0 | a = columns[records[A]] |
| 2192 | 0 | b = columns[records[B]] |
| 2193 | 0 | c = columns[records[C]] |
| 2194 | 0 | d = columns[records[D]] |
| 2195 | 0 | e = columns[records[E]] |
| 2196 | 0 | f = columns[records[F]] |
| 2197 | 0 | g = columns[records[G]] |
| 2198 | N/A | end | >
| 2199 | N/A | > |
| 2200 | 0 | local row = i |
| 2201 | 0 | i -= 1 |
| 2202 | N/A | > |
| 2203 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row] |
| 2204 | N/A | end | >
| 2205 | 0 | elseif not I then |
| 2206 | 0 | function world_query_iter_next(): any |
| 2207 | 0 | local entity = entities[i] |
| 2208 | 0 | while entity == nil do |
| 2209 | 0 | lastArchetype += 1 |
| 2210 | 0 | archetype = compatible_archetypes[lastArchetype] |
| 2211 | 0 | if not archetype then |
| 2212 | 0 | return nil |
| 2213 | N/A | end | >
| 2214 | N/A | > |
| 2215 | 0 | entities = archetype.entities |
| 2216 | 0 | i = #entities |
| 2217 | 0 | if i == 0 then |
| 2218 | 0 | continue |
| 2219 | N/A | end | >
| 2220 | 0 | entity = entities[i] |
| 2221 | 0 | columns = archetype.columns |
| 2222 | 0 | records = archetype.records |
| 2223 | 0 | a = columns[records[A]] |
| 2224 | 0 | b = columns[records[B]] |
| 2225 | 0 | c = columns[records[C]] |
| 2226 | 0 | d = columns[records[D]] |
| 2227 | 0 | e = columns[records[E]] |
| 2228 | 0 | f = columns[records[F]] |
| 2229 | 0 | g = columns[records[G]] |
| 2230 | 0 | h = columns[records[H]] |
| 2231 | N/A | end | >
| 2232 | N/A | > |
| 2233 | 0 | local row = i |
| 2234 | 0 | i -= 1 |
| 2235 | N/A | > |
| 2236 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row], h[row] |
| 2237 | N/A | end | >
| 2238 | 0 | else |
| 2239 | 0 | local queryOutput = {} |
| 2240 | 0 | function world_query_iter_next(): any |
| 2241 | 0 | local entity = entities[i] |
| 2242 | 0 | while entity == nil do |
| 2243 | 0 | lastArchetype += 1 |
| 2244 | 0 | archetype = compatible_archetypes[lastArchetype] |
| 2245 | 0 | if not archetype then |
| 2246 | 0 | return nil |
| 2247 | N/A | end | >
| 2248 | N/A | > |
| 2249 | 0 | entities = archetype.entities |
| 2250 | 0 | i = #entities |
| 2251 | 0 | if i == 0 then |
| 2252 | 0 | continue |
| 2253 | N/A | end | >
| 2254 | 0 | entity = entities[i] |
| 2255 | 0 | columns = archetype.columns |
| 2256 | 0 | records = archetype.records |
| 2257 | N/A | end | >
| 2258 | N/A | > |
| 2259 | 0 | local row = i |
| 2260 | 0 | i -= 1 |
| 2261 | N/A | > |
| 2262 | 0 | if not F then |
| 2263 | 0 | return entity, a[row], b[row], c[row], d[row], e[row] |
| 2264 | 0 | elseif not G then |
| 2265 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row] |
| 2266 | 0 | elseif not H then |
| 2267 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row] |
| 2268 | 0 | elseif not I then |
| 2269 | 0 | return entity, a[row], b[row], c[row], d[row], e[row], f[row], g[row], h[row] |
| 2270 | N/A | end | >
| 2271 | N/A | > |
| 2272 | 0 | for j, id in ids do |
| 2273 | 0 | queryOutput[j] = columns[records[id]][row] |
| 2274 | N/A | end | >
| 2275 | N/A | > |
| 2276 | 0 | return entity, unpack(queryOutput) |
| 2277 | N/A | end | >
| 2278 | N/A | end | >
| 2279 | N/A | > |
| 2280 | 6 | local cached_query = query :: any |
| 2281 | 6 | cached_query.archetypes = query_archetypes |
| 2282 | 6 | cached_query.__iter = cached_query_iter |
| 2283 | 6 | cached_query.iter = cached_query_iter |
| 2284 | 6 | setmetatable(cached_query, cached_query) |
| 2285 | 6 | return cached_query |
| 2286 | N/A | end | >
| 2287 | N/A | > |
| 2288 | 1 | local Query = {} |
| 2289 | 1 | Query.__index = Query |
| 2290 | 1 | Query.__iter = query_iter |
| 2291 | 1 | Query.iter = query_iter_init |
| 2292 | 1 | Query.without = query_without |
| 2293 | 1 | Query.with = query_with |
| 2294 | 1 | Query.archetypes = query_archetypes |
| 2295 | 1 | Query.cached = query_cached |
| 2296 | N/A | > |
| 2297 | 1 | local function world_query(world: ecs_world_t, ...) |
| 2298 | 33 | local compatible_archetypes = {} |
| 2299 | 33 | local length = 0 |
| 2300 | N/A | > |
| 2301 | 33 | local ids = { ... } |
| 2302 | N/A | > |
| 2303 | 33 | local archetypes = world.archetypes |
| 2304 | N/A | > |
| 2305 | 33 | local idr: ecs_id_record_t? |
| 2306 | 33 | local component_index = world.component_index |
| 2307 | N/A | > |
| 2308 | 33 | local q = setmetatable({ |
| 2309 | 33 | ids = ids, |
| 2310 | 33 | compatible_archetypes = compatible_archetypes, |
| 2311 | 33 | world = world, |
| 2312 | 33 | }, Query) |
| 2313 | N/A | > |
| 2314 | 33 | for _, id in ids do |
| 2315 | 47 | local map = component_index[id] |
| 2316 | 47 | if not map then |
| 2317 | 7 | return q |
| 2318 | N/A | end | >
| 2319 | N/A | > |
| 2320 | 40 | if idr == nil or map.size < idr.size then |
| 2321 | 27 | idr = map |
| 2322 | N/A | end | >
| 2323 | N/A | end | >
| 2324 | N/A | > |
| 2325 | 26 | if not idr then |
| 2326 | 0 | return q |
| 2327 | N/A | end | >
| 2328 | N/A | > |
| 2329 | 26 | for archetype_id in idr.cache do |
| 2330 | 48 | local compatibleArchetype = archetypes[archetype_id] |
| 2331 | 48 | if #compatibleArchetype.entities == 0 then |
| 2332 | 0 | continue |
| 2333 | N/A | end | >
| 2334 | 34 | local records = compatibleArchetype.records |
| 2335 | N/A | > |
| 2336 | 34 | local skip = false |
| 2337 | N/A | > |
| 2338 | 34 | for i, id in ids do |
| 2339 | 47 | local tr = records[id] |
| 2340 | 47 | if not tr then |
| 2341 | 0 | skip = true |
| 2342 | 0 | break |
| 2343 | N/A | end | >
| 2344 | N/A | end | >
| 2345 | N/A | > |
| 2346 | 34 | if skip then |
| 2347 | 0 | continue |
| 2348 | N/A | end | >
| 2349 | N/A | > |
| 2350 | 34 | length += 1 |
| 2351 | 34 | compatible_archetypes[length] = compatibleArchetype |
| 2352 | N/A | end | >
| 2353 | N/A | > |
| 2354 | 26 | return q |
| 2355 | N/A | end | >
| 2356 | N/A | > |
| 2357 | 1 | local function world_each(world: ecs_world_t, id: i53): () -> () |
| 2358 | 2 | local idr = world.component_index[id] |
| 2359 | 2 | if not idr then |
| 2360 | 0 | return NOOP |
| 2361 | N/A | end | >
| 2362 | N/A | > |
| 2363 | 2 | local idr_cache = idr.cache |
| 2364 | 2 | local archetypes = world.archetypes |
| 2365 | 2 | local archetype_id = next(idr_cache, nil) :: number |
| 2366 | 2 | local archetype = archetypes[archetype_id] |
| 2367 | 2 | if not archetype then |
| 2368 | 0 | return NOOP |
| 2369 | N/A | end | >
| 2370 | N/A | > |
| 2371 | 2 | local entities = archetype.entities |
| 2372 | 2 | local row = #entities |
| 2373 | N/A | > |
| 2374 | 2 | return function(): any |
| 2375 | 12 | local entity = entities[row] |
| 2376 | 12 | while not entity do |
| 2377 | 11 | archetype_id = next(idr_cache, archetype_id) :: number |
| 2378 | 11 | if not archetype_id then |
| 2379 | 4 | return |
| 2380 | N/A | end | >
| 2381 | 7 | archetype = archetypes[archetype_id] |
| 2382 | 7 | entities = archetype.entities |
| 2383 | 7 | row = #entities |
| 2384 | 7 | entity = entities[row] |
| 2385 | N/A | end | >
| 2386 | 8 | row -= 1 |
| 2387 | 8 | return entity |
| 2388 | N/A | end | >
| 2389 | N/A | end | >
| 2390 | N/A | > |
| 2391 | 1 | local function world_children(world: ecs_world_t, parent: i53) |
| 2392 | 2 | return world_each(world, ECS_PAIR(EcsChildOf, parent)) |
| 2393 | N/A | end | >
| 2394 | N/A | > |
| 2395 | 0 | export type Record = { |
| 2396 | 0 | archetype: Archetype, |
| 2397 | 0 | row: number, |
| 2398 | 0 | dense: i24, |
| 2399 | 0 | } |
| 2400 | 0 | export type ComponentRecord = { |
| 2401 | 0 | cache: { [Id]: number }, |
| 2402 | 0 | counts: { [Id]: number }, |
| 2403 | 0 | flags: number, |
| 2404 | 0 | size: number, |
| 2405 | 0 | hooks: { |
| 2406 | 0 | on_add: ((entity: Entity) -> ())?, |
| 2407 | 0 | on_set: ((entity: Entity, data: any) -> ())?, |
| 2408 | 0 | on_remove: ((entity: Entity) -> ())?, |
| 2409 | 0 | }, |
| 2410 | 0 | } |
| 2411 | 0 | export type ComponentIndex = Map |
| 2412 | 0 | export type Archetypes = { [Id]: Archetype } |
| 2413 | N/A | > |
| 2414 | 0 | export type EntityIndex = { |
| 2415 | 0 | dense_array: Map |
| 2416 | 0 | sparse_array: Map |
| 2417 | 0 | alive_count: number, |
| 2418 | 0 | max_id: number, |
| 2419 | 0 | } |
| 2420 | N/A | > |
| 2421 | 1 | local World = {} |
| 2422 | 1 | World.__index = World |
| 2423 | N/A | > |
| 2424 | 1 | World.entity = world_entity |
| 2425 | 1 | World.query = world_query |
| 2426 | 1 | World.remove = world_remove |
| 2427 | 1 | World.clear = world_clear |
| 2428 | 1 | World.delete = world_delete |
| 2429 | 1 | World.component = world_component |
| 2430 | 1 | World.add = world_add |
| 2431 | 1 | World.set = world_set |
| 2432 | 1 | World.get = world_get |
| 2433 | 1 | World.has = world_has |
| 2434 | 1 | World.target = world_target |
| 2435 | 1 | World.parent = world_parent |
| 2436 | 1 | World.contains = world_contains |
| 2437 | 1 | World.cleanup = world_cleanup |
| 2438 | 1 | World.each = world_each |
| 2439 | 1 | World.children = world_children |
| 2440 | N/A | > |
| 2441 | 1 | local function world_new() |
| 2442 | 73 | local entity_index = { |
| 2443 | 73 | dense_array = {}, |
| 2444 | 73 | sparse_array = {}, |
| 2445 | 73 | alive_count = 0, |
| 2446 | 73 | max_id = 0, |
| 2447 | 0 | } :: ecs_entity_index_t |
| 2448 | 73 | local self = setmetatable({ |
| 2449 | 73 | archetype_index = {} :: { [string]: Archetype }, |
| 2450 | 73 | archetypes = {} :: Archetypes, |
| 2451 | 73 | component_index = {} :: ComponentIndex, |
| 2452 | 73 | entity_index = entity_index, |
| 2453 | 73 | ROOT_ARCHETYPE = (nil :: any) :: Archetype, |
| 2454 | N/A | > |
| 2455 | 73 | max_archetype_id = 0, |
| 2456 | 73 | max_component_id = 0, |
| 2457 | N/A | > |
| 2458 | 73 | observable = {} :: Observable, |
| 2459 | 73 | }, World) :: any |
| 2460 | N/A | > |
| 2461 | 73 | self.ROOT_ARCHETYPE = archetype_create(self, {}, "") |
| 2462 | N/A | > |
| 2463 | 73 | for i = 1, HI_COMPONENT_ID do |
| 2464 | 18688 | local e = entity_index_new_id(entity_index) |
| 2465 | 18688 | world_add(self, e, EcsComponent) |
| 2466 | N/A | end | >
| 2467 | N/A | > |
| 2468 | 73 | for i = HI_COMPONENT_ID + 1, EcsRest do |
| 2469 | N/A | -- Initialize built-in components | >
| 2470 | 1022 | entity_index_new_id(entity_index) |
| 2471 | N/A | end | >
| 2472 | N/A | > |
| 2473 | 73 | world_add(self, EcsName, EcsComponent) |
| 2474 | 73 | world_add(self, EcsOnSet, EcsComponent) |
| 2475 | 73 | world_add(self, EcsOnAdd, EcsComponent) |
| 2476 | 73 | world_add(self, EcsOnRemove, EcsComponent) |
| 2477 | 73 | world_add(self, EcsWildcard, EcsComponent) |
| 2478 | 73 | world_add(self, EcsRest, EcsComponent) |
| 2479 | N/A | > |
| 2480 | 73 | world_set(self, EcsOnAdd, EcsName, "jecs.OnAdd") |
| 2481 | 73 | world_set(self, EcsOnRemove, EcsName, "jecs.OnRemove") |
| 2482 | 73 | world_set(self, EcsOnSet, EcsName, "jecs.OnSet") |
| 2483 | 73 | world_set(self, EcsWildcard, EcsName, "jecs.Wildcard") |
| 2484 | 73 | world_set(self, EcsChildOf, EcsName, "jecs.ChildOf") |
| 2485 | 73 | world_set(self, EcsComponent, EcsName, "jecs.Component") |
| 2486 | 73 | world_set(self, EcsOnDelete, EcsName, "jecs.OnDelete") |
| 2487 | 73 | world_set(self, EcsOnDeleteTarget, EcsName, "jecs.OnDeleteTarget") |
| 2488 | 73 | world_set(self, EcsDelete, EcsName, "jecs.Delete") |
| 2489 | 73 | world_set(self, EcsRemove, EcsName, "jecs.Remove") |
| 2490 | 73 | world_set(self, EcsName, EcsName, "jecs.Name") |
| 2491 | 73 | world_set(self, EcsRest, EcsRest, "jecs.Rest") |
| 2492 | N/A | > |
| 2493 | 73 | world_add(self, EcsChildOf, ECS_PAIR(EcsOnDeleteTarget, EcsDelete)) |
| 2494 | N/A | > |
| 2495 | 73 | return self |
| 2496 | N/A | end | >
| 2497 | N/A | > |
| 2498 | 1 | World.new = world_new |
| 2499 | N/A | > |
| 2500 | 0 | export type Entity |
| 2501 | 0 | export type Id |
| 2502 | 0 | export type Pair = Id |
| 2503 | 0 | type ecs_id_t |
| 2504 | 0 | export type Item |
| 2505 | 0 | export type Iter |
| 2506 | N/A | > |
| 2507 | 0 | export type Query |
| 2508 | 0 | __iter = (nil :: any) :: Iter |
| 2509 | 0 | })) & { |
| 2510 | 0 | iter: Iter |
| 2511 | 0 | with: (self: Query |
| 2512 | 0 | without: (self: Query |
| 2513 | 0 | archetypes: (self: Query |
| 2514 | 0 | cached: (self: Query |
| 2515 | 0 | } |
| 2516 | N/A | > |
| 2517 | 0 | export type Observer = { |
| 2518 | 0 | callback: (archetype: Archetype) -> (), |
| 2519 | 0 | query: QueryInner, |
| 2520 | 0 | } |
| 2521 | N/A | > |
| 2522 | 0 | export type Observable = { |
| 2523 | 0 | [Id]: { |
| 2524 | 0 | [Id]: { |
| 2525 | 0 | { Observer } |
| 2526 | 0 | } |
| 2527 | 0 | } |
| 2528 | 0 | } |
| 2529 | N/A | > |
| 2530 | 0 | export type World = { |
| 2531 | 0 | archetype_index: { [string]: Archetype }, |
| 2532 | 0 | archetypes: Archetypes, |
| 2533 | 0 | component_index: ComponentIndex, |
| 2534 | 0 | entity_index: EntityIndex, |
| 2535 | 0 | ROOT_ARCHETYPE: Archetype, |
| 2536 | N/A | > |
| 2537 | 0 | max_component_id: number, |
| 2538 | 0 | max_archetype_id: number, |
| 2539 | N/A | > |
| 2540 | 0 | observable: any, |
| 2541 | N/A | > |
| 2542 | N/A | --- Creates a new entity | >
| 2543 | 0 | entity: (self: World, id: Entity?) -> Entity, |
| 2544 | N/A | --- Creates a new entity located in the first 256 ids. | >
| 2545 | N/A | --- These should be used for static components for fast access. | >
| 2546 | 0 | component: |
| 2547 | N/A | --- Gets the target of an relationship. For example, when a user calls | >
| 2548 | N/A | --- `world:target(id, ChildOf(parent), 0)`, you will obtain the parent entity. | >
| 2549 | 0 | target: (self: World, id: Entity, relation: Id, index: number?) -> Entity?, |
| 2550 | N/A | --- Deletes an entity and all it's related components and relationships. | >
| 2551 | 0 | delete: (self: World, id: Entity) -> (), |
| 2552 | N/A | > |
| 2553 | N/A | --- Adds a component to the entity with no value | >
| 2554 | 0 | add: |
| 2555 | N/A | --- Assigns a value to a component on the given entity | >
| 2556 | 0 | set: |
| 2557 | N/A | > |
| 2558 | 0 | cleanup: (self: World) -> (), |
| 2559 | N/A | -- Clears an entity from the world | >
| 2560 | 0 | clear: (self: World, id: Entity) -> (), |
| 2561 | N/A | --- Removes a component from the given entity | >
| 2562 | 0 | remove: (self: World, id: Entity, component: Id) -> (), |
| 2563 | N/A | --- Retrieves the value of up to 4 components. These values may be nil. | >
| 2564 | 0 | get: ((self: World, id: Entity, Id) -> A?) |
| 2565 | 0 | & ((self: World, id: Entity, Id, Id) -> (A?, B?)) |
| 2566 | 0 | & ((self: World, id: Entity, Id, Id, Id |
| 2567 | 0 | & (self: World, id: Entity, Id, Id, Id |
| 2568 | N/A | > |
| 2569 | N/A | --- Returns whether the entity has the ID. | >
| 2570 | 0 | has: (self: World, entity: Entity, ...Id) -> boolean, |
| 2571 | N/A | > |
| 2572 | N/A | --- Get parent (target of ChildOf relationship) for entity. If there is no ChildOf relationship pair, it will return nil. | >
| 2573 | 0 | parent:(self: World, entity: Entity) -> Entity, |
| 2574 | N/A | > |
| 2575 | N/A | --- Checks if the world contains the given entity | >
| 2576 | 0 | contains:(self: World, entity: Entity) -> boolean, |
| 2577 | N/A | > |
| 2578 | 0 | each: (self: World, id: Id) -> () -> Entity, |
| 2579 | N/A | > |
| 2580 | 0 | children: (self: World, id: Id) -> () -> Entity, |
| 2581 | N/A | > |
| 2582 | N/A | --- Searches the world for entities that match a given query | >
| 2583 | 0 | query: ((World, Id) -> Query) |
| 2584 | 0 | & ((World, Id, Id) -> Query) |
| 2585 | 0 | & ((World, Id, Id, Id |
| 2586 | 0 | & ((World, Id, Id, Id |
| 2587 | 0 | & ((World, Id, Id, Id |
| 2588 | 0 | & ((World, Id, Id, Id |
| 2589 | 0 | & ((World, Id, Id, Id |
| 2590 | 0 | & ((World, Id, Id, Id |
| 2591 | 0 | } |
| 2592 | N/A | -- type function ecs_id_t(entity) | >
| 2593 | N/A | -- local ty = entity:components()[2] | >
| 2594 | N/A | -- local __T = ty:readproperty(types.singleton("__T")) | >
| 2595 | N/A | -- if not __T then | >
| 2596 | N/A | -- return ty:readproperty(types.singleton("__jecs_pair_value")) | >
| 2597 | N/A | -- end | >
| 2598 | N/A | -- return __T | >
| 2599 | N/A | -- end | >
| 2600 | N/A | > |
| 2601 | N/A | -- type function ecs_pair_t(first, second) | >
| 2602 | N/A | -- if ecs_id_t(first):is("nil") then | >
| 2603 | N/A | -- return second | >
| 2604 | N/A | -- else | >
| 2605 | N/A | -- return first | >
| 2606 | N/A | -- end | >
| 2607 | N/A | -- end | >
| 2608 | N/A | > |
| 2609 | 1 | return { |
| 2610 | 1 | World = World :: { new: () -> World }, |
| 2611 | 1 | world = World.new :: () -> World, |
| 2612 | N/A | > |
| 2613 | 1 | OnAdd = EcsOnAdd :: Entity<(entity: Entity) -> ()>, |
| 2614 | 1 | OnRemove = EcsOnRemove :: Entity<(entity: Entity) -> ()>, |
| 2615 | 1 | OnSet = EcsOnSet :: Entity<(entity: Entity, data: any) -> ()>, |
| 2616 | 1 | ChildOf = EcsChildOf :: Entity, |
| 2617 | 1 | Component = EcsComponent :: Entity, |
| 2618 | 1 | Wildcard = EcsWildcard :: Entity, |
| 2619 | 1 | w = EcsWildcard :: Entity, |
| 2620 | 1 | OnDelete = EcsOnDelete :: Entity, |
| 2621 | 1 | OnDeleteTarget = EcsOnDeleteTarget :: Entity, |
| 2622 | 1 | Delete = EcsDelete :: Entity, |
| 2623 | 1 | Remove = EcsRemove :: Entity, |
| 2624 | 1 | Name = EcsName :: Entity |
| 2625 | 1 | Rest = EcsRest :: Entity, |
| 2626 | N/A | > |
| 2627 | 1 | pair = (ECS_PAIR :: any) :: (first: Id , second: Id , |
| 2628 | N/A | > |
| 2629 | N/A | -- Inwards facing API for testing | >
| 2630 | 1 | ECS_ID = ECS_ENTITY_T_LO, |
| 2631 | 1 | ECS_GENERATION_INC = ECS_GENERATION_INC, |
| 2632 | 1 | ECS_GENERATION = ECS_GENERATION, |
| 2633 | 1 | ECS_ID_IS_WILDCARD = ECS_ID_IS_WILDCARD, |
| 2634 | N/A | > |
| 2635 | 1 | ECS_ID_DELETE = ECS_ID_DELETE, |
| 2636 | N/A | > |
| 2637 | 1 | IS_PAIR = ECS_IS_PAIR, |
| 2638 | 1 | pair_first = ecs_pair_first, |
| 2639 | 1 | pair_second = ecs_pair_second, |
| 2640 | 1 | entity_index_get_alive = entity_index_get_alive, |
| 2641 | N/A | > |
| 2642 | 1 | archetype_append_to_records = archetype_append_to_records, |
| 2643 | 1 | id_record_ensure = id_record_ensure, |
| 2644 | 1 | archetype_create = archetype_create, |
| 2645 | 1 | archetype_ensure = archetype_ensure, |
| 2646 | 1 | find_insert = find_insert, |
| 2647 | 1 | find_archetype_with = find_archetype_with, |
| 2648 | 1 | find_archetype_without = find_archetype_without, |
| 2649 | 1 | archetype_init_edge = archetype_init_edge, |
| 2650 | 1 | archetype_ensure_edge = archetype_ensure_edge, |
| 2651 | 1 | init_edge_for_add = init_edge_for_add, |
| 2652 | 1 | init_edge_for_remove = init_edge_for_remove, |
| 2653 | 1 | create_edge_for_add = create_edge_for_add, |
| 2654 | 1 | create_edge_for_remove = create_edge_for_remove, |
| 2655 | 1 | archetype_traverse_add = archetype_traverse_add, |
| 2656 | 1 | archetype_traverse_remove = archetype_traverse_remove, |
| 2657 | N/A | > |
| 2658 | 1 | entity_move = entity_move, |
| 2659 | N/A | > |
| 2660 | 1 | entity_index_try_get = entity_index_try_get, |
| 2661 | 1 | entity_index_try_get_any = entity_index_try_get_any, |
| 2662 | 1 | entity_index_try_get_fast = entity_index_try_get_fast, |
| 2663 | 1 | entity_index_is_alive = entity_index_is_alive, |
| 2664 | 1 | entity_index_new_id = entity_index_new_id, |
| 2665 | N/A | > |
| 2666 | 1 | query_iter = query_iter, |
| 2667 | 1 | query_iter_init = query_iter_init, |
| 2668 | 1 | query_with = query_with, |
| 2669 | 1 | query_without = query_without, |
| 2670 | 1 | query_archetypes = query_archetypes, |
| 2671 | 1 | query_match = query_match, |
| 2672 | N/A | > |
| 2673 | 1 | find_observers = find_observers, |
| 2674 | 0 | } |