From 0d08b8532a95bc0debb82eefba11976ba54385e8 Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 18 Mar 2021 19:56:25 +0100 Subject: [PATCH 1/6] -remove "SIMD" option from "compile_wasm.py" (new Emscripten hasn't that option) -removed some unnecessary variables -started C-API implemantation: * added C-API option to Meson (build included to main library) * refactored some code (moved some code form templates to final code, removed delegates from system) * moved templates outside EntityManager to make it possible to use in different functions --- c-api/meson.build | 7 + demos/compile_wasm.py | 2 +- meson.build | 11 +- meson_options.txt | 1 + source/bubel/ecs/manager.d | 1091 +++++++++++++++++++++++------------- source/bubel/ecs/system.d | 8 +- 6 files changed, 714 insertions(+), 406 deletions(-) create mode 100644 c-api/meson.build diff --git a/c-api/meson.build b/c-api/meson.build new file mode 100644 index 0000000..5e1e2cf --- /dev/null +++ b/c-api/meson.build @@ -0,0 +1,7 @@ +src += files( + 'manager.d' +) + +c_src = files( + 'test.c' +) \ No newline at end of file diff --git a/demos/compile_wasm.py b/demos/compile_wasm.py index 06d31ac..336221a 100644 --- a/demos/compile_wasm.py +++ b/demos/compile_wasm.py @@ -75,7 +75,7 @@ for arg in sys.argv[1:]: elif(arg == '-opt'): shared_flags += '-O3 ' ldc_flags += '-release -enable-inlining ' - emc_flags += '--llvm-lto 3 -s SIMD=1 ' + emc_flags += '--llvm-lto 3 ' elif(arg == '-quiet'): emc_flags += "-Wl,--no-check-features " elif(arg == '--clean'): diff --git a/meson.build b/meson.build index 0aff444..5b72d64 100644 --- a/meson.build +++ b/meson.build @@ -5,11 +5,13 @@ betterC_opt = get_option('betterC') BuildDemos_opt = get_option('BuildDemos') BuildTests_opt = get_option('BuildTests') LTO_otp = get_option('LTO') +C_API_opt = get_option('C-API') summary('betterC enabled', betterC_opt) summary('build demos', BuildDemos_opt) summary('build tests', BuildTests_opt) summary('LTO enabled', LTO_otp) +summary('C-API enabled', C_API_opt) meson_minimum_version = '>=0.57.1' assert(meson.version().version_compare(meson_minimum_version), 'Newer verson of meson required, current version: @0@, required: @1@'.format(meson.version(), meson_minimum_version)) @@ -18,7 +20,14 @@ assert(meson.version().version_compare(meson_minimum_version), 'Newer verson of src = files() subdir('source') -inc = include_directories('source/') +inc = [include_directories('source/')] + +#C API files +if C_API_opt + c_src = files() + subdir('c-api') + inc += include_directories('c-api/') +endif # Arguments args = [] diff --git a/meson_options.txt b/meson_options.txt index 335f32b..30f9c3d 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -2,3 +2,4 @@ option('betterC', type: 'boolean', value: false) option('BuildDemos', type: 'boolean', value: false) option('BuildTests', type: 'boolean', value: false) option('LTO', type: 'boolean', value: false) +option('C-API', type: 'boolean', value: false) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index e3ad7bc..6cba7e8 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -371,6 +371,8 @@ export struct EntityManager System system; system.m_pass = pass; + alias SystemData = SystemEntityData!Sys; + // static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) // { // static assert(0, "Add \"mixin ECS.System;\" in top of system structure;"); @@ -426,221 +428,9 @@ export struct EntityManager } } - static struct CompInfo - { - string name; - string type; - } + alias components_info = SystemData.components_info; - static struct ComponentsCounts - { - //one more than should be to prevent null arrays (zero length arrays) - uint readonly = 1; - uint mutable = 1; - uint excluded = 1; - uint optional = 1; - uint req = 1; - uint readonly_dep = 1; - uint writable_dep = 1; - } - - static ComponentsCounts getComponentsCounts() - { - ComponentsCounts components_counts; - - bool checkExcludedComponentsSomething(Sys)() - { - return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, - typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); - } - - foreach (member; __traits(allMembers, Sys.EntitiesData)) - { - alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); - if (member == "length" || member == "thread_id" || member == "job_id" - || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) - { - //continue; - } - else - { - string name; - static if (isArray!MemberType) - { // Workaround. This code is never called with: not an array type, but compiler prints an error - // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));//.stringof; - name = fullName!(Unqual!(ForeachType!MemberType)); - } - - bool is_optional; - bool is_read_only; - - if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) - { - is_read_only = true; - } - - foreach (att; __traits(getAttributes, __traits(getMember, - Sys.EntitiesData, member))) - { - if (att == "optional") - { - is_optional = true; - } - if (att == "readonly") - { - is_read_only = true; - } - } - if (is_read_only) - { - components_counts.readonly++; - } - else - { - components_counts.mutable++; - } - if (is_optional) - { - components_counts.optional++; - } - else - { - components_counts.req++; - } - } - } - - static if (__traits(hasMember, Sys, "ExcludedComponents")) - { - static if (is(Sys.ExcludedComponents == enum)) - { - foreach (str; __traits(allMembers, Sys.ExcludedComponents)) - { - components_counts.excluded++; - } - } - else //static if (checkExcludedComponentsSomething!Sys) - { - foreach (str; Sys.ExcludedComponents) - { - components_counts.excluded++; - } - } - } - - static if (__traits(hasMember, Sys, "ReadOnlyDependencies")) - { - foreach (str; Sys.ReadOnlyDependencies) - { - components_counts.readonly_dep++; - } - } - - static if (__traits(hasMember, Sys, "WritableDependencies")) - { - foreach (str; Sys.WritableDependencies) - { - components_counts.writable_dep++; - } - } - - return components_counts; - } - - enum ComponentsCounts component_counts = getComponentsCounts(); - - static struct ComponentsIndices(ComponentsCounts counts) - { - CompInfo[] readonly() - { - return m_readonly[0 .. m_readonly_counter]; - } - - CompInfo[] mutable() - { - return m_mutable[0 .. m_mutable_counter]; - } - - CompInfo[] excluded() - { - return m_excluded[0 .. m_excluded_counter]; - } - - CompInfo[] optional() - { - return m_optional[0 .. m_optional_counter]; - } - - CompInfo[] req() - { - return m_req[0 .. m_req_counter]; - } - - CompInfo[] readonlyDeps() - { - return m_readonly_dep[0 .. m_readonly_dep_counter]; - } - - CompInfo[] writableDeps() - { - return m_writable_dep[0 .. m_writable_dep_counter]; - } - - void addReadonly(CompInfo info) - { - m_readonly[m_readonly_counter++] = info; - } - - void addMutable(CompInfo info) - { - m_mutable[m_mutable_counter++] = info; - } - - void addExcluded(CompInfo info) - { - m_excluded[m_excluded_counter++] = info; - } - - void addOptional(CompInfo info) - { - m_optional[m_optional_counter++] = info; - } - - void addReq(CompInfo info) - { - m_req[m_req_counter++] = info; - } - - void addReadonlyDep(CompInfo info) - { - m_readonly_dep[m_readonly_dep_counter++] = info; - } - - void addWritableDep(CompInfo info) - { - m_writable_dep[m_writable_dep_counter++] = info; - } - - CompInfo[counts.readonly] m_readonly; - CompInfo[counts.mutable] m_mutable; - CompInfo[counts.excluded] m_excluded; - CompInfo[counts.optional] m_optional; - CompInfo[counts.req] m_req; - CompInfo[counts.readonly_dep] m_readonly_dep; - CompInfo[counts.writable_dep] m_writable_dep; - - uint m_readonly_counter; - uint m_mutable_counter; - uint m_excluded_counter; - uint m_optional_counter; - uint m_req_counter; - uint m_readonly_dep_counter; - uint m_writable_dep_counter; - - string entites_array; - } - - static void allocateSystemComponents(ComponentsIndices!component_counts components_info)( + static void allocateSystemComponents/*(ComponentsIndices!component_counts components_info)*/( ref System system) { size_t req = components_info.req.length; @@ -665,119 +455,8 @@ export struct EntityManager system.m_readonly_dependencies = Mallocator.makeArray!ushort(read_only_deps); if (writable_deps > 0) system.m_writable_dependencies = Mallocator.makeArray!ushort(writable_deps); - } - static ComponentsIndices!component_counts getComponentsInfo() - { - ComponentsIndices!component_counts components_info; - - bool checkExcludedComponentsSomething(Sys)() - { - return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, - typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); - } - - foreach (member; __traits(allMembers, Sys.EntitiesData)) - { - alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); - if (member == "length" || member == "thread_id" || member == "job_id" - || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) - { - if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) - components_info.entites_array = member; - //continue; - } - else - { - string name; - static if (isArray!MemberType) - { // Workaround. This code is never called with: not an array type, but compiler prints an error - // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType)); - name = fullName!(Unqual!(ForeachType!MemberType)); - //name = Unqual!(ForeachType!MemberType).stringof; - } - - bool is_optional; - bool is_read_only; - - if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) - { - is_read_only = true; - } - - foreach (att; __traits(getAttributes, __traits(getMember, - Sys.EntitiesData, member))) - { - if (att == "optional") - { - is_optional = true; - } - if (att == "readonly") - { - is_read_only = true; - } - } - if (is_read_only) - { - components_info.addReadonly(CompInfo(member, name)); - } - else - { - components_info.addMutable(CompInfo(member, name)); - } - if (is_optional) - { - components_info.addOptional(CompInfo(member, name)); - } - else - { - components_info.addReq(CompInfo(member, name)); - } - } - } - - static if (__traits(hasMember, Sys, "ExcludedComponents")) - { - static if (is(Sys.ExcludedComponents == enum)) - { - foreach (str; __traits(allMembers, Sys.ExcludedComponents)) - { - components_info.addExcluded(CompInfo(str, str)); - } - } - else //static if (checkExcludedComponentsSomething!Sys) - { - foreach (str; Sys.ExcludedComponents) - { - components_info.addExcluded(CompInfo(str.stringof, fullName!str)); - // components_info.addExcluded(CompInfo(str.stringof, str.stringof)); - } - - } - } - - static if (__traits(hasMember, Sys, "ReadOnlyDependencies")) - { - foreach (str; Sys.ReadOnlyDependencies) - { - components_info.addReadonlyDep(CompInfo(str, str)); - } - } - - static if (__traits(hasMember, Sys, "WritableDependencies")) - { - foreach (str; Sys.WritableDependencies) - { - components_info.addWritableDep(CompInfo(str, str)); - } - } - - return components_info; - } - - enum ComponentsIndices!component_counts components_info = getComponentsInfo(); - static void genCompList(ref System system, ref HashMap!(char[], ushort) components_map) { @@ -813,7 +492,7 @@ export struct EntityManager } //enum ComponentsIndices components_info = getComponentsInfo(); - allocateSystemComponents!(components_info)(system); + allocateSystemComponents(system); foreach (iii, comp_info; components_info.req) { @@ -877,50 +556,34 @@ export struct EntityManager } } - static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, + struct InputData + { + uint length; + uint thread_id; + uint job_id; + //this struct containt multiple data pointers in linear memory (e.g. data_pointer+1 may be valid) + void* data_pointer; + } + + static void fillInputData_dyn(ref InputData input_data, EntityInfo* info, EntitiesBlock* block, uint offset, uint entities_count, System* system) { - //enum ComponentsIndices components_info = getComponentsInfo(); - - static if (components_info.entites_array) + input_data.length = entities_count; + // input_data.thread_id = 0; + foreach(size_t i, ushort component; system.m_components) { - __traits(getMember, input_data, components_info.entites_array) = ( - cast(Entity*) block.dataBegin())[offset .. entities_count]; + *(&input_data.data_pointer + i) = cast(void*) block + info.deltas[component] + offset * gEntityManager.components[component].size; } - static if (hasMember!(Sys.EntitiesData, "length")) + foreach(size_t i, ushort component; system.m_optional_components) { - input_data.length = cast(typeof(input_data.length))(entities_count - offset); + if(component < info.deltas.length && info.deltas[component] != 0)*(&input_data.data_pointer + i + system.m_components.length) = cast(void*) block + info.deltas[component] + offset * gEntityManager.components[component].size; } + } - /*static if (hasMember!(Sys.EntitiesData, "thread_id")) - { - input_data.thread_id = cast(typeof(input_data.thread_id))threadID(); - }//*/ - - ///FIXME: should be "components_info.req()" but it's not compile with GCC - static foreach (iii, comp_info; components_info.m_req[0 - .. components_info.m_req_counter]) - { - __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, - Sys.EntitiesData, comp_info.name)))*)( - cast(void*) block + info.deltas[system.m_components[iii]]))[offset - .. entities_count]; - } - - static foreach (iii, comp_info; components_info.m_optional[0 - .. components_info.m_optional_counter]) - { - if (system.m_optional_components[iii] < info.deltas.length - && info.deltas[system.m_optional_components[iii]] != 0) - { - __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, - Sys.EntitiesData, comp_info.name)))*)(cast( - void*) block + info.deltas[system.m_optional_components[iii]]))[offset - .. entities_count]; - - } - } + static void fillEntitiesData(ref Sys.EntitiesData entities_data, ref InputData input_data) + { + } /*bool checkOnUpdateParams() @@ -964,9 +627,9 @@ export struct EntityManager static if (OnUpdateOverloadNum != -1) { - static if (!IsEmpty) - { - static void callUpdate(ref CallData data) + //static if (!IsEmpty) + //{ + /*static void callUpdate(ref CallData data) { Sys* s = cast(Sys*) data.system.m_system_pointer; @@ -1019,29 +682,46 @@ export struct EntityManager input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; } - //s.onUpdate(input_data); - (cast(typeof(&__traits(getOverloads, s, - "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)( - input_data); + if(data.context) (*cast(void delegate(Sys.EntitiesData)*)data.context)(input_data); + else s.onUpdate(input_data); } block = block.next_block; offset = 0; blocks--; } - } - } - else - { - static void callUpdate(ref CallData data) + }*/ + + static void callUpdate(SystemCallData* data) { - Sys* s = cast(Sys*) data.system.m_system_pointer; + Sys* s = cast(Sys*) data.system_pointer; Sys.EntitiesData input_data; + // EntityInfo* info = data.block.type_info; //block.type_info; + //System* system = data.system; - /*static if (hasMember!(Sys.EntitiesData, "length")) + static if (!IsEmpty)SystemData.fillInputData(input_data, data.info, data.block, data.begin, data.count);//, system); + + static if (hasMember!(Sys.EntitiesData, "thread_id")) { - input_data.length = 0; - }//*/ + input_data.thread_id = cast( + typeof(input_data.thread_id)) data.thread_id; + } + + static if (hasMember!(Sys.EntitiesData, "job_id")) + { + input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; + } + + s.onUpdate(input_data); + } + /*} + else + {*/ + /*static void callUpdate(SystemCallData data) + { + Sys* s = cast(Sys*) data.system_pointer; + + Sys.EntitiesData input_data; static if (hasMember!(Sys.EntitiesData, "thread_id")) { @@ -1053,10 +733,27 @@ export struct EntityManager input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; } - (cast(typeof(&__traits(getOverloads, s, - "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); - } - } + s.onUpdate(input_data); + }*/ + /*static void callUpdate(ref CallData data) + { + Sys* s = cast(Sys*) data.system.m_system_pointer; + + Sys.EntitiesData input_data; + + static if (hasMember!(Sys.EntitiesData, "thread_id")) + { + input_data.thread_id = cast(typeof(input_data.thread_id)) data.thread_id; + } + + static if (hasMember!(Sys.EntitiesData, "job_id")) + { + input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; + } + + s.onUpdate(input_data); + }*/ + // } system.m_update = &callUpdate; } @@ -1099,8 +796,8 @@ export struct EntityManager { Sys* s = cast(Sys*) data.system.m_system_pointer; Sys.EntitiesData input_data; - fillInputData(input_data, data.block.type_info, - data.block, data.begin, data.end, data.system); + SystemData.fillInputData(input_data, data.block.type_info, + data.block, data.begin, data.end);//, data.system); static if (is(RetTyp == void)) mixin("s." ~ func_name ~ "(input_data)"); else @@ -1160,12 +857,12 @@ export struct EntityManager static if(__traits(hasMember, Sys ,"__becs_jobs_count"))system.jobs = Mallocator.makeArray!(Job)(Sys.__becs_jobs_count); else system.jobs = Mallocator.makeArray!(Job)(32); - static if (OnUpdateOverloadNum != -1) + /*static if (OnUpdateOverloadNum != -1) { Sys* s = cast(Sys*) system.m_system_pointer; system.m_update_delegate = cast(void delegate())&__traits(getOverloads, s, "onUpdate")[OnUpdateOverloadNum]; - } + }*/ genCompList(system, components_map); @@ -1229,6 +926,41 @@ export struct EntityManager becsID!Sys = system.id; } + export ushort registerSystem(const (char)[] name, System system) + { + ushort sys_id = systems_map.get(cast(char[]) name, ushort.max); + if (sys_id < systems.length) + { + system.m_name = systems[sys_id].m_name; + systems[sys_id].m_name = null; + systems[sys_id].destroy(); + + if (system.m_create) + (cast(void function(void*)) system.m_create)(system.m_system_pointer); + + system.enable(); + + system.m_id = sys_id; + systems[sys_id] = system; + } + else + { + system.m_name = Mallocator.makeArray(cast(char[]) name); + + systems_map.add(system.m_name, cast(ushort) systems.length); + + system.m_id = cast(ushort)(systems.length); + + systems.add(system); + + if (system.m_create) + (cast(void function(void*)) system.m_create)(system.m_system_pointer); + + systems[$ - 1].enable(); + } + return system.m_id; + } + /************************************************************************************************************************ Return system ECS api by id */ @@ -1312,7 +1044,7 @@ export struct EntityManager info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof); *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); - ushort comp_id = components_map.get(cast(char[]) ComponentName, ushort.max); + /*ushort comp_id = components_map.get(cast(char[]) ComponentName, ushort.max); if (comp_id < components.length) { becsID!Comp = comp_id; @@ -1326,7 +1058,29 @@ export struct EntityManager becsID!Comp = cast(ushort)(components.length - 1); char[] name = Mallocator.makeArray(cast(char[]) ComponentName); components_map.add(name, cast(ushort)(components.length - 1)); + }*/ + becsID!Comp = registerComponent(ComponentName, info); + } + + ushort registerComponent(const (char)[] name, ComponentInfo info) + { + ushort comp_id = components_map.get(cast(char[]) name, ushort.max); + if (comp_id < components.length) + { + // becsID!Comp = comp_id; + if (components[comp_id].init_data) + Mallocator.dispose(components[comp_id].init_data); + components[comp_id] = info; } + else + { + components.add(info); + // becsID!Comp = cast(ushort)(components.length - 1); + comp_id = cast(ushort)(components.length - 1); + char[] name_copy = Mallocator.makeArray(cast(char[]) name); + components_map.add(name_copy, cast(ushort)(components.length - 1)); + } + return comp_id; } void registerEvent(Ev)() @@ -1388,9 +1142,46 @@ export struct EntityManager if (!system.m_any_system_caller) return; + /* struct Delegate + { + void* context; + void* func; + }*/ + + /*static void fillInputData_dyn(ref Sys.EntitiesData input_data, EntityInfo* info, + EntitiesBlock* block, uint offset, uint entities_count) + { + System* system = gEntityManager.getSystem(becsID!Sys); + input_data.length = cast(typeof(input_data.length))entities_count; + // input_data.thread_id = 0; + foreach(size_t i, ushort component; system.m_components) + { + *(&block.data_pointer + i) = cast(void*) block + info.deltas[component] + offset * gEntityManager.components[component].size; + } + + foreach(size_t i, ushort component; system.m_optional_components) + { + if(component < info.deltas.length && info.deltas[component] != 0)*(&input_data.data_pointer + i + system.m_components.length) = cast(void*) block + info.deltas[component] + offset * gEntityManager.components[component].size; + } + }*/ + + static void callUpdate(SystemCallData* data) + { + //Sys* s = cast(Sys*) data.system_pointer; + Sys.EntitiesData input_data; + EntityInfo* info = data.info; + + alias SystemData = SystemEntityData!Sys; + SystemData.fillInputData(input_data, info, data.block, data.begin, data.count); + //fillInputData(input_data, info, data.block, data.begin, data.end - data.begin); + //fillInputData_dyn(input_data, info, data.block, data.begin, data.end - data.begin); + + (*cast(void delegate(Sys.EntitiesData)*)data.context)(input_data); + } + foreach (info; system.m_any_system_caller.infos) { - CallData data = CallData(system.id, system, info, cast(void delegate()) func); + CallData data = CallData(system.id, system, info, cast(void*)&func, cast(void*)&callUpdate); data.update(); } } @@ -1419,14 +1210,14 @@ export struct EntityManager { if (sys.m_empty) { - CallData data = CallData(caller.system_id, sys, null, sys.m_update_delegate); + CallData data = CallData(caller.system_id, sys, null, null, sys.m_update); data.update(); } else foreach (info; caller.infos) { CallData data = CallData(caller.system_id, sys, info, - sys.m_update_delegate); + null, sys.m_update); data.update(); } } @@ -1472,7 +1263,7 @@ export struct EntityManager if (sys.m_empty) { - tmp_datas.add(CallData(caller.system_id, sys, null, sys.m_update_delegate)); + tmp_datas.add(CallData(caller.system_id, sys, null, null, sys.m_update)); nextJob(); caller.job_group.jobs = sys.jobs[0 .. 1]; (cast(void delegate(JobGroup) nothrow @nogc) m_dispatch_jobs)(caller.job_group); @@ -1537,7 +1328,7 @@ export struct EntityManager assert(entities_per_job == full_blocks_count * info.max_entities + entities_count + ( first_block.entities_count - first_elem)); CallData data = CallData(caller.system_id, sys, - info, sys.m_update_delegate, first_block, + info, null, sys.m_update, first_block, cast(ushort)(full_blocks_count + 1), cast(ushort) first_elem, 0); tmp_datas.add(data); @@ -1553,7 +1344,7 @@ export struct EntityManager assert(last_elem > 0); assert(last_elem <= block.entities_count); CallData data = CallData(caller.system_id, sys, - info, sys.m_update_delegate, first_block, + info, null, sys.m_update, first_block, cast(ushort)(full_blocks_count + 2), cast(ushort) first_elem, cast(ushort) last_elem); tmp_datas.add(data); @@ -1572,7 +1363,7 @@ export struct EntityManager uint last_elem = entities_per_job - entities_count; assert(last_elem > 0); CallData data = CallData(caller.system_id, sys, - info, sys.m_update_delegate, first_block, 1, + info, null, sys.m_update, first_block, 1, cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); tmp_datas.add(data); first_elem += last_elem; @@ -1592,7 +1383,7 @@ export struct EntityManager else { //take whole info blocks - CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate, + CallData data = CallData(caller.system_id, sys, info, null, sys.m_update, first_block, cast(ushort) blocks_count, cast(ushort) first_elem); tmp_datas.add(data); entities_count += (blocks_count - 1) * info.max_entities @@ -3331,9 +3122,9 @@ export struct EntityManager */ struct ComponentInfo { - export ~this() nothrow @nogc + /*export ~this() nothrow @nogc { - } + }*/ ///Component size ushort size; ///Component data alignment @@ -3604,7 +3395,65 @@ export struct EntityManager { export void update() nothrow @nogc { - (cast(SytemFuncType) system.m_update)(this); + //(cast(SytemFuncType) system.m_update)(this); + if(!system.m_empty) + { + // Sys* s = cast(Sys*) system.m_system_pointer; + + //Sys.EntitiesData input_data; + // EntityInfo* info = info; //block.type_info; + // System* system = system; + + EntitiesBlock* block; + if (first_block) + block = first_block; + else + block = info.first_block; + + uint offset = begin; + uint last_entity; + uint blocks; + if (blocks_count) + blocks = blocks_count; + else + blocks = uint.max; + + SystemCallData call_data = SystemCallData(0, thread_id, job_id, system.m_system_pointer, context, info); + + while (block !is null && blocks > 0) + { + if (blocks == 1) + { + if (end) + last_entity = end; + else + last_entity = block.entities_count; + } + else + last_entity = block.entities_count; + + if (last_entity > 0) + { + call_data.block = block; + call_data.begin = offset; + call_data.count = last_entity - offset; + + assert(last_entity <= block.entities_count + && offset < block.entities_count); + assert(last_entity > offset); + + (cast(void function(SystemCallData*) @nogc nothrow) update_func)(&call_data); + } + block = block.next_block; + offset = 0; + blocks--; + } + } + else + { + SystemCallData call_data = SystemCallData(0, thread_id, job_id, system.m_system_pointer, context, info); + (cast(void function(SystemCallData*) @nogc nothrow) update_func)(&call_data); + } } ///system ID. Used to update system pointer after system reload. @@ -3614,12 +3463,14 @@ export struct EntityManager ///poiner to Entity type info EntityManager.EntityInfo* info; ///delegate function to call (by default it's delegate to onUpdate call) - void delegate() update_delegate; + void* context; + void* update_func; + //void delegate() update_delegate; ///pointer to first block into process (if 0 then first block will be used) EntitiesBlock* first_block; ///number of blocks to update (if 0 then update all) - ushort blocks; + ushort blocks_count; ///index of first element in first block ushort begin; ///index of last element in last block @@ -3630,6 +3481,24 @@ export struct EntityManager uint job_id; } + /************************************************************************************************************************ + Structure with data used to call single System call. + + first_block, begin, end, blocks parameters are used + to call partial info update + */ + struct SystemCallData + { + uint count; + uint thread_id; + uint job_id; + void* system_pointer; + void* context; + EntityInfo* info; + EntitiesBlock* block; + uint begin; + } + struct ListenerCallData { System* system; @@ -3853,3 +3722,425 @@ export struct EntityManager } } + +/*static void fillInputData(Sys)(ref Sys.EntitiesData input_data, EntityManager.EntityInfo* info, + EntityManager.EntitiesBlock* block, uint offset, uint entities_count)//, System* system) +{ + //enum ComponentsIndices components_info = getComponentsInfo(); + + static if (components_info.entites_array) + { + __traits(getMember, input_data, components_info.entites_array) = ( + cast(Entity*) block.dataBegin())[offset .. entities_count]; + } + + static if (hasMember!(Sys.EntitiesData, "length")) + { + input_data.length = cast(typeof(input_data.length))(entities_count - offset); + } + + // static if (hasMember!(Sys.EntitiesData, "thread_id")) + // { + // input_data.thread_id = cast(typeof(input_data.thread_id))threadID(); + // } + + ///FIXME: should be "components_info.req()" but it's not compile with GCC + static foreach(comp; __traits(Stru)) + static foreach (iii, comp_info; components_info.m_req[0 + .. components_info.m_req_counter]) + { + __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, + Sys.EntitiesData, comp_info.name)))*)( + cast(void*) block + info.deltas[becsID!(typeof(__traits(getMember, Sys.EntitiesData, comp_info.name)))]))[offset + .. entities_count]; + } + + static foreach (iii, comp_info; components_info.m_optional[0 + .. components_info.m_optional_counter]) + { + ushort system_id = becsID!(typeof(__traits(getMember, Sys.EntitiesData, comp_info.name))); + if (system_id < info.deltas.length + && info.deltas[system_id] != 0) + { + __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, + Sys.EntitiesData, comp_info.name)))*)(cast( + void*) block + info.deltas[system_id]))[offset + .. entities_count]; + + } + } +}*/ + +struct SystemEntityData(Sys) +{ + static struct CompInfo + { + string name; + string type; + } + + static struct ComponentsCounts + { + //one more than should be to prevent null arrays (zero length arrays) + uint readonly = 1; + uint mutable = 1; + uint excluded = 1; + uint optional = 1; + uint req = 1; + uint readonly_dep = 1; + uint writable_dep = 1; + } + + static ComponentsCounts getComponentsCounts() + { + ComponentsCounts components_counts; + + bool checkExcludedComponentsSomething(Sys)() + { + return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, + typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); + } + + foreach (member; __traits(allMembers, Sys.EntitiesData)) + { + alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); + if (member == "length" || member == "thread_id" || member == "job_id" + || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + { + //continue; + } + else + { + string name; + static if (isArray!MemberType) + { // Workaround. This code is never called with: not an array type, but compiler prints an error + // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));//.stringof; + name = fullName!(Unqual!(ForeachType!MemberType)); + } + + bool is_optional; + bool is_read_only; + + if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) + { + is_read_only = true; + } + + foreach (att; __traits(getAttributes, __traits(getMember, + Sys.EntitiesData, member))) + { + if (att == "optional") + { + is_optional = true; + } + if (att == "readonly") + { + is_read_only = true; + } + } + if (is_read_only) + { + components_counts.readonly++; + } + else + { + components_counts.mutable++; + } + if (is_optional) + { + components_counts.optional++; + } + else + { + components_counts.req++; + } + } + } + + static if (__traits(hasMember, Sys, "ExcludedComponents")) + { + static if (is(Sys.ExcludedComponents == enum)) + { + foreach (str; __traits(allMembers, Sys.ExcludedComponents)) + { + components_counts.excluded++; + } + } + else //static if (checkExcludedComponentsSomething!Sys) + { + foreach (str; Sys.ExcludedComponents) + { + components_counts.excluded++; + } + } + } + + static if (__traits(hasMember, Sys, "ReadOnlyDependencies")) + { + foreach (str; Sys.ReadOnlyDependencies) + { + components_counts.readonly_dep++; + } + } + + static if (__traits(hasMember, Sys, "WritableDependencies")) + { + foreach (str; Sys.WritableDependencies) + { + components_counts.writable_dep++; + } + } + + return components_counts; + } + + enum ComponentsCounts component_counts = getComponentsCounts(); + + static struct ComponentsIndices(ComponentsCounts counts) + { + CompInfo[] readonly() + { + return m_readonly[0 .. m_readonly_counter]; + } + + CompInfo[] mutable() + { + return m_mutable[0 .. m_mutable_counter]; + } + + CompInfo[] excluded() + { + return m_excluded[0 .. m_excluded_counter]; + } + + CompInfo[] optional() + { + return m_optional[0 .. m_optional_counter]; + } + + CompInfo[] req() + { + return m_req[0 .. m_req_counter]; + } + + CompInfo[] readonlyDeps() + { + return m_readonly_dep[0 .. m_readonly_dep_counter]; + } + + CompInfo[] writableDeps() + { + return m_writable_dep[0 .. m_writable_dep_counter]; + } + + void addReadonly(CompInfo info) + { + m_readonly[m_readonly_counter++] = info; + } + + void addMutable(CompInfo info) + { + m_mutable[m_mutable_counter++] = info; + } + + void addExcluded(CompInfo info) + { + m_excluded[m_excluded_counter++] = info; + } + + void addOptional(CompInfo info) + { + m_optional[m_optional_counter++] = info; + } + + void addReq(CompInfo info) + { + m_req[m_req_counter++] = info; + } + + void addReadonlyDep(CompInfo info) + { + m_readonly_dep[m_readonly_dep_counter++] = info; + } + + void addWritableDep(CompInfo info) + { + m_writable_dep[m_writable_dep_counter++] = info; + } + + CompInfo[counts.readonly] m_readonly; + CompInfo[counts.mutable] m_mutable; + CompInfo[counts.excluded] m_excluded; + CompInfo[counts.optional] m_optional; + CompInfo[counts.req] m_req; + CompInfo[counts.readonly_dep] m_readonly_dep; + CompInfo[counts.writable_dep] m_writable_dep; + + uint m_readonly_counter; + uint m_mutable_counter; + uint m_excluded_counter; + uint m_optional_counter; + uint m_req_counter; + uint m_readonly_dep_counter; + uint m_writable_dep_counter; + + string entites_array; + } + + enum ComponentsIndices!component_counts components_info = getComponentsInfo(); + + static ComponentsIndices!component_counts getComponentsInfo() + { + ComponentsIndices!component_counts components_info; + + bool checkExcludedComponentsSomething(Sys)() + { + return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, + typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); + } + + foreach (member; __traits(allMembers, Sys.EntitiesData)) + { + alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); + if (member == "length" || member == "thread_id" || member == "job_id" + || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + { + if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + components_info.entites_array = member; + //continue; + } + else + { + string name; + static if (isArray!MemberType) + { // Workaround. This code is never called with: not an array type, but compiler prints an error + // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType)); + name = fullName!(Unqual!(ForeachType!MemberType)); + //name = Unqual!(ForeachType!MemberType).stringof; + } + + bool is_optional; + bool is_read_only; + + if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int))) + { + is_read_only = true; + } + + foreach (att; __traits(getAttributes, __traits(getMember, + Sys.EntitiesData, member))) + { + if (att == "optional") + { + is_optional = true; + } + if (att == "readonly") + { + is_read_only = true; + } + } + if (is_read_only) + { + components_info.addReadonly(CompInfo(member, name)); + } + else + { + components_info.addMutable(CompInfo(member, name)); + } + if (is_optional) + { + components_info.addOptional(CompInfo(member, name)); + } + else + { + components_info.addReq(CompInfo(member, name)); + } + } + } + + static if (__traits(hasMember, Sys, "ExcludedComponents")) + { + static if (is(Sys.ExcludedComponents == enum)) + { + foreach (str; __traits(allMembers, Sys.ExcludedComponents)) + { + components_info.addExcluded(CompInfo(str, str)); + } + } + else //static if (checkExcludedComponentsSomething!Sys) + { + foreach (str; Sys.ExcludedComponents) + { + components_info.addExcluded(CompInfo(str.stringof, fullName!str)); + // components_info.addExcluded(CompInfo(str.stringof, str.stringof)); + } + + } + } + + static if (__traits(hasMember, Sys, "ReadOnlyDependencies")) + { + foreach (str; Sys.ReadOnlyDependencies) + { + components_info.addReadonlyDep(CompInfo(str, str)); + } + } + + static if (__traits(hasMember, Sys, "WritableDependencies")) + { + foreach (str; Sys.WritableDependencies) + { + components_info.addWritableDep(CompInfo(str, str)); + } + } + + return components_info; + } + + static void fillInputData(ref Sys.EntitiesData input_data, EntityManager.EntityInfo* info, + EntityManager.EntitiesBlock* block, uint offset, uint entities_count)//, System* system) + { + //enum ComponentsIndices components_info = getComponentsInfo(); + uint last_entity = entities_count + offset; + + static if (components_info.entites_array) + { + __traits(getMember, input_data, components_info.entites_array) = ( + cast(Entity*) block.dataBegin())[offset .. last_entity]; + } + + static if (hasMember!(Sys.EntitiesData, "length")) + { + input_data.length = cast(typeof(input_data.length))(entities_count); + } + + // static if (hasMember!(Sys.EntitiesData, "thread_id")) + // { + // input_data.thread_id = cast(typeof(input_data.thread_id))threadID(); + // } + + ///FIXME: should be "components_info.req()" but it's not compile with GCC + static foreach (iii, comp_info; components_info.m_req[0 + .. components_info.m_req_counter]) + { + __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, + Sys.EntitiesData, comp_info.name)))*)( + cast(void*) block + info.deltas[becsID!(ForeachType!(typeof(__traits(getMember, Sys.EntitiesData, comp_info.name))))]))[offset + .. last_entity]; + } + + static foreach (iii, comp_info; components_info.m_optional[0 + .. components_info.m_optional_counter]) + { + if (becsID!(ForeachType!(typeof(__traits(getMember, Sys.EntitiesData, comp_info.name)))) < info.deltas.length + && info.deltas[becsID!(ForeachType!(typeof(__traits(getMember, Sys.EntitiesData, comp_info.name))))] != 0) + { + __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, + Sys.EntitiesData, comp_info.name)))*)(cast( + void*) block + info.deltas[becsID!(ForeachType!(typeof(__traits(getMember, Sys.EntitiesData, comp_info.name))))]))[offset + .. last_entity]; + + } + } + } +} \ No newline at end of file diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index e571e8b..256841d 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -89,7 +89,7 @@ struct System return cast(const(char)[]) m_name; } -package: +//package: void destroy() { @@ -170,7 +170,7 @@ package: //void function(ref EntityManager.CallData data) m_update; void* m_update; ///workaroud for DMD bug with upper line - void delegate() m_update_delegate; + //void delegate() m_update_delegate; //void function(void* system_pointer) m_enable; //void function(void* system_pointer) m_disable; @@ -198,6 +198,6 @@ package: //void function(ref EntityManager.CallData data) m_initialize; //void function(ref EntityManager.CallData data) m_deinitilize; - void* m_initialize; - void* m_deinitilize; + // void* m_initialize; + // void* m_deinitilize; } From 70a5388820e077e16de2f0ae9fc49ac1e851bc22 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 24 Mar 2021 18:35:03 +0100 Subject: [PATCH 2/6] -move code from templates to ECS side: *sendEvent - using EventRef (alias to ComponentRef) *ListenerCallData now contain entities count and pointer to EntityInfo *Remove system_pointer from SystemCallData (use context instead) *Register event -Now all BECS functinality can be used without templates -clean code --- meson.build | 20 ++- source/bubel/ecs/events.d | 16 +- source/bubel/ecs/manager.d | 329 +++++++++---------------------------- tests/basic.d | 2 + tests/tests.d | 20 ++- 5 files changed, 126 insertions(+), 261 deletions(-) diff --git a/meson.build b/meson.build index 5b72d64..48e3007 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('decs', 'd', version : '0.5.0') +project('decs', 'd', version : '0.1.0') # Options betterC_opt = get_option('betterC') @@ -78,6 +78,24 @@ decs_dep = declare_dependency( # Tests if BuildTests_opt subdir('tests') + + executable('d-api-tests', + ['tests/tests.d'], + include_directories : [inc], + d_args : args, + link_args : link_args, + dependencies : decs_dep, + ) + + if C_API_opt + add_languages('c') + executable('c-api-tests', + ['c-api/test.c'], + include_directories : [inc], + dependencies : decs_dep, + ) + endif + endif # Demos diff --git a/source/bubel/ecs/events.d b/source/bubel/ecs/events.d index 7cb0d0c..fdf02dc 100644 --- a/source/bubel/ecs/events.d +++ b/source/bubel/ecs/events.d @@ -8,6 +8,8 @@ import bubel.ecs.traits : becsID; import std.algorithm.comparison : max; +alias EventRef = ComponentRef; + package struct EventManager { @@ -30,12 +32,17 @@ package struct EventManager } export void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) nothrow @nogc + { + sendEvent(id, EventRef(&event, becsID!Ev), thread_id); + } + + export void sendEvent(EntityID id, EventRef event, uint thread_id = 0) nothrow @nogc { uint block_id = current_index + thread_id; - EventData* data = &events[becsID!Ev]; + EventData* data = &events[event.component_id]; EventBlock* block = data.blocks[block_id]; - //EntityManager.EventInfo* info = &manager.events[Ev.event_id]; + EntityManager.EventInfo* info = &manager.events[event.component_id]; //event.entity_id = id; if (block is null) @@ -61,10 +68,11 @@ package struct EventManager data.blocks[block_id] = block; } - uint size = Ev.sizeof + EntityID.sizeof; + uint size = info.size + EntityID.sizeof; void* ptr = cast(void*) block + data.data_offset + block.count * size; *cast(EntityID*)ptr = id; - *cast(Ev*)(ptr + EntityID.sizeof) = event; + memcpy(ptr + EntityID.sizeof, event.ptr, info.size); + //*cast(Ev*)(ptr + EntityID.sizeof) = event; //Ev* event_array = cast(Ev*)(cast(void*) block + data.data_offset); //event_array[block.count] = event; block.count++; diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 6cba7e8..ee7b9be 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -105,8 +105,6 @@ export struct EntityManager foreach (EntityInfo* info; &entities_infos.byValue) { - //if(info.components)Mallocator.dispose(info.components); - Mallocator.dispose(info); } @@ -364,20 +362,13 @@ export struct EntityManager else assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); - // enum SystemName = fullyQualifiedName!Sys; enum SystemName = fullName!Sys; - //enum SystemName = Sys.stringof; System system; system.m_pass = pass; alias SystemData = SystemEntityData!Sys; - // static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) - // { - // static assert(0, "Add \"mixin ECS.System;\" in top of system structure;"); - // } - static if (!(hasMember!(Sys, "EntitiesData"))) { static assert(0, "System should gave \"EntitiesData\" struct for input components"); @@ -407,7 +398,6 @@ export struct EntityManager { alias EventParamType = Params[1]; enum EventName = fullName!(Unqual!(EventParamType)); - // enum EventName = fullyQualifiedName!(Unqual!(EventParamType));//.stringof; ushort evt = events_map.get(cast(char[]) EventName, ushort.max); assert(evt != ushort.max, "Can't register system \"" ~ SystemName @@ -556,50 +546,6 @@ export struct EntityManager } } - struct InputData - { - uint length; - uint thread_id; - uint job_id; - //this struct containt multiple data pointers in linear memory (e.g. data_pointer+1 may be valid) - void* data_pointer; - } - - static void fillInputData_dyn(ref InputData input_data, EntityInfo* info, - EntitiesBlock* block, uint offset, uint entities_count, System* system) - { - input_data.length = entities_count; - // input_data.thread_id = 0; - foreach(size_t i, ushort component; system.m_components) - { - *(&input_data.data_pointer + i) = cast(void*) block + info.deltas[component] + offset * gEntityManager.components[component].size; - } - - foreach(size_t i, ushort component; system.m_optional_components) - { - if(component < info.deltas.length && info.deltas[component] != 0)*(&input_data.data_pointer + i + system.m_components.length) = cast(void*) block + info.deltas[component] + offset * gEntityManager.components[component].size; - } - } - - static void fillEntitiesData(ref Sys.EntitiesData entities_data, ref InputData input_data) - { - - } - - /*bool checkOnUpdateParams() - { - bool ret = false; - foreach (func; __traits(getOverloads, Sys, "onUpdate")) - { - if ((Parameters!(func)).length == 1 && is(Parameters!(func)[0] == Sys.EntitiesData)) - { - ret = true; - break; - } - } - return ret; - }*/ - int getOnUpdateOverload()() { int ret = -1; @@ -627,133 +573,27 @@ export struct EntityManager static if (OnUpdateOverloadNum != -1) { - //static if (!IsEmpty) - //{ - /*static void callUpdate(ref CallData data) + static void callUpdate(SystemCallData* data) + { + Sys* s = cast(Sys*) data.context; + + Sys.EntitiesData input_data; + + static if (!IsEmpty)SystemData.fillInputData(input_data, data.info, data.block, data.begin, data.count);//, system); + + static if (hasMember!(Sys.EntitiesData, "thread_id")) { - Sys* s = cast(Sys*) data.system.m_system_pointer; - - Sys.EntitiesData input_data; - EntityInfo* info = data.info; //block.type_info; - System* system = data.system; - - EntitiesBlock* block; - if (data.first_block) - block = data.first_block; - else - block = info.first_block; - - uint offset = data.begin; - uint entities_count; - uint blocks; - if (data.blocks) - blocks = data.blocks; - else - blocks = uint.max; - - while (block !is null && blocks > 0) - { - if (blocks == 1) - { - if (data.end) - entities_count = data.end; - else - entities_count = block.entities_count; - } - else - entities_count = block.entities_count; - - if (entities_count > 0) - { - assert(entities_count <= block.entities_count - && offset < block.entities_count); - assert(entities_count > offset); - - fillInputData(input_data, info, block, offset, entities_count, system); - - static if (hasMember!(Sys.EntitiesData, "thread_id")) - { - input_data.thread_id = cast( - typeof(input_data.thread_id)) data.thread_id; - } - - static if (hasMember!(Sys.EntitiesData, "job_id")) - { - input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; - } - - if(data.context) (*cast(void delegate(Sys.EntitiesData)*)data.context)(input_data); - else s.onUpdate(input_data); - } - block = block.next_block; - offset = 0; - blocks--; - } - }*/ - - static void callUpdate(SystemCallData* data) - { - Sys* s = cast(Sys*) data.system_pointer; - - Sys.EntitiesData input_data; - // EntityInfo* info = data.block.type_info; //block.type_info; - //System* system = data.system; - - static if (!IsEmpty)SystemData.fillInputData(input_data, data.info, data.block, data.begin, data.count);//, system); - - static if (hasMember!(Sys.EntitiesData, "thread_id")) - { - input_data.thread_id = cast( - typeof(input_data.thread_id)) data.thread_id; - } - - static if (hasMember!(Sys.EntitiesData, "job_id")) - { - input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; - } - - s.onUpdate(input_data); + input_data.thread_id = cast( + typeof(input_data.thread_id)) data.thread_id; } - /*} - else - {*/ - /*static void callUpdate(SystemCallData data) + + static if (hasMember!(Sys.EntitiesData, "job_id")) { - Sys* s = cast(Sys*) data.system_pointer; + input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; + } - Sys.EntitiesData input_data; - - static if (hasMember!(Sys.EntitiesData, "thread_id")) - { - input_data.thread_id = cast(typeof(input_data.thread_id)) data.thread_id; - } - - static if (hasMember!(Sys.EntitiesData, "job_id")) - { - input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; - } - - s.onUpdate(input_data); - }*/ - /*static void callUpdate(ref CallData data) - { - Sys* s = cast(Sys*) data.system.m_system_pointer; - - Sys.EntitiesData input_data; - - static if (hasMember!(Sys.EntitiesData, "thread_id")) - { - input_data.thread_id = cast(typeof(input_data.thread_id)) data.thread_id; - } - - static if (hasMember!(Sys.EntitiesData, "job_id")) - { - input_data.job_id = cast(typeof(input_data.job_id)) data.job_id; - } - - s.onUpdate(input_data); - }*/ - // } + s.onUpdate(input_data); + } system.m_update = &callUpdate; } @@ -797,7 +637,7 @@ export struct EntityManager Sys* s = cast(Sys*) data.system.m_system_pointer; Sys.EntitiesData input_data; SystemData.fillInputData(input_data, data.block.type_info, - data.block, data.begin, data.end);//, data.system); + data.block, data.begin, data.count);//, data.system); static if (is(RetTyp == void)) mixin("s." ~ func_name ~ "(input_data)"); else @@ -852,18 +692,10 @@ export struct EntityManager system.m_system_pointer = cast(void*) Mallocator.make!Sys; system.m_priority = priority; - //(cast(Sys*) system.m_system_pointer).__ecsInitialize(); - //system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; + static if(__traits(hasMember, Sys ,"__becs_jobs_count"))system.jobs = Mallocator.makeArray!(Job)(Sys.__becs_jobs_count); else system.jobs = Mallocator.makeArray!(Job)(32); - /*static if (OnUpdateOverloadNum != -1) - { - Sys* s = cast(Sys*) system.m_system_pointer; - system.m_update_delegate = cast(void delegate())&__traits(getOverloads, - s, "onUpdate")[OnUpdateOverloadNum]; - }*/ - genCompList(system, components_map); foreach (iii, comp_info; components_info.readonlyDeps) @@ -985,8 +817,6 @@ export struct EntityManager { UpdatePass* pass = Mallocator.make!UpdatePass; pass.name = Mallocator.makeArray(cast(char[]) name); - /*pass.name = Mallocator.makeArray!char(name.length); - pass.name[0..$] = name[0..$];*/ passes.add(pass); passes_map.add(name, cast(ushort)(passes.length - 1)); return cast(ushort)(passes.length - 1); @@ -1004,14 +834,7 @@ export struct EntityManager { ComponentInfo info; - // enum ComponentName = fullyQualifiedName!Comp; enum ComponentName = fullName!Comp; - // enum ComponentName = Comp.stringof; - - // static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort)) - // { - // static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;"); - // } static if (hasMember!(Comp, "onDestroy") && isFunction!(Comp.onDestroy) && is(ReturnType!(Comp.onDestroy) == void) @@ -1044,21 +867,6 @@ export struct EntityManager info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof); *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); - /*ushort comp_id = components_map.get(cast(char[]) ComponentName, ushort.max); - if (comp_id < components.length) - { - becsID!Comp = comp_id; - if (components[comp_id].init_data) - Mallocator.dispose(components[comp_id].init_data); - components[comp_id] = info; - } - else - { - components.add(info); - becsID!Comp = cast(ushort)(components.length - 1); - char[] name = Mallocator.makeArray(cast(char[]) ComponentName); - components_map.add(name, cast(ushort)(components.length - 1)); - }*/ becsID!Comp = registerComponent(ComponentName, info); } @@ -1121,6 +929,22 @@ export struct EntityManager } } + export ushort registerEvent(const (char)[] name, EventRegisterInfo refister_info) + { + EventInfo info; + info.size = refister_info.size; + info.alignment = refister_info.alignment; + + ushort event_id = events_map.get(name, ushort.max); + if (event_id >= events.length) + { + events.add(info); + event_id = cast(ushort)(events.length - 1); + events_map.add(name, cast(ushort)(events.length - 1)); + } + return event_id; + } + export void callEntitiesFunction(Sys, T)(T func) { //TODO: check if onUpdate function is good @@ -1210,14 +1034,14 @@ export struct EntityManager { if (sys.m_empty) { - CallData data = CallData(caller.system_id, sys, null, null, sys.m_update); + CallData data = CallData(caller.system_id, sys, null, sys.m_system_pointer, sys.m_update); data.update(); } else foreach (info; caller.infos) { CallData data = CallData(caller.system_id, sys, info, - null, sys.m_update); + sys.m_system_pointer, sys.m_update); data.update(); } } @@ -1263,7 +1087,7 @@ export struct EntityManager if (sys.m_empty) { - tmp_datas.add(CallData(caller.system_id, sys, null, null, sys.m_update)); + tmp_datas.add(CallData(caller.system_id, sys, null, sys.m_system_pointer, sys.m_update)); nextJob(); caller.job_group.jobs = sys.jobs[0 .. 1]; (cast(void delegate(JobGroup) nothrow @nogc) m_dispatch_jobs)(caller.job_group); @@ -1328,7 +1152,7 @@ export struct EntityManager assert(entities_per_job == full_blocks_count * info.max_entities + entities_count + ( first_block.entities_count - first_elem)); CallData data = CallData(caller.system_id, sys, - info, null, sys.m_update, first_block, + info, sys.m_system_pointer, sys.m_update, first_block, cast(ushort)(full_blocks_count + 1), cast(ushort) first_elem, 0); tmp_datas.add(data); @@ -1344,7 +1168,7 @@ export struct EntityManager assert(last_elem > 0); assert(last_elem <= block.entities_count); CallData data = CallData(caller.system_id, sys, - info, null, sys.m_update, first_block, + info, sys.m_system_pointer, sys.m_update, first_block, cast(ushort)(full_blocks_count + 2), cast(ushort) first_elem, cast(ushort) last_elem); tmp_datas.add(data); @@ -1363,7 +1187,7 @@ export struct EntityManager uint last_elem = entities_per_job - entities_count; assert(last_elem > 0); CallData data = CallData(caller.system_id, sys, - info, null, sys.m_update, first_block, 1, + info, sys.m_system_pointer, sys.m_update, first_block, 1, cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); tmp_datas.add(data); first_elem += last_elem; @@ -1383,7 +1207,7 @@ export struct EntityManager else { //take whole info blocks - CallData data = CallData(caller.system_id, sys, info, null, sys.m_update, + CallData data = CallData(caller.system_id, sys, info, sys.m_system_pointer, sys.m_update, first_block, cast(ushort) blocks_count, cast(ushort) first_elem); tmp_datas.add(data); entities_count += (blocks_count - 1) * info.max_entities @@ -1997,7 +1821,7 @@ export struct EntityManager { if (!new_info.systems[listener]) { - callRemoveEntityListener(&systems[listener], info, block, ind, ind + 1); + callRemoveEntityListener(&systems[listener], info, block, ind, 1); } } } @@ -2022,7 +1846,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count); + new_block.entities_count - 1, 1); } } } @@ -2034,7 +1858,7 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count, del_ids); + new_block.entities_count - 1, 1, del_ids); } } } @@ -2140,7 +1964,7 @@ export struct EntityManager { if (!new_info.systems[listener]) { - callRemoveEntityListener(&systems[listener], info, block, ind, ind + 1); + callRemoveEntityListener(&systems[listener], info, block, ind, 1); } } } @@ -2185,7 +2009,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count); + new_block.entities_count - 1, 1); } } } @@ -2197,7 +2021,7 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count, new_ids); + new_block.entities_count - 1, 1, new_ids); } } } @@ -2523,7 +2347,7 @@ export struct EntityManager { uint pos = block.entityIndex(entity); - callRemoveEntityListeners(info, block, pos, pos + 1); + callRemoveEntityListeners(info, block, pos, 1); } id_manager.releaseID(id); //release id from manager @@ -2654,49 +2478,51 @@ export struct EntityManager return has_work; } - private void callAddEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow + private void callAddEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int count) @nogc nothrow { foreach (listener; info.add_listeners) { System* system = &systems[listener]; - callAddEntityListener(system, info, block, begin, end); + callAddEntityListener(system, info, block, begin, count); } } private static void callAddEntityListener(System* system, EntityInfo* info, - EntitiesBlock* block, int begin, int end) @nogc nothrow + EntitiesBlock* block, int begin, int count) @nogc nothrow { ListenerCallData data; data.system = system; data.block = block; data.begin = begin; - data.end = end; + data.count = count; + data.info = block.type_info; (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_add_entity)(data); } private void callRemoveEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, - int end) @nogc nothrow + int count) @nogc nothrow { foreach (listener; info.remove_listeners) { System* system = &systems[listener]; - callRemoveEntityListener(system, info, block, begin, end); + callRemoveEntityListener(system, info, block, begin, count); } } private static void callRemoveEntityListener(System* system, - EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow + EntityInfo* info, EntitiesBlock* block, int begin, int count) @nogc nothrow { ListenerCallData data; data.system = system; data.block = block; data.begin = begin; - data.end = end; + data.count = count; + data.info = block.type_info; (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_remove_entity)(data); } private void callChangeEntityListener(System* system, EntityInfo* info, - EntitiesBlock* block, int begin, int end, ushort[] ch_ids) @nogc nothrow + EntitiesBlock* block, int begin, int count, ushort[] ch_ids) @nogc nothrow { int i = 0; int j = 0; @@ -2728,7 +2554,8 @@ export struct EntityManager data.system = system; data.block = block; data.begin = begin; - data.end = end; + data.count = count; + data.info = block.type_info; (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_change_entity)(data); } @@ -2771,7 +2598,7 @@ export struct EntityManager if (info.add_listeners) { - callAddEntityListeners(info, block, entities_count, block.entities_count); + callAddEntityListeners(info, block, entities_count, block.entities_count - entities_count); } } @@ -2947,6 +2774,11 @@ export struct EntityManager event_manager.sendEvent(id, event, threadID); } + void sendEvent(EntityID id, EventRef event) nothrow @nogc + { + event_manager.sendEvent(id, event, threadID); + } + private void generateDependencies() nothrow @nogc { foreach (pass_id, pass; passes) @@ -3147,19 +2979,25 @@ export struct EntityManager struct EventCallData { - EntitiesBlock* block; - void* system_pointer; - void* event; Entity* entity; + void* event; + void* system_pointer; ushort id; + EntitiesBlock* block; } struct EventInfo { ushort size; ushort alignment; - EventCaller[] callers; void function(void* pointer) nothrow @nogc destroy_callback; + EventCaller[] callers; + } + + struct EventRegisterInfo + { + ushort size; + ushort alignment; } /************************************************************************************************************************ @@ -3418,7 +3256,7 @@ export struct EntityManager else blocks = uint.max; - SystemCallData call_data = SystemCallData(0, thread_id, job_id, system.m_system_pointer, context, info); + SystemCallData call_data = SystemCallData(0, thread_id, job_id, context, info); while (block !is null && blocks > 0) { @@ -3451,7 +3289,7 @@ export struct EntityManager } else { - SystemCallData call_data = SystemCallData(0, thread_id, job_id, system.m_system_pointer, context, info); + SystemCallData call_data = SystemCallData(0, thread_id, job_id, context, info); (cast(void function(SystemCallData*) @nogc nothrow) update_func)(&call_data); } } @@ -3492,7 +3330,6 @@ export struct EntityManager uint count; uint thread_id; uint job_id; - void* system_pointer; void* context; EntityInfo* info; EntitiesBlock* block; @@ -3501,10 +3338,11 @@ export struct EntityManager struct ListenerCallData { + uint count; System* system; + EntityInfo* info; EntitiesBlock* block; uint begin; - uint end; } struct Job @@ -3814,7 +3652,6 @@ struct SystemEntityData(Sys) string name; static if (isArray!MemberType) { // Workaround. This code is never called with: not an array type, but compiler prints an error - // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));//.stringof; name = fullName!(Unqual!(ForeachType!MemberType)); } @@ -4014,9 +3851,7 @@ struct SystemEntityData(Sys) string name; static if (isArray!MemberType) { // Workaround. This code is never called with: not an array type, but compiler prints an error - // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType)); name = fullName!(Unqual!(ForeachType!MemberType)); - //name = Unqual!(ForeachType!MemberType).stringof; } bool is_optional; diff --git a/tests/basic.d b/tests/basic.d index aa730ea..a89477d 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -648,6 +648,8 @@ unittest void onAddEntity(EntitiesData data) { + foreach(i; 0..data.length) + data.long_[i] += 1; add++; assert(add_order == 1); add_order++; diff --git a/tests/tests.d b/tests/tests.d index 164eb30..16986cf 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -283,13 +283,13 @@ struct ChangeTestSystem bool onBegin() { - ////writeln("On Test System begin."); + // writeln("On Test System begin."); return true; } void onEnd() { - ////writeln("On Test System end."); + // writeln("On Test System end."); } void initialize(ref Entity entity, ref TestComp comp) @@ -307,10 +307,10 @@ struct ChangeTestSystem void onUpdate(EntitiesData data) { - foreach (i; 0 .. data.length) + /*foreach (i; 0 .. data.length) { - } + }*/ } } @@ -318,6 +318,8 @@ struct TestSystem { mixin ECS.System!16; //__gshared ushort system_id; + uint print = 1; + void onCreate() { //writeln("On Test System create."); @@ -343,13 +345,14 @@ struct TestSystem bool onBegin() { - ////writeln("On Test System begin."); + if(print)printf("On Test System begin.\n"); return true; } void onEnd() { - ////writeln("On Test System end."); + if(print)printf("On Test System end.\n"); + print = 0; } void initialize(ref Entity entity, ref TestComp comp) @@ -406,7 +409,7 @@ struct TestSystemWithHighPriority void initialize(ref Entity entity, ref TestComp comp) { - int o = 1; + } void onUpdate(EntitiesData data) @@ -844,6 +847,7 @@ else: //dur = (MonoTime.currTime - time).total!"usecs"; //writeln("Entities adding: ", dur, " usecs"); printf("Entities adding: %f usecs\n", cast(float)(Time.getUSecTime() - time)); + Mallocator.dispose(idss); time = Time.getUSecTime(); uint blocks = 0; @@ -1021,8 +1025,6 @@ else: gEntityManager.freeTemplate(copy_default_tempalte); EntityManager.destroy(); - Mallocator.dispose(idss); - printf("end\n"); //*/ return 0; From 24ef63d5050ac4abe9189422712c151de92d86ad Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 24 Mar 2021 19:29:04 +0100 Subject: [PATCH 3/6] -added '-pthread' to arguments in 'meson.build' for GDC --- meson.build | 5 +++++ source/bubel/ecs/manager.d | 7 ------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index 48e3007..d27a1a9 100644 --- a/meson.build +++ b/meson.build @@ -58,6 +58,11 @@ if betterC_opt endif endif +if comp_id == 'gcc' + args+='-pthread' + link_args+='-pthread' +endif + add_global_arguments(args, language : 'd') add_global_link_arguments(link_args, language : 'd') diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index ee7b9be..d33f0ff 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -3233,15 +3233,8 @@ export struct EntityManager { export void update() nothrow @nogc { - //(cast(SytemFuncType) system.m_update)(this); if(!system.m_empty) { - // Sys* s = cast(Sys*) system.m_system_pointer; - - //Sys.EntitiesData input_data; - // EntityInfo* info = info; //block.type_info; - // System* system = system; - EntitiesBlock* block; if (first_block) block = first_block; From bbb8144f3490841c9d0668654478f52264dae9e0 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 26 Apr 2021 17:04:39 +0200 Subject: [PATCH 4/6] -fixed DMD release compilation --- source/bubel/ecs/manager.d | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index d33f0ff..0a5e55a 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -1030,6 +1030,7 @@ export struct EntityManager foreach (caller; passes[pass].system_callers) { System* sys = &systems[caller.system_id]; + assert(sys !is null); if (sys.enabled && sys.willExecute) { if (sys.m_empty) @@ -3235,6 +3236,8 @@ export struct EntityManager { if(!system.m_empty) { + assert(info !is null); + EntitiesBlock* block; if (first_block) block = first_block; From 59db920a2e7d5330581b7e7176ebec9644072d53 Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 26 Apr 2021 17:23:46 +0200 Subject: [PATCH 5/6] -updated CodeCov token because of CodeCov Bash Uploader Security Issue --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8fa868a..86ccda1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -56,7 +56,7 @@ coverage_test_dmd: - mkdir reports - binaries/dmd_unittest_cov after_script: - - bash <(curl -s https://codecov.io/bash) -s reports -t 1a0c0169-a721-4085-8252-fed4755dcd8c + - bash <(curl -s https://codecov.io/bash) -s reports -t df87b1d8-85f4-4584-96e3-1315d27ec2c5 wasm: stage: build_wasm From 00028523035da8aa07002beba58497c0375a10cb Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 17 Nov 2021 15:22:13 +0100 Subject: [PATCH 6/6] Added CAPI files I forgot to add CAPI files to .gitignore with previous commits :/ --- .gitignore | 6 +- c-api/becs.h | 207 ++++++++++ c-api/manager.d | 306 ++++++++++++++ c-api/test.c | 1051 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1569 insertions(+), 1 deletion(-) create mode 100644 c-api/becs.h create mode 100644 c-api/manager.d create mode 100644 c-api/test.c diff --git a/.gitignore b/.gitignore index e0e6fff..eae1286 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,8 @@ !compile_wasm.py !compile_android.py !.gitlab-ci.yml -!LICENSE \ No newline at end of file +!LICENSE +!c-api +!c-api/*.h +!c-api/*.d +!c-api/*.c \ No newline at end of file diff --git a/c-api/becs.h b/c-api/becs.h new file mode 100644 index 0000000..2a2bca0 --- /dev/null +++ b/c-api/becs.h @@ -0,0 +1,207 @@ +#ifndef __BECS__ +#define __BECS__ + +#include +#include +#include +#include + +typedef struct BECSSystem +{ + +}BECSSystem; + +typedef struct BECSArray +{ + size_t size; + void* ptr; +}BECSArray; + +typedef struct EntityID +{ + ///Index to entity in IDManager. + uint32_t id; + ///Counter required for reusing ID. + uint32_t counter; +}EntityID; + +typedef struct Entity +{ + ///Entity ID. + EntityID id; +}Entity; + +typedef struct ComponentRef +{ + ///pointer to component + void* ptr; + ///component index + uint16_t id; +}ComponentRef; + +typedef ComponentRef EventRef; + +typedef struct BECSComponentInfo +{ + ///Component size + uint16_t size; + ///Component data alignment + uint16_t alignment; + ///Initialization data + BECSArray init_data; + ///Pointer to component destroy callback + void* destroy_callback; + ///Pointer to component create callback + void* create_callback; + //void* create_callback; +}BECSComponentInfo; + +typedef struct BECSEventRegisterInfo +{ + ///Component size + uint16_t size; + ///Component data alignment + uint16_t alignment; +}BECSEventRegisterInfo; + +typedef struct EntityTemplate +{ + /*///Entity components data + BECSArray entity_data; + ///Pointer to entity type info. + void* info;*/ +}EntityTemplate; + +enum BECSSystemComponentAttribute +{ + required = 0, + optional = 1, + excluded = 2 +}; + +enum BECSSystemComponentAccess +{ + writable = 0, + readonly = 1 +}; + +typedef struct BECSSystemComponentInfo +{ + uint16_t id; + enum BECSSystemComponentAttribute attribute; + enum BECSSystemComponentAccess access; +}BECSSystemComponentInfo; + +///C-API structure conatin only subset of real data which can be accessed directly. Component arrays can be retrived using function calls. +typedef struct BECSListenerCallData +{ + uint32_t count; + void* context; +}BECSListenerCallData; + +///C-API structure conatin only subset of real data which can be accessed directly. Component arrays can be retrived using function calls. +typedef struct BECSSystemCallData +{ + uint32_t count; + uint32_t thread_id; + uint32_t job_id; + void* context; +}BECSSystemCallData; + +///C-API structure conatin only subset of real data which can be accessed directly. Component arrays can be retrived using function calls. +typedef struct BECSEventCallData +{ + Entity* entity; + void* event; + void* context; +}BECSEventCallData; + +typedef struct BECSEventCallback +{ + uint16_t id; + void (*callback)(BECSEventCallData* data); +}BECSEventCallback; + +typedef struct BECSSystemRegisterInfo +{ + uint32_t pass_id; + int32_t priority; + uint32_t max_jobs; + + size_t components_count; + BECSSystemComponentInfo* components; + + size_t event_handlers_count; + BECSEventCallback* event_handlers; + + size_t system_size; + void* init_data; + + void (*on_update)(BECSSystemCallData* call_data); + void (*on_create)(void* system_pointer); + void (*on_destroy)(void* system_pointer); + void (*on_enable)(void* system_pointer); + void (*on_disable)(void* system_pointer); + char (*on_begin)(void* system_pointer); + void (*on_end)(void* system_pointer); + void (*on_add_entity)(BECSListenerCallData*); + void (*on_remove_entity)(BECSListenerCallData*); + void (*on_change_entity)(BECSListenerCallData*); + void (*filter_entity)(void* system_pointer, void* info); +}BECSSystemRegisterInfo; + +void becsInitialize(); +void becsDestroy(); + +void becsBeginRegister(); +void becsEndRegister(); + +void becsBegin(); +void becsEnd(); +void becsCommit(); + +void becsUpdate(uint16_t pass_id); +void becsUpdateMT(uint16_t pass_id); + +uint16_t becsRegisterComponent(const char* name, BECSComponentInfo info); +uint16_t becsRegisterEvent(const char* name, BECSEventRegisterInfo info); +uint16_t becsRegisterSystem(const char* name, BECSSystemRegisterInfo info); +uint16_t becsRegisterPass(const char* name); + +Entity* becsAddEntity(EntityTemplate* template); +Entity* becsAddEntityCopy(EntityID id); +void becsRemoveEntity(EntityID id); + +Entity* becsGetEntity(EntityID id); + +void becsAddComponents(const EntityID entity_id, size_t length, ComponentRef* comps); +void becsRemoveComponents(const EntityID entity_id, size_t length, uint16_t* comps); + +EntityTemplate* becsAllocateTemplate(uint32_t count, uint16_t* components); +EntityTemplate* becsAllocateTemplateFromEntity(EntityID id, uint8_t fill_default); +EntityTemplate* becsAllocateTemplateCopy(EntityTemplate* tmpl); +EntityTemplate* becsAllocateTemplateFromTemplate(EntityTemplate* tmpl, size_t new_count, uint16_t* components, size_t remove_count, uint16_t* remove_components); +void becsFreeTemplate(EntityTemplate* tmpl); + +void* becsEntityGetComponent(Entity* entity, uint16_t component_id); + +void* becsSystemCallDataGetComponentArray(BECSSystemCallData* data, uint16_t component_id); +Entity* becsSystemCallDataGetEntitiesArray(BECSSystemCallData* data); + +void* becsListenerCallDataGetComponentArray(BECSListenerCallData* data, uint16_t component_id); +Entity* becsListenerCallDataGetEntitiesArray(BECSListenerCallData* data); + +void becsCallEntitiesFunction(uint16_t system_id, void (*on_update)(BECSSystemCallData* call_data), void* context); + +void becsSendEvent(EntityID id, EventRef event); + +#define BECS_REGISTER_COMPONENT(comp) \ + ({ \ + void* mem_ptr = malloc(sizeof(comp)); \ + memcpy(mem_ptr, &comp, sizeof(comp)); \ + becsRegisterComponent(#comp, (BECSComponentInfo){sizeof(comp), alignof(comp), (BECSArray){sizeof(comp), mem_ptr}, 0, 0}); \ + }) + + //BECSComponentInfo(sizeof(comp), 4, 0, 0, 0)); + +#endif //__BECS__ \ No newline at end of file diff --git a/c-api/manager.d b/c-api/manager.d new file mode 100644 index 0000000..e109f1d --- /dev/null +++ b/c-api/manager.d @@ -0,0 +1,306 @@ +module manager; + +import bubel.ecs.manager; +import bubel.ecs.entity; +import bubel.ecs.events; +import bubel.ecs.system; +import bubel.ecs.std; + +import core.stdc.string; + +extern (C): +/* +struct BECSComponentInfo +{ + ///Component size + ushort size; + ///Component data alignment + ushort alignment; + ///Initialization data + ubyte[] init_data; + ///Pointer to component destroy callback + void* destroy_callback; + ///Pointer to component create callback + void* create_callback; + //void* create_callback; +}*/ + +alias BECSComponentInfo = EntityManager.ComponentInfo; +// alias BECSEventCallData = EntityManager.EventCallData; + +enum BECSSystemComponentAttribute +{ + required = 0, + optional = 1, + excluded = 2 +} + +enum BECSSystemComponentAccess +{ + writable = 0, + readonly = 1 +} + +struct BECSSystemComponentInfo +{ + ushort id; + BECSSystemComponentAttribute attribute; + BECSSystemComponentAccess access; +} + +struct BECSEventCallback +{ + ushort id; + void function(EntityManager.EventCallData* data) callback; +} + +struct BECSSystemRegisterInfo +{ + uint pass_id; + int priority; + uint max_jobs; + + BECSSystemComponentInfo[] components; + BECSEventCallback[] event_handlers; + + byte[] init_data; + + void function(EntityManager.SystemCallData* call_data) on_update; + void function(void* system_pointer) on_create; + void function(void* system_pointer) on_destroy; + void function(void* system_pointer) on_enable; + void function(void* system_pointer) on_disable; + bool function(void* system_pointer) on_begin; + void function(void* system_pointer) on_end; + void function(EntityManager.ListenerCallData*) on_add_entity; + void function(EntityManager.ListenerCallData*) on_remove_entity; + void function(EntityManager.ListenerCallData*) on_change_entity; + void function(void* system_pointer, EntityManager.EntityInfo* info) filter_entity; +} + +alias BECSEventRegisterInfo = EntityManager.EventRegisterInfo; + +void becsInitialize() +{ + EntityManager.initialize(); +} + +void becsDestroy() +{ + EntityManager.destroy(); +} + +void becsBeginRegister() +{ + gEntityManager.beginRegister(); +} + +void becsEndRegister() +{ + gEntityManager.endRegister(); +} + +void becsBegin() +{ + gEntityManager.begin(); +} + +void becsEnd() +{ + gEntityManager.end(); +} + +void becsCommit() +{ + gEntityManager.commit(); +} + +void becsUpdate(ushort pass_id) +{ + gEntityManager.update(pass_id); +} + +void becsUpdateMT(ushort pass_id) +{ + gEntityManager.update(pass_id); +} + +ushort becsRegisterPass(const (char)* name) +{ + return gEntityManager.registerPass(name[0 .. strlen(name)]); +} + +ushort becsRegisterComponent(const(char)* name, BECSComponentInfo info) +{ + return gEntityManager.registerComponent(name[0 .. strlen(name)], info); +} + +ushort becsRegisterEvent(const(char)* name, BECSEventRegisterInfo info) +{ + return gEntityManager.registerEvent(name[0 .. strlen(name)], info); +} + +ushort becsRegisterSystem(const(char)* name, BECSSystemRegisterInfo info) +{ + System system; + + if(info.init_data.length) + { + system.m_system_pointer = malloc(info.init_data.length); + memcpy(system.m_system_pointer, info.init_data.ptr, info.init_data.length); + } + + if(info.event_handlers.length) + { + system.m_event_callers = Mallocator.makeArray!(System.EventCaller)(info.event_handlers.length); + foreach(i, BECSEventCallback callback; info.event_handlers) + { + system.m_event_callers[i].id = callback.id; + system.m_event_callers[i].callback = callback.callback; + } + } + + system.m_update = info.on_update; + system.m_create = info.on_create; + system.m_destroy = info.on_destroy; + system.m_enable = info.on_enable; + system.m_disable = info.on_disable; + system.m_begin = info.on_begin; + system.m_end = info.on_end; + system.m_add_entity = info.on_add_entity; + system.m_remove_entity = info.on_remove_entity; + system.m_change_entity = info.on_change_entity; + system.m_filter_entity = info.filter_entity; + + if(info.components.length) + { + uint req; + uint opt; + foreach(comp; info.components) + { + if(comp.attribute == BECSSystemComponentAttribute.required)req++; + else if(comp.attribute == BECSSystemComponentAttribute.optional)opt++; + } + if(req)system.m_components = Mallocator.makeArray!ushort(req); + if(opt)system.m_optional_components = Mallocator.makeArray!ushort(opt); + req = 0; + opt = 0; + foreach(comp; info.components) + { + if(comp.attribute == BECSSystemComponentAttribute.required) + { + system.m_components[req++] = comp.id; + } + else if(comp.attribute == BECSSystemComponentAttribute.optional) + { + system.m_optional_components[opt++] = comp.id; + } + } + } + else + { + system.m_empty = true; + } + return gEntityManager.registerSystem(name[0 .. strlen(name)], system); +} + +EntityTemplate* becsAllocateTemplate(uint count, ushort* components) +{ + return gEntityManager.allocateTemplate(components[0 .. count]); +} + +EntityTemplate* becsAllocateTemplateFromEntity(EntityID id, bool fill_default) +{ + return gEntityManager.allocateTemplate(id, fill_default); +} + +EntityTemplate* becsAllocateTemplateCopy(EntityTemplate* tmpl) +{ + return gEntityManager.allocateTemplate(tmpl); +} + +EntityTemplate* becsAllocateTemplateFromTemplate(EntityTemplate* tmpl, size_t new_count, ushort* components, size_t remove_count, ushort* remove_components) +{ + return gEntityManager.allocateTemplate(tmpl, components[0 .. new_count], remove_components[0 .. remove_count]); +} + +void becsFreeTemplate(EntityTemplate* tmpl) +{ + gEntityManager.freeTemplate(tmpl); +} + +Entity* becsAddEntity(EntityTemplate* tmpl) +{ + return gEntityManager.addEntity(tmpl); +} + +Entity* becsAddEntityCopy(EntityID id) +{ + return gEntityManager.addEntityCopy(id); +} + +void becsRemoveEntity(EntityID id) +{ + gEntityManager.removeEntity(id); +} + +Entity* becsGetEntity(EntityID id) +{ + return gEntityManager.getEntity(id); +} + +void* becsEntityGetComponent(Entity* entity, ushort component_id) +{ + return entity.getComponent(component_id); +} + +void* becsSystemCallDataGetComponentArray(EntityManager.SystemCallData* data, ushort component_id) +{ + if(data.info.deltas.length <= component_id || data.info.deltas[component_id] == 0)return null; + return cast(void*)data.block + data.info.deltas[component_id]; +} + +Entity* becsSystemCallDataGetEntitiesArray(EntityManager.SystemCallData* data) +{ + return cast(Entity*)data.block.dataBegin(); +} + +void* becsListenerCallDataGetComponentArray(EntityManager.ListenerCallData* data, ushort component_id) +{ + if(data.info.deltas.length <= component_id || data.info.deltas[component_id] == 0)return null; + return cast(void*)data.block + data.info.deltas[component_id]; +} + +Entity* becsListenerCallDataGetEntitiesArray(EntityManager.ListenerCallData* data) +{ + return cast(Entity*)data.block.dataBegin(); +} + +void becsCallEntitiesFunction(ushort system_id, void function(EntityManager.SystemCallData*) callback, void* context) +{ + System* system = gEntityManager.getSystem(system_id); + + if (!system.m_any_system_caller) + return; + + foreach (info; system.m_any_system_caller.infos) + { + EntityManager.CallData data = EntityManager.CallData(system.id, system, info, context, cast(void*)callback); + data.update(); + } +} + +void becsAddComponents(const EntityID entity_id, ComponentRef[] comps) +{ + gEntityManager.addComponents(entity_id, comps); +} + +void becsRemoveComponents(const EntityID entity_id, ushort[] comps) +{ + gEntityManager.removeComponents(entity_id, comps); +} + +void becsSendEvent(EntityID id, EventRef event) +{ + gEntityManager.sendEvent(id, event); +} \ No newline at end of file diff --git a/c-api/test.c b/c-api/test.c new file mode 100644 index 0000000..c6b1246 --- /dev/null +++ b/c-api/test.c @@ -0,0 +1,1051 @@ +#include "becs.h" +#include +#include + +uint32_t getID() +{ + return 0; +} + +long getUSecTime() +{ + //time_t time; + struct timespec spec; + + clock_gettime(CLOCK_REALTIME, &spec); + + //time = spec.tv_sec; + return spec.tv_sec * 1000000 + spec.tv_nsec / 1000; //time / 1000_000; +} + +typedef struct TestEvent +{ + int32_t a; +}TestEvent; +static uint16_t TestEventID; + +typedef struct TestEvent2 +{ + float a; +}TestEvent2; +static uint16_t TestEvent2ID; + +typedef struct +{ + float x,y; +}CLocation; +static uint16_t CLocationID; + +typedef struct +{ + float x,y; +}CVelocity; +static uint16_t CVelocityID; + +typedef struct TestComp +{ + int32_t a;// = 1; + uint64_t b;// = 2; +}TestComp; +static uint16_t TestCompID; + +typedef struct TestComp2 +{ + int32_t b;// = 3; + int32_t a;// = 4; +}TestComp2; +static uint16_t TestComp2ID; + +typedef struct TestComp3 +{ + uint32_t gg;// = 5; //good game + uint32_t bg;// = 6; //bad game +}TestComp3; +static uint16_t TestComp3ID; + +typedef struct TestComp4 +{ + uint32_t gg;// = 7; //good game + uint32_t bg;// = 8; //bad game + uint64_t a;// = 9; + uint64_t b;// = 10; + uint64_t c;// = 11; + uint64_t g;// = 12; +}TestComp4; +static uint16_t TestComp4ID; + +typedef struct TestComp5 +{ + uint32_t gg;// = 7; //good game + uint32_t bg;// = 8; //bad game + uint64_t a;// = 9; + uint64_t b;// = 10; + uint64_t c;// = 11; + uint64_t g;// = 12; +}TestComp5; +static uint16_t TestComp5ID; + +typedef struct CPosition +{ + float x; + float y; +}CPosition; +static uint16_t CPositionID; + +void onUpdateTest(BECSSystemCallData* call_data) +{ + CLocation* location = (CLocation*)becsSystemCallDataGetComponentArray(call_data, CLocationID); + CVelocity* velocity = (CVelocity*)becsSystemCallDataGetComponentArray(call_data, CVelocityID); + //if(velocity != NULL)exit(0); + for(int i=0; icount; i++) + { + location[i].y += 10; + if(velocity)velocity[i].x += 1; + } + printf("To jest printf z systemu!\n"); +} +/* +struct EverySystem +{ + struct EntitiesData + { + uint length; + Entity[] entity; + CPosition[] pos; + } + + +};*/ + +void EverySystemFree(BECSSystemCallData* call_data) +{ + Entity* entity = becsSystemCallDataGetEntitiesArray(call_data); + for(int i=0; icount; i++) + { + becsRemoveEntity(entity[i].id); + } +} + +void EverySystemAddOne(BECSSystemCallData* call_data) +{ + Entity* entity = becsSystemCallDataGetEntitiesArray(call_data); + TestComp2 comp2 = {3, 4}; + ComponentRef ref = {&comp2, TestComp2ID}; + + for(int i=0; icount; i++) + { + becsAddComponents(entity[i].id, 1, &ref); + ///gEntityManager.addComponents(data.entity[i].id, TestComp2()); + } +} + +void EverySystemOnUpdate(BECSSystemCallData* call_data) +{ + //CLocation* location = (CLocation*)becsSystemCallDataGetComponentArray(call_data, CLocationID); + CPosition* pos = (CPosition*)becsSystemCallDataGetComponentArray(call_data, CPositionID); + + for(int i=0; icount; i++) + { + pos[i].x++; + pos[i].y++; + } +}; + +void EverySystemIterate(BECSSystemCallData* call_data) +{ + //CLocation* location = (CLocation*)becsSystemCallDataGetComponentArray(call_data, CLocationID); + CPosition* pos = (CPosition*)becsSystemCallDataGetComponentArray(call_data, CPositionID); + + for(int i=0; icount; i++) + { + pos[i].x++; + pos[i].y++; + } +}; + +/* +struct ChangeTestSystem +{ + mixin ECS.System!16; //__gshared ushort system_id; + + static struct EntitiesData + { + size_t length; + const(Entity)[] entites; + TestComp4[] test4; + @optional TestComp5[] test5; + } + + +}*/ + +void ChangeTestSystemOnCreate() +{ + //writeln("On Change Test System create."); + printf("On Change Test System create.\n"); +} + +void ChangeTestSystemOnDestroy() +{ + //writeln("On Change Test System destroy."); + printf("On Change Test System destroy.\n"); +} + +void ChangeTestSystemOnAddEntity(BECSListenerCallData* call_data) +{ + Entity* entities = becsListenerCallDataGetEntitiesArray(call_data); + //printf("Entity added! ID: "); + for(int i=0; icount; i++) + printf("Entity added! ID: %u\n",(uint32_t) entities[i].id.id); + ////writeln("Entity added! ID: ", entities[i].id); +} + +void ChangeTestSystemOnRemoveEntity(BECSListenerCallData* call_data) +{ + Entity* entities = becsListenerCallDataGetEntitiesArray(call_data); + ////writeln("Entity removed! ID: ", entities[0].id); + printf("Entity removed! ID: %u\n",(uint32_t) entities[0].id.id); +} + +void ChangeTestSystemOnChangeEntity(BECSListenerCallData* call_data) +{ + Entity* entities = becsListenerCallDataGetEntitiesArray(call_data); + ////writeln("Entity changed! ID: ", entities[0].id); + printf("Entity changed! ID: %u\n",(uint32_t) entities[0].id.id); +} + +char ChangeTestSystemOnBegin(void* context) +{ + ////writeln("On Test System begin."); + return 1; +} + +void ChangeTestSystemOnEnd(void* context) +{ + ////writeln("On Test System end."); +} + +void ChangeTestSystemOnUpdate(BECSSystemCallData* call_data) +{ + /*for(int i=0; icount; i++) + { + + }*/ +} + +uint16_t ChangeTestSystemID; + + +typedef struct TestSystem +{ + uint32_t print; + + /* + + void initialize(ref Entity entity, ref TestComp comp) + { + + } + + static struct EntitiesData + { + size_t length; + const(Entity)[] entites; + TestComp[] test; + TestComp2[] test2; + @readonly @optional const(TestComp3)[] test3; + //@excluded TestComp4[] test4; + } + + void handleEvent(TestEvent event, ref TestComp test, ref TestComp2 test2, TestComp3* test3) + { + + }*/ +}TestSystem; + +void TestSystemOnCreate(void* context) +{ + //writeln("On Test System create."); + printf("On Change Test System create.\n"); +} + +void TestSystemOnDestroy(void* context) +{ + //writeln("On Test System destroy."); + printf("On Change Test System destroy.\n"); +} + +void TestSystemOnAddEntity(BECSListenerCallData* call_data) +{ + //foreach(i;0..data.length) + ////writeln("Entity added ID: ",data.entites[i].id.id); +} + +void TestSystemOnRemoveEntity(BECSListenerCallData* call_data) +{ + ////writeln("Entity destroyed ID: ",data.entites[0].id); +} + +char TestSystemOnBegin(void* context) +{ + TestSystem* system = (TestSystem*)context; + if(system->print)printf("On Test System begin.\n"); + return 1; +} + +void TestSystemOnEnd(void* context) +{ + TestSystem* system = (TestSystem*)context; + if(system->print)printf("On Test System end.\n"); + system->print = 0; +} + +void TestSystemOnUpdate(BECSSystemCallData* call_data) +{ + TestComp* test = (TestComp*)becsSystemCallDataGetComponentArray(call_data, TestCompID); + TestComp2* test2 = (TestComp2*)becsSystemCallDataGetComponentArray(call_data, TestComp2ID); + for(int i=0; icount; i++) + { + test[i].a += 1000; + test[i].b += 2000; + test2[i].b += 2; + test2[i].a = 8; + } +} + +uint16_t TestSystemID; + +/* +struct TestSystemWithHighPriority +{ + mixin ECS.System!16; //__gshared ushort system_id; + + static struct EntitiesData + { + TestComp[] test; + } + + void initialize(ref Entity entity, ref TestComp comp) + { + int o = 1; + } +} +*/ + +void TestSystemWithHighPriorityOnUpdate(BECSSystemCallData* call_data) +{ + +} + +uint16_t TestSystemWithHighPriorityID; + +/* +struct Sys1 +{ + mixin ECS.System; + + struct EntitiesData + { + TestComp[] comp; + } +}*/ + +void Sys1OnAddEntity(BECSListenerCallData* call_data) +{ + +} + +uint16_t Sys1ID; +/* +struct Sys2 +{ + mixin ECS.System; + + struct EntitiesData + { + TestComp[] comp; + } +}*/ + +void Sys2OnAddEntity(BECSListenerCallData* call_data) +{ + +} + +uint16_t Sys2ID; +/* +struct Sys3 +{ + mixin ECS.System; + + struct EntitiesData + { + TestComp[] comp; + } +}*/ + +void Sys3OnAddEntity(BECSListenerCallData* call_data) +{ + +} + +void Sys3OnUpdate(BECSSystemCallData* call_data) +{ + +} + +uint16_t Sys3ID; + + +typedef struct EmptyEventSystem +{ + char handled; +}EmptyEventSystem; + +void EmptyEventSystemHandleEvent(BECSEventCallData* call_data) +{ + //TestEvent* event = (TestEvent*)call_data->event; + EmptyEventSystem* context = (EmptyEventSystem*)call_data->context; + if (!context->handled) + { + printf("EmptyEventSystem.handleEvent() called!\n"); + context->handled = 1; + } + exit(0);//assert(0, "this shouldn't be called!"); +} + +uint16_t EmptyEventSystemID; + + +typedef struct EventSystem +{ + char handled; + + /*struct EntitiesData + { + uint thread_id; + TestComp[] comp; + }*/ +}EventSystem; + +void EventSystemHandleTestEvent(BECSEventCallData* call_data) +{ + //TestEvent* event = (TestEvent*)call_data->event; + EmptyEventSystem* context = (EmptyEventSystem*)call_data->context; + if (!context->handled) + { + printf("EventSystem.handleEvent() called!\n"); + context->handled = 1; + } +} + +uint16_t EventSystemID; + +/* +struct EmptySystem +{ + mixin ECS.System; + + struct EntitiesData + { + uint thread_id; + } +}*/ + +void EmptySystemOnUpdate(BECSSystemCallData* call_data) +{ + printf("EmptySystem.onUpdate() - this should be called once per update\n"); +} + +uint16_t EmptySystemID; + +/* +import std.meta; + +struct TestSystem2 +{ + mixin ECS.System!16; //__gshared ushort system_id; + + //alias ExcludedComponents = AliasSeq!("TestComp", "TestComp4"); + + static struct EntitiesData + { + short length; + const(Entity)[] entity; + TestComp3[] test; + //@excluded TestComp[] testt; + } + + static struct EventInput + { + Entity* entity; + TestComp3* test; + //TestComp* tt; + } + + void initialize(ref Entity entity, ref TestComp comp) + { + + } + + void lateUpdate(ref BECSSystemCallData* call_data) + { + for(int i=0;icount;i++) + { + data.test[i].gg -= 1; + //gEntityManager.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); + } + } + +} +*/ + +void TestSystem2HandleEvent(BECSEventCallData* call_data) +{ + Entity* entity = call_data->entity; + TestEvent* event = (TestEvent*)call_data->event; + EmptyEventSystem* context = (EmptyEventSystem*)call_data->context; + + TestComp3* test = (TestComp3*)becsEntityGetComponent(entity, TestComp3ID); + test->bg = event->a; + TestEvent2 event2; + event2.a = event->a + 8; + becsSendEvent(entity->id, (EventRef){&event2, TestEvent2ID}); +} + +void TestSystem2HandleEvent2(BECSEventCallData* call_data) +{ + Entity* entity = call_data->entity; + TestEvent2* event = (TestEvent2*)call_data->event; + EmptyEventSystem* context = (EmptyEventSystem*)call_data->context; + + TestComp3* test = (TestComp3*)becsEntityGetComponent(entity, TestComp3ID); + test->gg =(uint32_t) event->a; +} + +void TestSystem2OnEnable() +{ + + //writeln("TestSystem2 enabled"); + printf("TestSystem2 enabled\n"); +} + +void TestSystem2OnDisable() +{ + + //writeln("TestSystem2 disabled"); + printf("TestSystem2 disabled\n"); +} + +void TestSystem2OnUpdate(BECSSystemCallData* call_data) +{ + TestComp3* test = (TestComp3*)becsSystemCallDataGetComponentArray(call_data, TestComp3ID); + Entity* entity = becsSystemCallDataGetEntitiesArray(call_data); + for(int i=0;icount;i++) + { + test[i].gg += 14; + TestEvent event; + event.a = test[i].gg + 4; + becsSendEvent(entity[i].id, (EventRef){&event, TestEventID}); + //gEntityManager.sendEvent!(TestEvent)(data.entity[i].id, event); + //gEntityManager.sendSelfEvent!(TestEvent)(data.entity[i].id, TestEvent()); + } +} + +uint16_t TestSystem2ID; + +typedef struct ExternalUpdateCallTest +{ + int print_count;// = 3 +}ExternalUpdateCallTest; + +void ExternalUpdateCallTestUpdate(BECSSystemCallData* call_data) +{ + TestComp3* test = becsSystemCallDataGetComponentArray(call_data, TestComp3ID); + ExternalUpdateCallTest* context = (ExternalUpdateCallTest*)call_data->context; + + if (context->print_count > 0) + { + context->print_count--; + printf("ExternalUpdateCallTest %u %u\n", test[0].gg,(uint32_t) call_data->count); + } +} + +static uint16_t EverySystemID; + +void writeEntityComponents(Entity* entity) +{ + + printf("EntityID(%u, %u)", (uint32_t) entity->id.id, (uint32_t) entity->id.counter); + //write(entity->id); + TestComp* test_comp = (TestComp*)becsEntityGetComponent(entity, TestCompID);//.getComponent!TestComp; + if (test_comp) + printf("TestComp(%u, %u)", (uint32_t) test_comp->a, (uint32_t) test_comp->b); //write(*test_comp); + TestComp2* test_comp2 = (TestComp2*)becsEntityGetComponent(entity, TestComp2ID);//.getComponent!TestComp2; + if (test_comp2) + printf("TestComp2(%u, %u)", (uint32_t) test_comp2->b, (uint32_t) test_comp2->a); //write(*test_comp2); + TestComp3* test_comp3 = (TestComp3*)becsEntityGetComponent(entity, TestComp3ID);//.getComponent!TestComp3; + if (test_comp3) + printf("TestComp3(%u, %u)", (uint32_t) test_comp3->gg, (uint32_t) test_comp3->bg); //write(*test_comp3); + TestComp4* test_comp4 = (TestComp4*)becsEntityGetComponent(entity, TestComp4ID);//.getComponent!TestComp4; + if (test_comp4) + printf("TestComp4(%u, %u, %u, %u, %u, %u)", test_comp4->gg, test_comp4->bg, + (uint32_t) test_comp4->a, (uint32_t) test_comp4->b, + (uint32_t) test_comp4->c, (uint32_t) test_comp4->g); //write(*test_comp4); + printf("\n"); + //writeln(); + ////writeln(((uint32_t*) pp)[0 .. 14], " ", pp); +} + +int main() +{ + becsInitialize(); + //gEntityManager.setMultithreadingCallbacks(&dispatch, &getID); + + becsBeginRegister(); + uint16_t fixed_pass = becsRegisterPass("fixed"); + + long time = getUSecTime(); + + TestComp2 test_comp2 = {3,4}; + TestComp2ID = BECS_REGISTER_COMPONENT(test_comp2); + TestComp4 test_comp4 = {7,8,9,10,11,12}; + TestComp4ID = BECS_REGISTER_COMPONENT(test_comp4); + TestComp test_comp = {1,2}; + TestCompID = BECS_REGISTER_COMPONENT(test_comp); + TestComp3 test_comp3 = {5,6}; + TestComp3ID = BECS_REGISTER_COMPONENT(test_comp3); + TestComp5 test_comp5 = {7,8,9,10,11,12}; + TestComp5ID = BECS_REGISTER_COMPONENT(test_comp5); + CPosition position = {0,0}; + CPositionID = BECS_REGISTER_COMPONENT(position); + + CLocation loc = {10,12.2}; + CLocationID = BECS_REGISTER_COMPONENT(loc); + CVelocity vel = {1,2.6}; + CVelocityID = BECS_REGISTER_COMPONENT(vel); + + TestEventID = becsRegisterEvent("TestEvent", (BECSEventRegisterInfo){sizeof(TestEvent), alignof(TestEvent)}); + TestEvent2ID = becsRegisterEvent("TestEvent2", (BECSEventRegisterInfo){sizeof(TestEvent2), alignof(TestEvent2)}); + + printf("Components register: %f usecs\n", (float)(getUSecTime() - time)); + time = getUSecTime(); + + /*{ + BECSSystemComponentInfo array[] = {(BECSSystemComponentInfo){0}}; + BECSSystemRegisterInfo register_info; + register_info.components_count = 1; + register_info.components = array; + register_info.on_update = onUpdateTest; + becsRegisterSystem("System", register_info); + }*/ + + { + BECSSystemComponentInfo array[] = {(BECSSystemComponentInfo){TestCompID}}; + BECSSystemRegisterInfo register_info = {}; + register_info.priority = 100; + register_info.components_count = 1; + register_info.components = array; + register_info.pass_id = fixed_pass; + register_info.on_update = TestSystemWithHighPriorityOnUpdate; + TestSystemWithHighPriorityID = becsRegisterSystem("TestSystemWithHighPriority", register_info); + } + + { + BECSSystemComponentInfo array[] = { + (BECSSystemComponentInfo){TestCompID}, + (BECSSystemComponentInfo){TestComp2ID}, + (BECSSystemComponentInfo){TestComp3ID,optional}}; + BECSSystemRegisterInfo register_info = {}; + register_info.priority = 0; + register_info.system_size = sizeof(TestSystem); + register_info.init_data = &(TestSystem){1}; + register_info.components_count = 3; + register_info.components = array; + register_info.on_create = TestSystemOnCreate; + register_info.on_destroy = TestSystemOnDestroy; + register_info.on_add_entity = TestSystemOnAddEntity; + register_info.on_update = TestSystemOnUpdate; + register_info.on_begin = TestSystemOnBegin; + register_info.on_end = TestSystemOnEnd; + TestSystemID = becsRegisterSystem("TestSystem", register_info); + } + + { + BECSSystemComponentInfo array[] = { + (BECSSystemComponentInfo){TestComp4ID}, + (BECSSystemComponentInfo){TestComp5ID,optional}}; + BECSSystemRegisterInfo register_info = {}; + register_info.priority = 0; + register_info.components_count = 2; + register_info.components = array; + register_info.on_update = ChangeTestSystemOnUpdate; + register_info.on_create = ChangeTestSystemOnCreate; + register_info.on_destroy = ChangeTestSystemOnDestroy; + register_info.on_add_entity = ChangeTestSystemOnAddEntity; + register_info.on_remove_entity = ChangeTestSystemOnRemoveEntity; + register_info.on_change_entity = ChangeTestSystemOnChangeEntity; + register_info.on_begin = ChangeTestSystemOnBegin; + register_info.on_end = ChangeTestSystemOnEnd; + ChangeTestSystemID = becsRegisterSystem("ChangeTestSystem", register_info); + } + + { + BECSSystemComponentInfo array[] = {(BECSSystemComponentInfo){TestCompID}}; + BECSSystemRegisterInfo register_info= {}; + register_info.priority = 10; + register_info.components_count = 1; + register_info.components = array; + register_info.on_add_entity = Sys1OnAddEntity; + Sys1ID = becsRegisterSystem("Sys1", register_info); + } + + { + BECSSystemComponentInfo array[] = {(BECSSystemComponentInfo){TestCompID}}; + BECSSystemRegisterInfo register_info= {}; + register_info.priority = -100; + register_info.components_count = 1; + register_info.components = array; + register_info.on_add_entity = Sys2OnAddEntity; + Sys2ID = becsRegisterSystem("Sys2", register_info); + } + + { + BECSSystemComponentInfo array[] = {(BECSSystemComponentInfo){TestCompID}}; + BECSSystemRegisterInfo register_info= {}; + register_info.priority = -2; + register_info.components_count = 1; + register_info.components = array; + register_info.on_update = Sys3OnUpdate; + register_info.on_add_entity = Sys3OnAddEntity; + Sys3ID = becsRegisterSystem("Sys3", register_info); + } + + { + BECSSystemRegisterInfo register_info= {}; + register_info.priority = 2; + register_info.on_update = EmptySystemOnUpdate; + EmptySystemID = becsRegisterSystem("EmptySystem", register_info); + } + + { + BECSEventCallback event_array[] = {(BECSEventCallback){TestEventID, EmptyEventSystemHandleEvent}}; + BECSSystemRegisterInfo register_info= {}; + register_info.priority = 2; + register_info.system_size = sizeof(EmptyEventSystem); + register_info.init_data = &(EmptyEventSystem){}; + register_info.event_handlers_count = 1; + register_info.event_handlers = event_array; + EmptyEventSystemID = becsRegisterSystem("EmptyEventSystem", register_info); + } + + { + BECSEventCallback event_array[] = {(BECSEventCallback){TestEventID, EventSystemHandleTestEvent}}; + BECSSystemComponentInfo array[] = {(BECSSystemComponentInfo){TestCompID}}; + BECSSystemRegisterInfo register_info= {}; + register_info.priority = 2; + register_info.system_size = sizeof(EventSystem); + register_info.init_data = &(EventSystem){}; + register_info.components_count = 1; + register_info.components = array; + register_info.event_handlers_count = 1; + register_info.event_handlers = event_array; + EventSystemID = becsRegisterSystem("EventSystem", register_info); + } + + { + BECSSystemComponentInfo array[] = {(BECSSystemComponentInfo){CPositionID}}; + BECSSystemRegisterInfo register_info= {}; + register_info.priority = 0; + register_info.components_count = 1; + register_info.components = array; + register_info.on_update = EverySystemOnUpdate; + EverySystemID = becsRegisterSystem("EverySystem", register_info); + } + + becsEndRegister(); + + printf("Systems register: %f usecs\n", (float)(getUSecTime() - time)); + time = getUSecTime(); + + uint16_t ids[2] = {TestComp2ID, TestCompID}; + EntityTemplate* tmpl = becsAllocateTemplate(2, ids); + + uint16_t ids2[2] = {TestComp3ID, TestCompID}; + EntityTemplate* tmpl2 = becsAllocateTemplate(2, ids2); + + printf("Template allocating: %f usecs\n", (float)(getUSecTime() - time)); + time = getUSecTime(); + + uint16_t empty_ids[1] = {CPositionID}; + EntityTemplate* tmpl_empty = becsAllocateTemplate(1, empty_ids); + + becsCommit(); + + time = getUSecTime(); + for(int i = 0;i < 4000000; i++)becsAddEntity(tmpl_empty); + becsCommit(); + for(int i = 0;i < 4000000; i++)becsAddEntity(tmpl_empty); + becsCommit(); + for(int i = 0;i < 2000000; i++)becsAddEntity(tmpl_empty); + becsCommit(); + + printf("Adding 1M entities: %f usecs\n", (float)(getUSecTime() - time)); + + becsCommit(); + time = getUSecTime(); + becsCallEntitiesFunction(EverySystemID, EverySystemIterate, NULL); + printf("Iterate 1M entities: %f usecs\n", (float)(getUSecTime() - time)); + + becsBegin(); + time = getUSecTime(); + becsUpdate(0); + printf("Iterate 1M entities (update): %f usecs\n", (float)(getUSecTime() - time)); + becsEnd(); + + time = getUSecTime(); + becsCallEntitiesFunction(EverySystemID,EverySystemFree, NULL); + becsCommit(); + printf("Deleting 1M entities: %f usecs\n", (float)(getUSecTime() - time)); + + time = getUSecTime(); + for(int i = 0;i < 4000000; i++)becsAddEntity(tmpl_empty); + becsCommit(); + for(int i = 0;i < 4000000; i++)becsAddEntity(tmpl_empty); + becsCommit(); + for(int i = 0;i < 2000000; i++)becsAddEntity(tmpl_empty); + becsCommit(); + + printf("Adding 1M entities (prealloc): %f usecs\n", (float)(getUSecTime() - time)); + + becsCommit(); + time = getUSecTime(); + becsCallEntitiesFunction(EverySystemID, EverySystemAddOne, NULL); + becsCommit(); + printf("Adding 1M component: %f usecs\n", (float)(getUSecTime() - time)); + + becsCommit(); + becsCallEntitiesFunction(EverySystemID,EverySystemFree, NULL); + becsCommit(); + + time = getUSecTime(); + + EntityID entity; + + { + entity = becsAddEntity(tmpl)->id; + writeEntityComponents(becsGetEntity(entity)); + /*EntityManager.EntitiesBlock* block = gEntityManager.getMetaData( + gEntityManager.getEntity(entity)); + EntityManager.EntityInfo* info = block.type_info;*/ + //writeln(info.add_listeners); + //if(info)assert(0); + } + + time = getUSecTime(); + + //EntityID[] idss = Mallocator.makeArray!EntityID(5000); //[5000] + EntityID* idss = (EntityID*)malloc(sizeof(EntityID) * 5000); + + for (int i=0;i<200;i++) + { + becsBegin(); + for (int j=0;j<5000;j++) + idss[j] = becsAddEntity(tmpl)->id; + for (int j=0;j<5000;j++) + becsRemoveEntity(idss[j]); + becsEnd(); + } + becsCommit(); + + printf("Entities adding: %f usecs\n", (float)(getUSecTime() - time)); + free(idss); + time = getUSecTime(); + + uint32_t blocks = 0; + /*foreach (info; &gEntityManager.entities_infos.byValue) + { + EntityManager.EntitiesBlock* block = info.first_block; + while (block !is null) + { + block = block.next_block; + blocks++; + } + }*/ + //writeln("Entities blocks: ", blocks); + printf("Entities blocks: %u\n", blocks); + + becsBeginRegister(); + { + BECSEventCallback event_array[] = { + (BECSEventCallback){TestEventID, TestSystem2HandleEvent}, + (BECSEventCallback){TestEvent2ID, TestSystem2HandleEvent2}}; + BECSSystemComponentInfo array[] = {(BECSSystemComponentInfo){TestComp3ID}}; + BECSSystemRegisterInfo register_info; + register_info.priority = 0; + register_info.components_count = 1; + register_info.components = array; + register_info.event_handlers_count = 2; + register_info.event_handlers = event_array; + register_info.on_enable = TestSystem2OnEnable; + register_info.on_disable = TestSystem2OnDisable; + register_info.on_update = TestSystem2OnUpdate; + TestSystem2ID = becsRegisterSystem("TestSystem2", register_info); + } + becsEndRegister(); + + EntityID entity2; + + time = getUSecTime(); + + EntityID* entities = (EntityID*)malloc(sizeof(EntityID) * 1000000); + for (int i=0;i< 500000;i++) + { + entity2 = becsAddEntity(tmpl)->id; + entities[i * 2] = entity2; + entities[i * 2 + 1] = becsAddEntity(tmpl2)->id; + } + + becsCommit(); + + printf("Entities adding2: %f usecs\n", (float)(getUSecTime() - time)); + time = getUSecTime(); + + for (int i=0;i< 1000000;i++) + { + becsAddComponents(entities[i], 1, &(ComponentRef){&(TestComp5){7, 8, 9, 10, 11, 12}, TestComp5ID}); + if ((i & 0x00FFFF) == 0) + becsCommit(); + } + + becsCommit(); + + printf("Components adding: %f usecs\n", (float)(getUSecTime() - time)); + time = getUSecTime(); + + for (int i=0;i< 1000000;i++) + { + becsRemoveComponents(entities[i], 1, &TestComp5ID); + //if((i & 0x00FFFF) == 0)gEntityManager.commit(); + } + + becsCommit(); + printf("Components removing: %f usecs\n", (float)(getUSecTime() - time)); + time = getUSecTime(); + + free(entities); + + time = getUSecTime(); + + becsBegin(); + becsUpdate(0); + becsEnd(); + + printf("Update: %f usecs\n", (float)(getUSecTime() - time)); + + writeEntityComponents(becsGetEntity(entity2)); + + time = getUSecTime(); + + becsBegin(); + becsUpdateMT(0); + becsEnd(); + + printf("Update: %f usecs\n", (float)(getUSecTime() - time)); + + writeEntityComponents(becsGetEntity(entity2)); + + time = getUSecTime(); + + becsBegin(); + becsUpdate(0); + becsEnd(); + + printf("Update: %f usecs\n", (float)(getUSecTime() - time)); + + writeEntityComponents(becsGetEntity(entity2)); + + entity = becsAddEntity(tmpl)->id; + + becsBegin(); + becsUpdate(0); + becsEnd(); + + writeEntityComponents(becsGetEntity(entity)); + + becsAddEntity(tmpl); + writeEntityComponents(becsGetEntity(entity)); + writeEntityComponents(becsAddEntityCopy(entity)); + EntityTemplate* copy_tempalte = becsAllocateTemplateFromEntity(entity, 0); + writeEntityComponents(becsAddEntity(copy_tempalte)); + EntityTemplate* copy_default_tempalte = becsAllocateTemplateFromEntity(entity, 1); + writeEntityComponents(becsAddEntity(copy_default_tempalte)); + + becsAddComponents(entity, 1, &(ComponentRef){&(TestComp4){7,8,9,10,11,12},TestComp4ID}); + becsAddComponents(entity, 1, &(ComponentRef){&(TestComp3){5,6},TestComp3ID}); + + becsBegin(); + becsUpdate(0); + becsEnd(); + + writeEntityComponents(becsGetEntity(entity)); + + becsRemoveComponents(entity, 1, &TestCompID); + becsAddComponents(entity, 1, &(ComponentRef){&(TestComp){1,2},TestCompID}); + becsAddComponents(entity, 1, &(ComponentRef){&(TestComp5){7,8,9,10,11,12},TestComp5ID}); + + becsBegin(); + becsUpdate(0); + becsUpdate(fixed_pass); + becsEnd(); + + becsRemoveComponents(entity, 1, &TestComp4ID); + + becsCommit(); + + // BECSSystem* sys = (BECSSystem*)becsGetSystem(TestSystem2ID); + + ExternalUpdateCallTest external_update_test = {3}; + + becsCallEntitiesFunction(TestSystem2ID, ExternalUpdateCallTestUpdate, &external_update_test); + + printf("pre end\n"); + + writeEntityComponents(becsGetEntity(entity)); + becsFreeTemplate(tmpl_empty); + becsFreeTemplate(tmpl); + becsFreeTemplate(tmpl2); + becsFreeTemplate(copy_tempalte); + becsFreeTemplate(copy_default_tempalte); + becsDestroy(); + + printf("end\n"); + +/* + unsigned short components[1] = {CLocationID}; + EntityTemplate* template = becsAllocateTemplate(1, components); + unsigned short components2[2] = {CVelocityID, CLocationID}; + EntityTemplate* template2 = becsAllocateTemplate(2, components2); + Entity* entity = becsAddEntity(template); + Entity* entity2 = becsAddEntity(template2); + Entity* entity3 = becsAddEntity(template2); + printf("%lu\n", (unsigned long)entity); + entity = becsGetEntity(entity->id); + printf("%lu\n", (unsigned long)entity); + CLocation* location = (CLocation*)becsEntityGetComponent(entity, CLocationID); + printf("comp %f %f\n", location->x, location->y); + + entity2 = becsGetEntity(entity2->id); + CVelocity* velocity = (CVelocity*)becsEntityGetComponent(entity2, CVelocityID); + printf("compv %f %f\n", velocity->x, velocity->y); + + entity3 = becsGetEntity(entity3->id); + location = (CLocation*)becsEntityGetComponent(entity3, CLocationID); + printf("comp %f %f\n", location->x, location->y); + + becsBegin(); + becsUpdate(0); + becsEnd(); + printf("comp %f %f\n", location->x, location->y);*/ + return 0; +} \ No newline at end of file