diff --git a/develop/untests.lua b/develop/untests.lua index e1cbb97..ddef23d 100644 --- a/develop/untests.lua +++ b/develop/untests.lua @@ -2453,6 +2453,27 @@ do end end +do + local f1, f2 = evo.id(2) + + do + local e = evo.entity() + :set(f1, 41) + :set(f2, 42) + :build() + assert(evo.has(e, f1) and evo.get(e, f1) == 41) + assert(evo.has(e, f2) and evo.get(e, f2) == 42) + end + + do + local e = evo.entity() + :set(f1, 11) + :set(f1, 41) + :build() + assert(evo.has(e, f1) and evo.get(e, f1) == 41) + end +end + do local f1 = evo.fragment():default(41):build() local f2 = evo.fragment():construct(function() return 42 end):build() @@ -2579,7 +2600,7 @@ do assert(evo.commit()) assert(evo.has(e1, f1) and evo.get(e1, f1) == 41) assert(evo.has(e1, f2) and evo.get(e1, f2) == 42) - assert(evo.has(e2, f2) and evo.get(e2, f2) == 44) + assert(evo.has(e2, f2) and evo.get(e2, f2) == 43) end end @@ -2943,3 +2964,185 @@ do assert(last_insert_entity == e and last_insert_component == 42) end end + +do + local f1 = evo.id() + + local assign_entity_sum = 0 + local assign_component_sum = 0 + local insert_entity_sum = 0 + local insert_component_sum = 0 + local remove_entity_sum = 0 + local remove_component_sum = 0 + + evo.set(f1, evo.ON_ASSIGN, function(e, f, c) + assert(f == f1) + assign_entity_sum = assign_entity_sum + e + assign_component_sum = assign_component_sum + c + end) + + evo.set(f1, evo.ON_INSERT, function(e, f, c) + assert(f == f1) + insert_entity_sum = insert_entity_sum + e + insert_component_sum = insert_component_sum + c + end) + + evo.set(f1, evo.ON_REMOVE, function(e, f, c) + assert(f == f1) + remove_entity_sum = remove_entity_sum + e + remove_component_sum = remove_component_sum + c + end) + + do + assign_entity_sum, assign_component_sum = 0, 0 + insert_entity_sum, insert_component_sum = 0, 0 + + local e = evo.id() + assert(evo.multi_set(e, { f1, f1 }, { 41, 42 })) + + assert(assign_entity_sum == e and assign_component_sum == 42) + assert(insert_entity_sum == e and insert_component_sum == 41) + end + + do + assign_entity_sum, assign_component_sum = 0, 0 + insert_entity_sum, insert_component_sum = 0, 0 + + local e = evo.id() + assert(evo.multi_set(e, { f1, f1, f1 }, { 41, 42, 43 })) + + assert(assign_entity_sum == e + e and assign_component_sum == 42 + 43) + assert(insert_entity_sum == e and insert_component_sum == 41) + end + + do + assign_entity_sum, assign_component_sum = 0, 0 + insert_entity_sum, insert_component_sum = 0, 0 + + local e = evo.id() + assert(evo.insert(e, f1, 41)) + assert(evo.multi_assign(e, { f1, f1 }, { 42, 43 })) + + assert(assign_entity_sum == e + e and assign_component_sum == 42 + 43) + assert(insert_entity_sum == e and insert_component_sum == 41) + end + + do + assign_entity_sum, assign_component_sum = 0, 0 + insert_entity_sum, insert_component_sum = 0, 0 + + local e = evo.id() + assert(evo.multi_insert(e, { f1, f1 }, { 41, 42 })) + + assert(insert_entity_sum == e and insert_component_sum == 41) + end + + do + remove_entity_sum, remove_component_sum = 0, 0 + + local e = evo.id() + assert(evo.insert(e, f1, 41)) + assert(evo.multi_remove(e, { f1, f1 })) + + assert(remove_entity_sum == e and remove_component_sum == 41) + end +end + +do + local f1, f2 = evo.id(2) + local qb = evo.query() + + do + local q = qb:build() + + local includes, excludes = evo.get(q, evo.INCLUDES, evo.EXCLUDES) + assert(includes == nil) + assert(excludes == nil) + end + + do + local q = qb:include(f1):build() + + local includes, excludes = evo.get(q, evo.INCLUDES, evo.EXCLUDES) + assert(#includes == 1 and includes[1] == f1) + assert(excludes == nil) + end + + do + local q = qb:include(f1, f2):build() + + local includes, excludes = evo.get(q, evo.INCLUDES, evo.EXCLUDES) + assert(#includes == 2 and includes[1] == f1 and includes[2] == f2) + assert(excludes == nil) + end + + do + local q = qb:include(f1):include(f2):build() + + local includes, excludes = evo.get(q, evo.INCLUDES, evo.EXCLUDES) + assert(#includes == 2 and includes[1] == f1 and includes[2] == f2) + assert(excludes == nil) + end + + do + local q = qb:exclude(f1):build() + + local includes, excludes = evo.get(q, evo.INCLUDES, evo.EXCLUDES) + assert(includes == nil) + assert(#excludes == 1 and excludes[1] == f1) + end + + do + local q = qb:exclude(f1, f2):build() + + local includes, excludes = evo.get(q, evo.INCLUDES, evo.EXCLUDES) + assert(includes == nil) + assert(#excludes == 2 and excludes[1] == f1 and excludes[2] == f2) + end + + do + local q = qb:exclude(f1):exclude(f2):build() + + local includes, excludes = evo.get(q, evo.INCLUDES, evo.EXCLUDES) + assert(includes == nil) + assert(#excludes == 2 and excludes[1] == f1 and excludes[2] == f2) + end + + do + qb:include(f1) + qb:exclude(f2) + + local q = qb:build() + + local includes, excludes = evo.get(q, evo.INCLUDES, evo.EXCLUDES) + assert(#includes == 1 and includes[1] == f1) + assert(#excludes == 1 and excludes[1] == f2) + end +end + +do + local f1, f2 = evo.id(2) + local eb = evo.entity() + + do + local e = eb:build() + assert(evo.is_alive(e) and evo.is_empty(e)) + end + + do + local e = eb:set(f1, 41):build() + assert(evo.has(e, f1) and evo.get(e, f1) == 41) + assert(not evo.has(e, f2) and evo.get(e, f2) == nil) + end + + do + local e = eb:set(f1, 41):set(f2, 42):build() + assert(evo.has(e, f1) and evo.get(e, f1) == 41) + assert(evo.has(e, f2) and evo.get(e, f2) == 42) + end + + do + local e = eb:build() + assert(evo.is_alive(e) and evo.is_empty(e)) + end +end diff --git a/evolved.lua b/evolved.lua index 093a732..f8f0aed 100644 --- a/evolved.lua +++ b/evolved.lua @@ -212,14 +212,17 @@ end ---| `__TABLE_POOL_TAG__CHUNK_LIST` ---| `__TABLE_POOL_TAG__EACH_STATE` ---| `__TABLE_POOL_TAG__EXECUTE_STATE` +---| `__TABLE_POOL_TAG__FRAGMENT_SET` ---| `__TABLE_POOL_TAG__FRAGMENT_LIST` +---| `__TABLE_POOL_TAG__COMPONENT_LIST` local __TABLE_POOL_TAG__BYTECODE = 1 local __TABLE_POOL_TAG__CHUNK_LIST = 2 local __TABLE_POOL_TAG__EACH_STATE = 3 local __TABLE_POOL_TAG__EXECUTE_STATE = 4 -local __TABLE_POOL_TAG__FRAGMENT_LIST = 5 -local __TABLE_POOL_TAG__COMPONENT_LIST = 6 +local __TABLE_POOL_TAG__FRAGMENT_SET = 5 +local __TABLE_POOL_TAG__FRAGMENT_LIST = 7 +local __TABLE_POOL_TAG__COMPONENT_LIST = 8 ---@type table local __tagged_table_pools = __table_new(6, 0) @@ -2561,9 +2564,11 @@ function evolved.multi_set(entity, fragments, components) __detach_entity(entity) end + local inserted_set = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_SET, 0, fragment_count) + for i = 1, fragment_count do local fragment = fragments[i] - if old_fragment_set[fragment] then + if inserted_set[fragment] or old_fragment_set[fragment] then local new_component_index = new_component_indices[fragment] if new_component_index then @@ -2597,6 +2602,8 @@ function evolved.multi_set(entity, fragments, components) end end else + inserted_set[fragment] = true + local new_component_index = new_component_indices[fragment] if new_component_index then @@ -2631,6 +2638,8 @@ function evolved.multi_set(entity, fragments, components) end end + __release_table(__TABLE_POOL_TAG__FRAGMENT_SET, inserted_set) + __entity_chunks[entity_index] = new_chunk __entity_places[entity_index] = new_place @@ -2790,9 +2799,13 @@ function evolved.multi_insert(entity, fragments, components) __detach_entity(entity) end + local inserted_set = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_SET, 0, fragment_count) + for i = 1, fragment_count do local fragment = fragments[i] - if not old_fragment_set[fragment] then + if not inserted_set[fragment] and not old_fragment_set[fragment] then + inserted_set[fragment] = true + local new_component_index = new_component_indices[fragment] if new_component_index then @@ -2876,9 +2889,12 @@ function evolved.multi_remove(entity, fragments) local old_component_storages = old_chunk.__component_storages if old_chunk.__has_remove_hooks then + local removed_set = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_SET, 0, fragment_count) + for i = 1, fragment_count do local fragment = fragments[i] - if old_fragment_set[fragment] then + if not removed_set[fragment] and old_fragment_set[fragment] then + removed_set[fragment] = true local old_component_index = old_component_indices[fragment] if old_component_index then local old_component_storage = old_component_storages[old_component_index] @@ -2889,6 +2905,8 @@ function evolved.multi_remove(entity, fragments) end end end + + __release_table(__TABLE_POOL_TAG__FRAGMENT_SET, removed_set) end if new_chunk then @@ -3411,8 +3429,8 @@ evolved_entity_builder.__index = evolved_entity_builder function evolved.entity() ---@type evolved.__entity_builder local builder = { - __fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, 8, 0), - __component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST, 8, 0), + __fragment_list = nil, + __component_list = nil, } ---@cast builder evolved.entity_builder return setmetatable(builder, evolved_entity_builder) @@ -3427,6 +3445,13 @@ function evolved_entity_builder:set(fragment, ...) local fragment_list = self.__fragment_list local component_list = self.__component_list + if not fragment_list then + fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, 8, 0) + component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST, 8, 0) + self.__fragment_list = fragment_list + self.__component_list = component_list + end + fragment_list[#fragment_list + 1] = fragment component_list[#component_list + 1] = component @@ -3438,17 +3463,17 @@ function evolved_entity_builder:build() local fragment_list = self.__fragment_list local component_list = self.__component_list - self.__fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, 8, 0) - self.__component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST, 8, 0) + self.__fragment_list = nil + self.__component_list = nil local entity = evolved.id() - for i = 1, #fragment_list do - local fragment = fragment_list[i] - local component = component_list[i] - evolved.set(entity, fragment, component) + if not fragment_list then + return entity end + evolved.multi_set(entity, fragment_list, component_list) + __release_table(__TABLE_POOL_TAG__FRAGMENT_LIST, fragment_list) __release_table(__TABLE_POOL_TAG__COMPONENT_LIST, component_list) @@ -3515,18 +3540,29 @@ function evolved_fragment_builder:build() local fragment = evolved.id() + local fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, 3, 0) + local component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST, 3, 0) + if tag then - evolved.set(fragment, evolved.TAG, tag) + fragment_list[#fragment_list + 1] = evolved.TAG + component_list[#component_list + 1] = true end if default ~= nil then - evolved.set(fragment, evolved.DEFAULT, default) + fragment_list[#fragment_list + 1] = evolved.DEFAULT + component_list[#component_list + 1] = default end if construct ~= nil then - evolved.set(fragment, evolved.CONSTRUCT, construct) + fragment_list[#fragment_list + 1] = evolved.CONSTRUCT + component_list[#component_list + 1] = construct end + evolved.multi_set(fragment, fragment_list, component_list) + + __release_table(__TABLE_POOL_TAG__FRAGMENT_LIST, fragment_list) + __release_table(__TABLE_POOL_TAG__COMPONENT_LIST, component_list) + return fragment end @@ -3568,7 +3604,7 @@ function evolved_query_builder:include(...) local include_list = self.__include_list if not include_list then - include_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, 8, 0) + include_list = __table_new(math.max(8, fragment_count), 0) self.__include_list = include_list end @@ -3576,8 +3612,7 @@ function evolved_query_builder:include(...) for i = 1, fragment_count do local fragment = select(i, ...) - include_list[include_list_size + 1] = fragment - include_list_size = include_list_size + 1 + include_list[include_list_size + i] = fragment end return self @@ -3595,7 +3630,7 @@ function evolved_query_builder:exclude(...) local exclude_list = self.__exclude_list if not exclude_list then - exclude_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, 8, 0) + exclude_list = __table_new(math.max(8, fragment_count), 0) self.__exclude_list = exclude_list end @@ -3603,8 +3638,7 @@ function evolved_query_builder:exclude(...) for i = 1, fragment_count do local fragment = select(i, ...) - exclude_list[exclude_list_size + 1] = fragment - exclude_list_size = exclude_list_size + 1 + exclude_list[exclude_list_size + i] = fragment end return self @@ -3620,16 +3654,24 @@ function evolved_query_builder:build() local query = evolved.id() + local fragment_list = __acquire_table(__TABLE_POOL_TAG__FRAGMENT_LIST, 2, 0) + local component_list = __acquire_table(__TABLE_POOL_TAG__COMPONENT_LIST, 2, 0) + if include_list then - evolved.insert(query, evolved.INCLUDES, __table_unpack(include_list)) - __release_table(__TABLE_POOL_TAG__FRAGMENT_LIST, include_list) + fragment_list[#fragment_list + 1] = evolved.INCLUDES + component_list[#component_list + 1] = include_list end if exclude_list then - evolved.insert(query, evolved.EXCLUDES, __table_unpack(exclude_list)) - __release_table(__TABLE_POOL_TAG__FRAGMENT_LIST, exclude_list) + fragment_list[#fragment_list + 1] = evolved.EXCLUDES + component_list[#component_list + 1] = exclude_list end + evolved.multi_set(query, fragment_list, component_list) + + __release_table(__TABLE_POOL_TAG__FRAGMENT_LIST, fragment_list) + __release_table(__TABLE_POOL_TAG__COMPONENT_LIST, component_list) + return query end