@@ -62,6 +62,8 @@ type ecs_entity_index_t = {
6262 sparse_array : Map <i24 , ecs_record_t >,
6363 alive_count : number ,
6464 max_id : number ,
65+ range_begin : number ? ,
66+ range_end : number ?
6567}
6668
6769type ecs_query_data_t = {
@@ -125,6 +127,12 @@ local ECS_INTERNAL_ERROR = [[
125127 https://github.com/Ukendio/jecs/issues/new?template=BUG-REPORT.md
126128]]
127129
130+ local function ecs_assert (condition , msg : string ? )
131+ if not condition then
132+ error (msg )
133+ end
134+ end
135+
128136local ecs_metadata : Map <i53 , Map <i53 , any >> = {}
129137local ecs_max_component_id = 0
130138local ecs_max_tag_id = EcsRest
@@ -185,6 +193,10 @@ local function ECS_ENTITY_T_LO(e: i53): i24
185193 return e % ECS_ENTITY_MASK
186194end
187195
196+ local function ECS_ID (e : i53 )
197+ return e % ECS_ENTITY_MASK
198+ end
199+
188200local function ECS_GENERATION (e : i53 )
189201 return e // ECS_ENTITY_MASK
190202end
@@ -249,10 +261,10 @@ local function entity_index_is_alive(entity_index: ecs_entity_index_t, entity: i
249261 return entity_index_try_get (entity_index , entity ) ~= nil
250262end
251263
252- local function entity_index_get_alive (index : ecs_entity_index_t , entity : i53 ): i53 ?
253- local r = entity_index_try_get_any (index , entity )
264+ local function entity_index_get_alive (entity_index : ecs_entity_index_t , entity : i53 ): i53 ?
265+ local r = entity_index_try_get_any (entity_index , entity )
254266 if r then
255- return index .dense_array [r .dense ]
267+ return entity_index .dense_array [r .dense ]
256268 end
257269 return nil
258270end
@@ -280,23 +292,30 @@ local function ecs_get_alive(world, entity)
280292 return current
281293end
282294
295+ local ECS_INTERNAL_ERROR_INCOMPATIBLE_ENTITY = "Entity is outside range"
296+
283297local function entity_index_new_id (entity_index : ecs_entity_index_t ): i53
284298 local dense_array = entity_index .dense_array
285299 local alive_count = entity_index .alive_count
300+ local sparse_array = entity_index .sparse_array
286301 local max_id = entity_index .max_id
287- if alive_count ~= max_id then
302+
303+ if alive_count < max_id then
288304 alive_count += 1
289305 entity_index .alive_count = alive_count
290306 local id = dense_array [alive_count ]
291307 return id
292308 end
293309
294310 local id = max_id + 1
311+ local range_end = entity_index .range_end
312+ ecs_assert (range_end == nil or id < range_end , ECS_INTERNAL_ERROR_INCOMPATIBLE_ENTITY )
313+
295314 entity_index .max_id = id
296315 alive_count += 1
297316 entity_index .alive_count = alive_count
298317 dense_array [alive_count ] = id
299- entity_index . sparse_array [id ] = { dense = alive_count } :: ecs_record_t
318+ sparse_array [id ] = { dense = alive_count } :: ecs_record_t
300319
301320 return id
302321end
@@ -583,10 +602,10 @@ local function id_record_ensure(world: ecs_world_t, id: number): ecs_id_record_t
583602 local is_pair = ECS_IS_PAIR (id )
584603 if is_pair then
585604 relation = entity_index_get_alive (entity_index , ECS_PAIR_FIRST (id )) :: i53
586- assert (relation and entity_index_is_alive (
605+ ecs_assert (relation and entity_index_is_alive (
587606 entity_index , relation ), ECS_INTERNAL_ERROR )
588607 target = entity_index_get_alive (entity_index , ECS_PAIR_SECOND (id )) :: i53
589- assert (target and entity_index_is_alive (
608+ ecs_assert (target and entity_index_is_alive (
590609 entity_index , target ), ECS_INTERNAL_ERROR )
591610 end
592611
@@ -719,8 +738,100 @@ local function archetype_create(world: ecs_world_t, id_types: { i24 }, ty, prev:
719738 return archetype
720739end
721740
722- local function world_entity (world : ecs_world_t ): i53
723- return entity_index_new_id (world .entity_index )
741+ local function world_range (world : ecs_world_t , range_begin : number , range_end : number ? )
742+ local entity_index = world .entity_index
743+
744+ entity_index .range_begin = range_begin
745+ entity_index .range_end = range_end
746+
747+ local max_id = entity_index .max_id
748+
749+ if range_begin > max_id then
750+ local dense_array = entity_index .dense_array
751+ local sparse_array = entity_index .sparse_array
752+
753+ for i = max_id , range_begin do
754+ dense_array [i ] = i
755+ sparse_array [i ] = {
756+ dense = 0
757+ } :: ecs_record_t
758+ end
759+ entity_index .max_id = range_begin - 1
760+ entity_index .alive_count = range_begin - 1
761+ end
762+ end
763+
764+ local function world_entity (world : ecs_world_t , entity : i53 ? ): i53
765+ local entity_index = world .entity_index
766+ if entity then
767+ local index = ECS_ID (entity )
768+ local max_id = entity_index .max_id
769+ local sparse_array = entity_index .sparse_array
770+ local dense_array = entity_index .dense_array
771+ local alive_count = entity_index .alive_count
772+ local r = sparse_array [index ]
773+ if r then
774+ local dense = r .dense
775+ if not dense or dense == 0 then
776+ dense = index
777+ end
778+ local any = dense_array [dense ]
779+ if any == entity then
780+ if alive_count > dense then
781+ return entity
782+ end
783+ local e_swap = dense_array [alive_count ]
784+ local r_swap = sparse_array [alive_count ]
785+ r_swap .dense = dense
786+ r .dense = alive_count
787+ dense_array [alive_count ] = entity
788+ dense_array [dense ] = e_swap
789+ return entity
790+ end
791+
792+ -- assert(any ~= 0) should never happen
793+
794+ local e_swap = dense_array [alive_count ]
795+ local r_swap = sparse_array [alive_count ]
796+
797+ if dense <= alive_count then
798+ alive_count += 1
799+ entity_index .alive_count = alive_count
800+ end
801+
802+ r_swap .dense = dense
803+ r .dense = alive_count
804+ dense_array [alive_count ] = any
805+ dense_array [dense ] = e_swap
806+ return any
807+ else
808+ for i = max_id + 1 , index do
809+ sparse_array [i ] = { dense = i } :: ecs_record_t
810+ dense_array [i ] = i
811+ end
812+ entity_index .max_id = index
813+
814+ local e_swap = dense_array [alive_count ]
815+ local r_swap = sparse_array [alive_count ]
816+ r_swap .dense = index
817+
818+ alive_count += 1
819+ entity_index .alive_count = alive_count
820+
821+ r = sparse_array [index ]
822+
823+ r .dense = alive_count
824+
825+ sparse_array [index ] = r
826+
827+ dense_array [index ] = e_swap
828+ dense_array [alive_count ] = entity
829+
830+
831+ return entity
832+ end
833+ end
834+ return entity_index_new_id (entity_index , entity )
724835end
725836
726837local function world_parent (world : ecs_world_t , entity : i53 )
@@ -2311,6 +2422,8 @@ export type EntityIndex = {
23112422 sparse_array : Map <i24 , Record >,
23122423 alive_count : number ,
23132424 max_id : number ,
2425+ range_begin : number ? ,
2426+ range_end : number ?
23142427}
23152428
23162429local World = {}
@@ -2332,6 +2445,7 @@ World.contains = world_contains
23322445World .cleanup = world_cleanup
23332446World .each = world_each
23342447World .children = world_children
2448+ World .range = world_range
23352449
23362450local function world_new ()
23372451 local entity_index = {
@@ -2454,6 +2568,9 @@ export type World = {
24542568
24552569 observable : any ,
24562570
2571+ --- Enforce a check on entities to be created within desired range
2572+ range : (self : World , range_begin : number , range_end : number ? ) -> (),
2573+
24572574 --- Creates a new entity
24582575 entity : (self : World , id : Entity ? ) -> Entity ,
24592576 --- Creates a new entity located in the first 256 ids.
@@ -2558,6 +2675,8 @@ return {
25582675 ECS_META_RESET = ECS_META_RESET ,
25592676
25602677 IS_PAIR = (ECS_IS_PAIR :: any ) :: <P , O >(pair : Pair <P , O >) - > boolean ,
2678+ ECS_PAIR_FIRST = ECS_PAIR_FIRST ,
2679+ ECS_PAIR_SECOND = ECS_PAIR_SECOND ,
25612680 pair_first = (ecs_pair_first :: any ) :: <P , O >(world : World , pair : Pair <P , O >) - > Id < P > ,
25622681 pair_second = (ecs_pair_second :: any ) :: <P , O >(world : World , pair : Pair <P , O >) - > Id < O > ,
25632682 entity_index_get_alive = entity_index_get_alive ,
0 commit comments