diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 62847a5..7c89b71 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -11,7 +11,7 @@ import std.traits; //import core.stdc.stdlib : qsort; //import core.stdc.string; -import ecs.system;//not ordered as forward reference bug workaround +import ecs.system; //not ordered as forward reference bug workaround import ecs.block_allocator; import ecs.entity; import ecs.events; @@ -33,17 +33,21 @@ alias SerializeVector = ecs.vector.Vector!ubyte; */ export struct EntityManager { - export static void initialize(uint threads_count) + /************************************************************************************************************************ + *Initialize ECS. + */ + export static void initialize(uint threads_count, uint page_size = 32768, + uint block_pages_count = 128) { if (instance is null) { //instance = Mallocator.make!EntityManager(threads_count); - instance = Mallocator.make!EntityManager(threads_count); - - with(instance) + instance = Mallocator.make!EntityManager(threads_count, page_size, block_pages_count); + + with (instance) { UpdatePass* pass = Mallocator.make!UpdatePass; - pass.name = Mallocator.makeArray(cast(char[])"update"); + pass.name = Mallocator.makeArray(cast(char[]) "update"); //pass.name = Mallocator.makeArray!char("update".length); //pass.name[0..$] = "update"; passes.add(pass); @@ -52,12 +56,15 @@ export struct EntityManager } } + /************************************************************************************************************************ + *Deinitialize and destroy ECS. This function release whole memory. + */ export static void destroy() { if (instance is null) return; - with(instance) + with (instance) { foreach (ref system; systems) { @@ -65,44 +72,56 @@ export struct EntityManager if (system.m_destroy) (cast(void function(void*)) system.m_destroy)(system.m_system_pointer); - if(system.jobs)Mallocator.dispose(system.jobs); - if(system.m_read_only_components)Mallocator.dispose(system.m_read_only_components); - if(system.m_modified_components)Mallocator.dispose(system.m_modified_components); - if(system.m_components)Mallocator.dispose(system.m_components); - if(system.m_excluded_components)Mallocator.dispose(system.m_excluded_components); - if(system.m_optional_components)Mallocator.dispose(system.m_optional_components); - if(system.m_name)Mallocator.dispose(system.m_name); - if(system.m_event_callers)Mallocator.dispose(system.m_event_callers); - - if(system.m_system_pointer)Mallocator.dispose(system.m_system_pointer); + if (system.jobs) + Mallocator.dispose(system.jobs); + if (system.m_read_only_components) + Mallocator.dispose(system.m_read_only_components); + if (system.m_modified_components) + Mallocator.dispose(system.m_modified_components); + if (system.m_components) + Mallocator.dispose(system.m_components); + if (system.m_excluded_components) + Mallocator.dispose(system.m_excluded_components); + if (system.m_optional_components) + Mallocator.dispose(system.m_optional_components); + if (system.m_name) + Mallocator.dispose(system.m_name); + if (system.m_event_callers) + Mallocator.dispose(system.m_event_callers); + + if (system.m_system_pointer) + Mallocator.dispose(system.m_system_pointer); } - foreach(EntityInfo* info;&entities_infos.byValue) + foreach (EntityInfo* info; &entities_infos.byValue) { //if(info.components)Mallocator.dispose(info.components); Mallocator.dispose(info); - }//*/ + } //*/ - foreach(UpdatePass* pass; passes) + foreach (UpdatePass* pass; passes) { Mallocator.dispose(pass); } passes.clear(); - foreach(ComponentInfo info; components) + foreach (ComponentInfo info; components) { - if(info.init_data)Mallocator.dispose(info.init_data); + if (info.init_data) + Mallocator.dispose(info.init_data); } - foreach(EventInfo info; events) + foreach (EventInfo info; events) { - if(info.callers)Mallocator.dispose(info.callers); + if (info.callers) + Mallocator.dispose(info.callers); } - foreach(name; &components_map.byKey) + foreach (name; &components_map.byKey) { - if(name)Mallocator.dispose(name); + if (name) + Mallocator.dispose(name); } } @@ -165,6 +184,7 @@ export struct EntityManager SystemCaller* sys_caller = Mallocator.make!SystemCaller; sys_caller.system_id = system.id; sys_caller.job_group.caller = sys_caller; + system.m_any_system_caller = sys_caller; passes[system.m_pass].system_callers.add(sys_caller, i); added = true; break; @@ -175,6 +195,7 @@ export struct EntityManager SystemCaller* sys_caller = Mallocator.make!SystemCaller; sys_caller.system_id = system.id; sys_caller.job_group.caller = sys_caller; + system.m_any_system_caller = sys_caller; passes[system.m_pass].system_callers.add(sys_caller); } @@ -235,13 +256,14 @@ export struct EntityManager return 1; } - foreach(ref event; events) + foreach (ref event; events) { - qsort(event.callers.ptr, event.callers.length, EventCaller.sizeof, &comapreEventCaller); + qsort(event.callers.ptr, event.callers.length, + EventCaller.sizeof, &comapreEventCaller); } //qsort(event_callers.ptr, event_callers.length, EventInfo.sizeof, &compareUShorts); - foreach(EntityInfo* info;&entities_infos.byValue) + foreach (EntityInfo* info; &entities_infos.byValue) { generateListeners(info); } @@ -252,17 +274,20 @@ export struct EntityManager /************************************************************************************************************************ *Default constructor. */ - export this(uint threads_count) nothrow @nogc + export this(uint threads_count, uint page_size, uint block_pages_count) nothrow @nogc { if (threads_count == 0) threads_count = 1; threads = Mallocator.makeArray!ThreadData(threads_count); //foreach(ref thread;threads)thread = ThreadData().init; + m_page_size = page_size; + m_pages_in_block = block_pages_count; + id_manager.initialize(); event_manager.initialize(&this); - allocator = BlockAllocator(page_size, pages_in_block); + allocator = BlockAllocator(m_page_size, m_pages_in_block); //add_mutex = Mallocator.make!Mutex; entity_block_alloc_mutex = Mallocator.make!Mutex; @@ -276,8 +301,9 @@ export struct EntityManager id_manager.deinitialize(); event_manager.destroy(); - if(threads)Mallocator.dispose(threads); - if(entity_block_alloc_mutex) + if (threads) + Mallocator.dispose(threads); + if (entity_block_alloc_mutex) { entity_block_alloc_mutex.destroy(); Mallocator.dispose(entity_block_alloc_mutex); @@ -293,7 +319,7 @@ export struct EntityManager void registerSystem(Sys)(int priority, const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); - assert(pass != ushort.max);//, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); + assert(pass != ushort.max); //, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); registerSystem!(Sys)(priority, pass); } @@ -312,19 +338,19 @@ export struct EntityManager assert(register_state, "registerSystem must be called between beginRegister() and endRegister()."); - assert(pass < passes.length);//, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); + assert(pass < passes.length); //, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); System system; system.m_pass = pass; static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) { - static assert(0);//, "Add \"mixin ECS.System;\" in top of system structure;"); //"System should have \"__gshared ushort system_id"); + static assert(0); //, "Add \"mixin ECS.System;\" in top of system structure;"); //"System should have \"__gshared ushort system_id"); } static if (!(hasMember!(Sys, "EntitiesData"))) { - static assert(0);//, "System should gave \"EntitiesData\" struct for input components"); + static assert(0); //, "System should gave \"EntitiesData\" struct for input components"); } static if (hasMember!(Sys, "handleEvent")) @@ -378,28 +404,28 @@ export struct EntityManager void setEventCallers(Sys)(ref System system) { enum event_handlers_num = __traits(getOverloads, Sys, "handleEvent").length; - System.EventCaller[] callers = (cast(System.EventCaller*)alloca(event_handlers_num * System.EventCaller.sizeof))[0..event_handlers_num]; + System.EventCaller[] callers = (cast(System.EventCaller*) alloca( + event_handlers_num * System.EventCaller.sizeof))[0 .. event_handlers_num]; int i = 0; foreach (j, func; __traits(getOverloads, Sys, "handleEvent")) { - alias Params = Parameters!(__traits(getOverloads, - Sys, "handleEvent")[j]); - static if(Params.length == 2 && is(Params[0] == Entity*)) + alias Params = Parameters!(__traits(getOverloads, Sys, "handleEvent")[j]); + static if (Params.length == 2 && is(Params[0] == Entity*)) { alias EventParamType = Params[1]; enum EventName = Unqual!(EventParamType).stringof; ushort evt = events_map.get(cast(char[]) EventName, ushort.max); - assert(evt != ushort.max, "Can't register system \""~Sys.stringof~"\" due to non existing event \""~EventName~"\"."); - - callers[i].callback = cast( - void*)&callEventHandler!(EventParamType); + assert(evt != ushort.max, "Can't register system \"" ~ Sys.stringof + ~ "\" due to non existing event \"" ~ EventName ~ "\"."); + + callers[i].callback = cast(void*)&callEventHandler!(EventParamType); callers[i].id = EventParamType.event_id; i++; } } - system.m_event_callers = Mallocator.makeArray(callers[0..i]); + system.m_event_callers = Mallocator.makeArray(callers[0 .. i]); } static if (__traits(hasMember, Sys, "handleEvent")) @@ -416,7 +442,7 @@ export struct EntityManager static struct ComponentsIndices { - + CompInfo[] readonly() { return m_readonly[0 .. m_readonly_counter]; @@ -516,9 +542,11 @@ export struct EntityManager foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); - if (member == "length" || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + if (member == "length" || is(MemberType == Entity[]) + || is(MemberType == const(Entity)[])) { - if(is(MemberType == Entity[]) || is(MemberType == const(Entity)[]))components_info.entites_array = member; + if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + components_info.entites_array = member; continue; } @@ -536,7 +564,8 @@ export struct EntityManager is_read_only = true; } - foreach (att; __traits(getAttributes, __traits(getMember, Sys.EntitiesData, member))) + foreach (att; __traits(getAttributes, __traits(getMember, + Sys.EntitiesData, member))) { if (att == "optional") { @@ -549,22 +578,22 @@ export struct EntityManager } if (is_read_only) { - components_info.addReadonly(CompInfo(member,name)); + components_info.addReadonly(CompInfo(member, name)); //components_info.readonly ~= CompInfo(member,name); } else { - components_info.addMutable(CompInfo(member,name)); + components_info.addMutable(CompInfo(member, name)); //components_info.mutable ~= CompInfo(member,name); } if (is_optional) { - components_info.addOptional(CompInfo(member,name)); + components_info.addOptional(CompInfo(member, name)); //components_info.optional ~= CompInfo(member,name); } else { - components_info.addReq(CompInfo(member,name)); + components_info.addReq(CompInfo(member, name)); //components_info.req ~= CompInfo(member,name); } /*if (is_read_only) @@ -583,16 +612,16 @@ export struct EntityManager { foreach (str; __traits(allMembers, Sys.ExcludedComponents)) { - components_info.addExcluded(CompInfo(str,str)); - //components_info.excluded ~= CompInfo(str,str); + components_info.addExcluded(CompInfo(str, str)); + //components_info.excluded ~= CompInfo(str,str); } } else //static if (checkExcludedComponentsSomething!Sys) { foreach (str; Sys.ExcludedComponents) { - components_info.addExcluded(CompInfo(str.stringof,str.stringof)); - //components_info.excluded ~= CompInfo(str,str); + components_info.addExcluded(CompInfo(str.stringof, str.stringof)); + //components_info.excluded ~= CompInfo(str,str); } } @@ -608,14 +637,16 @@ export struct EntityManager foreach (member; __traits(allMembers, Sys.EntitiesData)) { - alias MemberType=typeof(__traits(getMember, Sys.EntitiesData, member)); + alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); static if (isFunction!(__traits(getMember, Sys.EntitiesData, member))) static assert(0, "EntitiesData can't have any function!"); else static if (member == "length") { - static assert(isIntegral!(MemberType), "EntitiesData 'length' member must be integral type."); - static assert(MemberType.sizeof > 1, "EntitiesData 'length' member can't be byte or ubyte."); + static assert(isIntegral!(MemberType), + "EntitiesData 'length' member must be integral type."); + static assert(MemberType.sizeof > 1, + "EntitiesData 'length' member can't be byte or ubyte."); } else static if (!(isArray!(MemberType))) static assert(0, "EntitiesData members should be arrays of elements!"); @@ -627,31 +658,31 @@ export struct EntityManager foreach (iii, comp_info; components_info.req) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_components[iii] = comp; } foreach (iii, comp_info; components_info.excluded) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_excluded_components[iii] = comp; } foreach (iii, comp_info; components_info.optional) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_optional_components[iii] = comp; } foreach (iii, comp_info; components_info.readonly) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_read_only_components[iii] = comp; } foreach (iii, comp_info; components_info.mutable) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - assert(comp != ushort.max);//, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); + assert(comp != ushort.max); //, "Can't register system \""~Sys.stringof~"\" due to non existing component \""~comp_info.type~"\"."); system.m_modified_components[iii] = comp; } @@ -662,36 +693,40 @@ export struct EntityManager { //enum ComponentsIndices components_info = getComponentsInfo(); - static if(components_info.entites_array) + static if (components_info.entites_array) { - __traits(getMember, input_data, components_info.entites_array) = (cast(Entity*) block.dataBegin())[offset .. entities_count]; + __traits(getMember, input_data, components_info.entites_array) = ( + cast(Entity*) block.dataBegin())[offset .. entities_count]; } - static if(hasMember!(Sys.EntitiesData,"length")) + static if (hasMember!(Sys.EntitiesData, "length")) { input_data.length = cast(typeof(input_data.length))(entities_count - offset); } static foreach (iii, comp_info; components_info.req) { - __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]; + __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.optional) { - if(system.m_optional_components[iii] < info.deltas.length && info.deltas[system.m_optional_components[iii]] != 0) + 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]; - + __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]; + } } } - - bool checkOnUpdateParams()() + + /*bool checkOnUpdateParams()() { bool ret = false; foreach (func; __traits(getOverloads, Sys, "onUpdate")) @@ -703,9 +738,29 @@ export struct EntityManager } } return ret; + }*/ + + int getOnUpdateOverload()() + { + int ret = -1; + foreach (i, func; __traits(getOverloads, Sys, "onUpdate")) + { + if ((Parameters!(func)).length == 1 && is(Parameters!(func)[0] == Sys.EntitiesData)) + { + ret = i; + break; + } + } + return ret; } - static if (hasMember!(Sys, "onUpdate") && checkOnUpdateParams()) + static if (hasMember!(Sys, "onUpdate")) + enum OnUpdateOverloadNum = getOnUpdateOverload(); + else + enum OnUpdateOverloadNum = -1; + //enum HasOnUpdate = (hasMember!(Sys, "onUpdate") && checkOnUpdateParams()); + + static if (OnUpdateOverloadNum != -1) { static void callUpdate(ref CallData data) { @@ -744,8 +799,10 @@ export struct EntityManager assert(entities_count <= block.entities_count && offset <= block.entities_count); fillInputData(input_data, info, block, offset, entities_count, system); - - s.onUpdate(input_data); + + //s.onUpdate(input_data); + (cast(typeof(&__traits(getOverloads, s, + "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data); block = block.next_block; offset = 0; @@ -758,7 +815,7 @@ export struct EntityManager static void catchFunction(string func_name, RetType = void)(void** member) { - static if(hasMember!(Sys,func_name)) + static if (hasMember!(Sys, func_name)) { foreach (func; __traits(getOverloads, Sys, func_name)) { @@ -767,9 +824,12 @@ export struct EntityManager static RetType callFunc(void* system_pointer) { Sys* s = cast(Sys*) system_pointer; - static if(is(RetTyp == void))mixin("s."~func_name~"()"); - else return mixin("s."~func_name~"()"); + static if (is(RetTyp == void)) + mixin("s." ~ func_name ~ "()"); + else + return mixin("s." ~ func_name ~ "()"); } + *member = cast(void*)&callFunc; break; } @@ -779,20 +839,26 @@ export struct EntityManager static void catchEntityFunction(string func_name, RetType = void)(void** member) { - static if(hasMember!(Sys,func_name)) + static if (hasMember!(Sys, func_name)) { foreach (func; __traits(getOverloads, Sys, func_name)) { - static if ((Parameters!(func)).length == 1 && is(Parameters!(func)[0] == Sys.EntitiesData) && is(ReturnType!(func) == RetType)) + static if ((Parameters!(func)).length == 1 + && is(Parameters!(func)[0] == Sys.EntitiesData) + && is(ReturnType!(func) == RetType)) { static RetType callFunc(ref ListenerCallData data) { 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); - static if(is(RetTyp == void))mixin("s."~func_name~"(input_data)"); - else return mixin("s."~func_name~"(input_data)"); + 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 + return mixin("s." ~ func_name ~ "(input_data)"); } + *member = cast(void*)&callFunc; break; } @@ -804,7 +870,7 @@ export struct EntityManager catchFunction!("onDisable")(&system.m_disable); catchFunction!("onCreate")(&system.m_create); catchFunction!("onDestroy")(&system.m_destroy); - catchFunction!("onBegin",bool)(&system.m_begin); + catchFunction!("onBegin", bool)(&system.m_begin); catchFunction!("onEnd")(&system.m_end); catchEntityFunction!("onAddEntity")(&system.m_add_entity); @@ -815,11 +881,19 @@ export struct EntityManager system.m_priority = priority; //(cast(Sys*) system.m_system_pointer).__ecsInitialize(); //system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; - system.jobs = Mallocator.makeArray!(Job)((cast(Sys*) system.m_system_pointer).__ecs_jobs_count); + system.jobs = Mallocator.makeArray!(Job)((cast(Sys*) system.m_system_pointer) + .__ecs_jobs_count); + + 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); - ushort sys_id = systems_map.get(cast(char[])Sys.stringof, ushort.max); + ushort sys_id = systems_map.get(cast(char[]) Sys.stringof, ushort.max); if (sys_id < systems.length) { system.enable(); @@ -832,7 +906,7 @@ export struct EntityManager } else { - system.m_name = Mallocator.makeArray(cast(char[])Sys.stringof); + system.m_name = Mallocator.makeArray(cast(char[]) Sys.stringof); systems_map.add(system.m_name, cast(ushort) systems.length); system.m_id = cast(ushort)(systems.length); @@ -866,7 +940,7 @@ export struct EntityManager export ushort registerPass(const(char)[] name) { UpdatePass* pass = Mallocator.make!UpdatePass; - pass.name = Mallocator.makeArray(cast(char[])name); + pass.name = Mallocator.makeArray(cast(char[]) name); /*pass.name = Mallocator.makeArray!char(name.length); pass.name[0..$] = name[0..$];*/ passes.add(pass); @@ -914,7 +988,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[])Comp.stringof, ushort.max); + ushort comp_id = components_map.get(cast(char[]) Comp.stringof, ushort.max); if (comp_id < components.length) { Comp.component_id = comp_id; @@ -924,7 +998,7 @@ export struct EntityManager { components.add(info); Comp.component_id = cast(ushort)(components.length - 1); - char[] name = Mallocator.makeArray(cast(char[])Comp.stringof); + char[] name = Mallocator.makeArray(cast(char[]) Comp.stringof); /*char[] name = Mallocator.makeArray!char(Comp.stringof.length); name[0..$] = Comp.stringof;*/ components_map.add(name, cast(ushort)(components.length - 1)); @@ -967,6 +1041,28 @@ export struct EntityManager } } + export void callEntitiesFunction(Sys, T)(T func) + { + Sys* s; + static assert(isDelegate!func, "Function must be delegate."); + static assert(__traits(hasMember, Sys, "EntitiesData"), + "Can't call function with system which hasn't EntitesData structure."); + static assert(__traits(hasMember, Sys, "onUpdate"), + "Can't call function with system which hasn't onUpdate function callback."); + static assert(is(T == typeof(&s.onUpdate)), "Function must match system update function."); + static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type."); + + System* system = getSystem(Sys.system_id); + assert(system != null, + "System must be registered in EntityManager before any funcion can be called."); + + foreach (info; system.m_any_system_caller.infos) + { + CallData data = CallData(system.id, system, info, cast(void delegate()) func); + data.update(); + } + } + /************************************************************************************************************************ *Same as "void update(int pass = 0)" but use pass name instead of id. */ @@ -991,7 +1087,7 @@ export struct EntityManager { foreach (info; caller.infos) { - CallData data = CallData(caller.system_id, sys, info); + CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate); data.update(); } } @@ -1085,7 +1181,8 @@ export struct EntityManager if (full_blocks_count * info.max_entities + entities_count + ( first_block.entities_count - first_elem) >= entities_per_job) { - CallData data = CallData(caller.system_id, sys, info, first_block, + CallData data = CallData(caller.system_id, sys, + info, sys.m_update_delegate, first_block, cast(ushort)(full_blocks_count + 1), cast(ushort) first_elem, 0); tmp_datas.add(data); @@ -1098,8 +1195,9 @@ export struct EntityManager entities_count += full_blocks_count * info.max_entities + ( first_block.entities_count - first_elem); // - first_elem; uint last_elem = entities_per_job - entities_count; // + first_elem - 1; - CallData data = CallData(caller.system_id, sys, info, - first_block, cast(ushort)(full_blocks_count + 2), + CallData data = CallData(caller.system_id, sys, + info, sys.m_update_delegate, first_block, + cast(ushort)(full_blocks_count + 2), cast(ushort) first_elem, cast(ushort) last_elem); tmp_datas.add(data); first_elem = last_elem; @@ -1111,7 +1209,8 @@ export struct EntityManager else { uint last_elem = entities_per_job - entities_count; - CallData data = CallData(caller.system_id, sys, info, first_block, 1, + CallData data = CallData(caller.system_id, sys, + info, sys.m_update_delegate, first_block, 1, cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); tmp_datas.add(data); first_elem += last_elem; @@ -1123,7 +1222,7 @@ export struct EntityManager } else { - CallData data = CallData(caller.system_id, sys, info, + CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate, first_block, cast(ushort) blocks_count, cast(ushort) first_elem); tmp_datas.add(data); entities_count += (blocks_count - 1) * info.max_entities @@ -1138,10 +1237,11 @@ export struct EntityManager } } - export void setMultithreadingCallbacks(void delegate(JobGroup) dispatch_callback, uint delegate() get_id_callback) + export void setMultithreadingCallbacks(void delegate(JobGroup) dispatch_callback, + uint delegate() get_id_callback) { - m_dispatch_jobs = cast(void delegate(JobGroup jobs) nothrow @nogc)dispatch_callback; - m_thread_id_func = cast(uint delegate() nothrow @nogc)get_id_callback; + m_dispatch_jobs = cast(void delegate(JobGroup jobs) nothrow @nogc) dispatch_callback; + m_thread_id_func = cast(uint delegate() nothrow @nogc) get_id_callback; } /*export void setJobDispachFunc(void delegate(JobGroup) @nogc nothrow func) nothrow @nogc @@ -1149,6 +1249,23 @@ export struct EntityManager m_dispatch_jobs = func; }*/ + /************************************************************************************************************************ + *Return size of single page (block). Every entity data block has size of page. + */ + uint pageSize() + { + return m_page_size; + } + + /************************************************************************************************************************ + *Return number of pages in single block allocation. Library allocate defined number of pages at once and assign it's + *for entities. + */ + uint pagesInBlock() + { + return m_pages_in_block; + } + static void alignNum(ref ushort num, ushort alignment) nothrow @nogc pure { num = cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); //num += alignment - (num & (alignment - 1)); @@ -1183,12 +1300,13 @@ export struct EntityManager temp.entity_data = Mallocator.makeArray!ubyte(info.size); temp.info = info; - if(fill_default) + if (fill_default) { //fill components with default data foreach (comp; info.components) { - memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); + memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], + components[comp].init_data.ptr, components[comp].size); /*temp.entity_data[info.tmpl_deltas[comp] .. info.tmpl_deltas[comp] + components[comp].size] = components[comp].init_data;*/ } @@ -1199,10 +1317,11 @@ export struct EntityManager foreach (comp; info.components) { memcpy(cast(void*) temp.entity_data + info.tmpl_deltas[comp], - cast(void*) block + info.deltas[comp] + components[comp].size * index, components[comp].size); + cast(void*) block + info.deltas[comp] + components[comp].size * index, + components[comp].size); } } - + return temp; } @@ -1244,7 +1363,8 @@ export struct EntityManager //fill components with default data foreach (comp; info.components) { - memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); + memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], + components[comp].init_data.ptr, components[comp].size); /*temp.entity_data[info.tmpl_deltas[comp] .. info.tmpl_deltas[comp] + components[comp].size] = components[comp].init_data;*/ } @@ -1287,7 +1407,7 @@ export struct EntityManager alignNum(info.size, info.alignment); uint block_memory = cast(uint)( - page_size - EntitiesBlock.sizeof - (info.size - components_size)); + m_page_size - EntitiesBlock.sizeof - (info.size - components_size)); //uint entity_comps_size = EntityID.sizeof; uint mem_begin = EntitiesBlock.sizeof; @@ -1532,7 +1652,7 @@ export struct EntityManager data.change_entities_list.add(0); data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]); - data.change_entities_list.add((cast(ubyte*)del_ids.ptr)[0 .. num * 2]); + data.change_entities_list.add((cast(ubyte*) del_ids.ptr)[0 .. num * 2]); } private void __removeComponents(EntityID entity_id, ushort[] del_ids) @@ -1550,12 +1670,13 @@ export struct EntityManager EntityInfo* new_info = info; - foreach(id;del_ids) + foreach (id; del_ids) { new_info = new_info.getNewInfoRemove(id); } - if(new_info == info)return; + if (new_info == info) + return; //EntityInfo* new_info = getEntityInfo(ids[0 .. j]); @@ -1669,12 +1790,13 @@ export struct EntityManager EntityInfo* new_info = info; - foreach(id;new_ids) + foreach (id; new_ids) { new_info = new_info.getNewInfoAdd(id); } - if(new_info == info)return; + if (new_info == info) + return; //EntityInfo* new_info = getEntityInfo(ids[0 .. len]); @@ -1701,10 +1823,10 @@ export struct EntityManager } } - foreach (ref id; new_info.components)//ids[0 .. len]) + foreach (ref id; new_info.components) //ids[0 .. len]) { void* dst = cast(void*) new_block + new_info.deltas[id] + ( - new_block.entities_count ) * components[id].size; + new_block.entities_count) * components[id].size; uint size = components[id].size; if (k >= new_ids.length) { @@ -1779,7 +1901,7 @@ export struct EntityManager } ThreadData* data = &threads[threadID]; - data.change_entities_list.add(cast(ubyte)1u); + data.change_entities_list.add(cast(ubyte) 1u); data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); data.change_entities_list.add((cast(ubyte*)&num)[0 .. uint.sizeof]); data.change_entities_list.add(cast(ubyte[]) new_ids); @@ -1835,12 +1957,13 @@ export struct EntityManager foreach (i, comp; info.components) { memcpy(cast(void*) new_block + info.deltas[comp] + components[comp].size * new_id, - cast(void*) block + info.deltas[comp] + components[comp].size * index, components[comp].size); + cast(void*) block + info.deltas[comp] + components[comp].size * index, + components[comp].size); if (components[comp].create_callback) { - components[comp].create_callback( - cast(void*) block + info.deltas[comp] + new_id * components[comp].size); + components[comp].create_callback(cast( + void*) block + info.deltas[comp] + new_id * components[comp].size); } } @@ -2072,7 +2195,7 @@ export struct EntityManager */ export EntitiesBlock* getMetaData(const void* pointer) nothrow @nogc { - return cast(EntitiesBlock*)(cast(size_t) pointer & (~cast(size_t)(page_size - 1))); + return cast(EntitiesBlock*)(cast(size_t) pointer & (~cast(size_t)(m_page_size - 1))); } private void changeEntities() @@ -2081,7 +2204,7 @@ export struct EntityManager { uint index = 0; uint len = cast(uint) thread.change_entities_list.length; - void*[32] pointers;// = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; + void*[32] pointers; // = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; while (index < len) { if (!thread.change_entities_list[index++]) @@ -2090,7 +2213,7 @@ export struct EntityManager index += EntityID.sizeof; uint num = *cast(uint*)&thread.change_entities_list[index]; index += uint.sizeof; - ushort[] ids;// = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; + ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; ids = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; index += ushort.sizeof * num; __removeComponents(id, ids); @@ -2101,7 +2224,7 @@ export struct EntityManager index += EntityID.sizeof; uint num = *cast(uint*)&thread.change_entities_list[index]; index += uint.sizeof; - ushort[] ids;// = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; + ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num]; ids = (cast(ushort*)&thread.change_entities_list[index])[0 .. num]; index += ushort.sizeof * num; //void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num]; @@ -2110,7 +2233,7 @@ export struct EntityManager pointers[i] = &thread.change_entities_list[index]; index += components[ids[i]].size; } - __addComponents(id, ids, pointers[0..num]); + __addComponents(id, ids, pointers[0 .. num]); } } thread.change_entities_list.clear(); @@ -2260,7 +2383,7 @@ export struct EntityManager { EntityID entity_id = *cast(EntityID*) event_pointer; Entity* entity = id_manager.getEntityPointer(entity_id); - if(entity) + if (entity) { call_data.block = getMetaData(entity); call_data.id = call_data.block.entityIndex(entity); @@ -2268,8 +2391,9 @@ export struct EntityManager foreach (caller; events[i].callers) { call_data.system_pointer = caller.system.m_system_pointer; - (cast(void function(ref EventCallData) nothrow @nogc) caller - .callback)(call_data); + (cast(void function( + ref EventCallData) nothrow @nogc) caller.callback)( + call_data); } } event_pointer += events[i].size; @@ -2360,7 +2484,7 @@ export struct EntityManager index = 0; out_for: foreach (caller2; pass.system_callers) { - if ( caller is caller2) + if (caller is caller2) continue; foreach (cmp; caller.system.m_read_only_components) { @@ -2448,8 +2572,7 @@ export struct EntityManager caller.dependencies = Mallocator.makeArray(exclusion[0 .. index]); /*caller.dependencies = Mallocator.makeArray!(SystemCaller*)(index); caller.dependencies[0..$] = exclusion[0 .. index];*/ - caller.job_group.dependencies = Mallocator.makeArray!( - JobGroup*)(index); + caller.job_group.dependencies = Mallocator.makeArray!(JobGroup*)(index); foreach (j, dep; caller.dependencies) { @@ -2467,7 +2590,9 @@ export struct EntityManager */ struct ComponentInfo { - export ~this() nothrow @nogc {} + export ~this() nothrow @nogc + { + } ///Component size ushort size; ///Component data alignment @@ -2535,37 +2660,42 @@ export struct EntityManager EntityInfo* getNewInfoAdd(ushort id) { - if(comp_add_info.length < id) + if (comp_add_info.length < id) { - EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)(instance.components.length); - if(comp_add_info !is null) + EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)( + instance.components.length); + if (comp_add_info !is null) { //new_infos[0 .. comp_add_info.length] = comp_add_info[0 .. $]; - memcpy(new_infos.ptr, comp_add_info.ptr, (EntityInfo*).sizeof * comp_add_info.length); + memcpy(new_infos.ptr, comp_add_info.ptr, (EntityInfo*) + .sizeof * comp_add_info.length); Mallocator.dispose(comp_add_info); } comp_add_info = new_infos; } - if(comp_add_info[id])return comp_add_info[id]; + if (comp_add_info[id]) + return comp_add_info[id]; ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (components.length + 1)))[0 - .. components.length + 1]; + .. components.length + 1]; uint len = 0; - foreach(comp; components) + foreach (comp; components) { - if(id > comp) + if (id > comp) { ids[len++] = comp; } - else if(id == comp)return &this; - else + else if (id == comp) + return &this; + else { ids[len++] = id; ids[len++] = comp; } } - if(id > components[$ - 1])ids[len++] = id; + if (id > components[$ - 1]) + ids[len++] = id; assert(len == components.length + 1); @@ -2577,31 +2707,35 @@ export struct EntityManager EntityInfo* getNewInfoRemove(ushort id) { - if(comp_rem_info.length < id) + if (comp_rem_info.length < id) { - EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)(instance.components.length); - if(comp_rem_info !is null) + EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)( + instance.components.length); + if (comp_rem_info !is null) { //new_infos[0 .. comp_rem_info.length] = comp_rem_info[0 .. $]; - memcpy(new_infos.ptr, comp_rem_info.ptr, (EntityInfo*).sizeof * comp_rem_info.length); + memcpy(new_infos.ptr, comp_rem_info.ptr, (EntityInfo*) + .sizeof * comp_rem_info.length); Mallocator.dispose(comp_rem_info); } comp_rem_info = new_infos; } - if(comp_rem_info[id])return comp_rem_info[id]; + if (comp_rem_info[id]) + return comp_rem_info[id]; ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (components.length - 1)))[0 - .. components.length - 1]; + .. components.length - 1]; uint len = 0; - foreach(comp; components) + foreach (comp; components) { - if(id != comp) + if (id != comp) { ids[len++] = comp; } } - if(len == components.length)return &this; + if (len == components.length) + return &this; assert(len == components.length - 1); @@ -2613,13 +2747,20 @@ export struct EntityManager export ~this() @nogc nothrow { - if(components)Mallocator.dispose(components); - if(deltas)Mallocator.dispose(deltas); - if(tmpl_deltas)Mallocator.dispose(tmpl_deltas); - if(systems)Mallocator.dispose(systems); - if(add_listeners)Mallocator.dispose(add_listeners); - if(remove_listeners)Mallocator.dispose(remove_listeners); - if(change_listeners)Mallocator.dispose(change_listeners); + if (components) + Mallocator.dispose(components); + if (deltas) + Mallocator.dispose(deltas); + if (tmpl_deltas) + Mallocator.dispose(tmpl_deltas); + if (systems) + Mallocator.dispose(systems); + if (add_listeners) + Mallocator.dispose(add_listeners); + if (remove_listeners) + Mallocator.dispose(remove_listeners); + if (change_listeners) + Mallocator.dispose(change_listeners); } ///entity components @@ -2722,6 +2863,8 @@ export struct EntityManager System* system; ///poiner to Entity type info EntityManager.EntityInfo* info; + ///delegate function to call (by default it's delegate to onUpdate call) + void delegate() update_delegate; ///pointer to first block into process (if 0 then first block will be used) EntitiesBlock* first_block; @@ -2772,7 +2915,7 @@ export struct EntityManager { Mallocator.dispose(dependencies); } - if(exclusion) + if (exclusion) { Mallocator.dispose(exclusion); } @@ -2803,7 +2946,7 @@ export struct EntityManager assert(name); if (name) Mallocator.dispose(name); - foreach(caller; system_callers) + foreach (caller; system_callers) { Mallocator.dispose(caller); } @@ -2845,9 +2988,9 @@ export struct EntityManager alias SytemFuncType = void function(ref EntityManager.CallData data) nothrow @nogc; ///Single page size. Must be power of two. - enum page_size = 32768; //4096; + int m_page_size = 32768; //32768; //4096; ///Number of pages in block. - enum pages_in_block = 128; + int m_pages_in_block = 128; IDManager id_manager; BlockAllocator allocator; @@ -2880,7 +3023,7 @@ export struct EntityManager export ~this() nothrow @nogc { - foreach(block;blocks) + foreach (block; blocks) { Mallocator.dispose(block); } diff --git a/source/ecs/system.d b/source/ecs/system.d index 30e9389..c63a2b2 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -77,9 +77,9 @@ struct System /************************************************************************************************************************ *Get system name. */ - export const (char)[] name() nothrow @nogc + export const(char)[] name() nothrow @nogc { - return cast(const (char)[])m_name; + return cast(const(char)[]) m_name; } struct EventCaller @@ -120,10 +120,13 @@ package: ushort[] m_read_only_components; ushort[] m_modified_components; + EntityManager.SystemCaller* m_any_system_caller; + EventCaller[] m_event_callers; //void function(ref EntityManager.CallData data) m_update; void* m_update; ///workaroud for DMD bug with upper line + void delegate() m_update_delegate; //void function(void* system_pointer) m_enable; //void function(void* system_pointer) m_disable; diff --git a/tests/tests.d b/tests/tests.d index 703f391..9f432fa 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -501,6 +501,20 @@ struct TestSystem2 } +struct ExternalUpdateCallTest +{ + int print_count = 3; + + void update(TestSystem2.EntitiesData data) + { + if(print_count > 0) + { + print_count--; + printf("ExternalUpdateCallTest %u %u\n", data.test[0].gg, cast(uint)data.length); + } + } +} + extern(C) int main() { @@ -660,8 +674,6 @@ extern(C) int main() gEM.registerSystem!TestSystem2(0); gEM.endRegister(); - System* sys = EntityManager.instance.getSystem(TestSystem2.system_id); - //gEM.generateDependencies(); //assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+24)) == EntityID(1,1)); @@ -799,6 +811,12 @@ extern(C) int main() gEM.commit(); + System* sys = EntityManager.instance.getSystem(TestSystem2.system_id); + + ExternalUpdateCallTest external_update_test; + + EntityManager.instance.callEntitiesFunction!TestSystem2(&external_update_test.update); + printf("pre end\n"); writeEntityComponents(gEM.getEntity(entity));