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; }