// D import file generated from 'source\ecs\manager.d' module ecs.manager; import std.algorithm : max; import std.conv : to; import std.experimental.allocator; import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; import std.traits; import core.stdc.stdlib; import core.stdc.string; import ecs.entity; import ecs.entity_allocator; import ecs.hash_map; import ecs.id_manager; import ecs.system; import ecs.vector; alias gEM = EntityManager.instance; alias SerializeVector = ecs.vector.Vector!ubyte; class EntityManager { export static void initialize(); export static void destroy(); export void registerSystem(Sys)(int priority) { alias types = Parameters!(Sys.update); alias storages = ParameterStorageClassTuple!(Sys.update); alias STC = ParameterStorageClass; System system; static string genCall()() { string ret = "s.update(*cast(Entity*)data_pointer,"; uint i = 0; uint req = 0; uint opt = 0; static foreach (param; Parameters!(Sys.update)[1..$]) { i++; if (isPointer!param) { ret ~= "cast(types[" ~ i.to!string ~ "])(optional_pointers[" ~ opt++.to!string ~ "]),"; } else { ret ~= "*cast(types[" ~ i.to!string ~ "]*)(pointers[" ~ req++.to!string ~ "]),"; } } ret ~= ");"; return ret; } static string genCompList()() { string ret = "ushort comp;uint req;uint opt;"; foreach (i; 1 .. (Parameters!(Sys.update)).length) { ret ~= "\x0a static if(isPointer!(types[" ~ i.to!string ~ "]))opt++;\x0a else static if(storages[" ~ i.to!string ~ "] == STC.ref_)req++;\x0a\x0a else static assert(0,\"Can't register system \\\"" ~ Sys.stringof ~ "\\\". Unsupported parameter type \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\");"; } ret ~= "system.m_components = Mallocator.instance.makeArray!ushort(req);"; ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(opt);"; ret ~= "opt = 0;req = 0;"; foreach (i; 1 .. (Parameters!(Sys.update)).length) { ret ~= "\x0a static if(isPointer!(types[" ~ i.to!string ~ "]))\x0a {\x0a comp = components_map.get(PointerTarget!(types[" ~ i.to!string ~ "]).stringof, ushort.max);\x0a\x0a if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof ~ "\\\" due to non existing component \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\");\x0a system.m_optional_components[opt++] = comp;\x0a }\x0a else static if(storages[" ~ i.to!string ~ "] == STC.ref_)\x0a {\x0a comp = components_map.get(types[" ~ i.to!string ~ "].stringof, ushort.max);\x0a\x0a if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof ~ "\\\" due to non existing component \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\");\x0a system.m_components[req++] = comp;\x0a }"; } return ret; } static string catchFunc()(string member, string func) { string ret = "static if (hasMember!(Sys, \"" ~ func ~ "\"))\x0a {\x0a static void call" ~ func ~ "(void* system_pointer)\x0a {\x0a\x0a Sys* s = cast(Sys*) system_pointer;\x0a s." ~ func ~ "();\x0a }\x0a\x0a system." ~ member ~ " = &call" ~ func ~ ";\x0a }"; return ret; } static if (hasMember!(Sys, "update")) { static void callUpdate(ref CallData data, void* entity) { static if (hasMember!(Sys, "update")) { Sys* s = cast(Sys*) data.system.m_system_pointer; void*[] pointers = (cast(void**) alloca(data.system.m_components.length * (void*) .sizeof))[0 .. data.system.m_components.length]; void*[] optional_pointers = (cast(void**) alloca( data.system.m_optional_components.length * (void*).sizeof))[0 .. data.system.m_optional_components.length]; EntitiesBlock* block = data.info.first_block; while (block !is null) { uint size = block.type_data.size; void* data_pointer = block.dataBegin(); foreach (i, ref pointer; pointers) { pointer = data_pointer + data.deltas[i]; } foreach (i, ref pointer; optional_pointers) { uint ind = cast(uint)(i + pointers.length); if (data.deltas[ind] != uint.max) pointer = data_pointer + data.deltas[ind]; else pointer = null; } foreach (i; 0 .. block.entities_count) { mixin(genCall()); data_pointer += size; //data.info.size; foreach (ref pointer; pointers) pointer += size; foreach (ref pointer; optional_pointers) if (pointer != null) pointer += size; } block = block.next_block; } } } system.m_update = &callUpdate; } mixin(catchFunc("m_enable", "onEnable")); mixin(catchFunc("m_disable", "onDisable")); mixin(catchFunc("m_create", "onCreate")); mixin(catchFunc("m_destroy", "onDestroy")); mixin(catchFunc("m_begin", "onBegin")); mixin(catchFunc("m_end", "onEnd")); system.m_system_pointer = cast(void*)Mallocator.instance.make!Sys; system.m_priority = priority; mixin(genCompList()); ushort sys_id = systems_map.get(Sys.stringof, (ushort).max); if (sys_id < systems.length) { system.enable(); systems[sys_id] = system; } else { systems_map.add(Sys.stringof, cast(ushort)systems.length); systems.add(system); if (system.m_create) system.m_create(system.m_system_pointer); systems[$ - 1].enable(); foreach (info; &entities_infos.byValue) { addEntityCaller(*info, cast(uint)systems.length - 1); } } updateEntityCallers(); } void registerComponent(Comp)() { ComponentInfo info; static if (!hasMember!(Comp, "component_id") || !is(typeof(Comp.component_id) == ushort)) { static assert(0, "Component should have \"__gshared ushort component_id"); } static if (hasMember!(Comp, "onDestroy") && isFunction!(Comp.onDestroy) && is(ReturnType!(Comp.onDestroy) == void) && (Parameters!(Comp.onDestroy).length == 0)) { static void callDestroy(void* pointer) { (cast(Comp*) pointer).onDestroy(); } info.destroy_callback = &callDestroy; } info.size = Comp.sizeof; info.aligment = Comp.alignof; info.init_data = Mallocator.instance.makeArray!ubyte(Comp.sizeof); *cast(Comp*)info.init_data.ptr = Comp.init; ushort comp_id = components_map.get(Comp.stringof, (ushort).max); if (comp_id < components.length) { Comp.component_id = comp_id; } else { components.add(info); Comp.component_id = cast(ushort)(components.length - 1); components_map.add(Comp.stringof, cast(ushort)(components.length - 1)); } } export void update(); static void alignNum(ref ushort num, ushort aligment); extern (C) static int compareUShorts(const void* a, const void* b); export EntityTemplate* allocateTemplate(ushort[] components_ids); export EntityInfo* getEntityInfo(ushort[] ids); export void updateEntityCallers(); export void addEntityCaller(ref EntityInfo entity, uint system_id); export Entity* getEntity(EntityID id); export void removeComponents(EntityID entity_id, ushort[] del_ids); private void __removeComponents(EntityID entity_id, ushort[] del_ids); void removeComponents(Components...)(EntityID entity_id) { const uint num = Components.length; ushort[num] del_ids; static foreach (i, comp; Components) { del_ids[i] = comp.component_id; } removeComponents(entity_id, del_ids); } private void __addComponents(EntityID entity_id, ushort[] new_ids, void*[] data_pointers); void addComponents(Components...)(EntityID entity_id, Components comps) { const uint num = Components.length; Entity* entity = id_manager.getEntityPointer(entity_id); EntitiesBlock* block = getMetaData(entity); EntityInfo* info = block.type_data; ushort[] ids = (cast(ushort*)alloca((ushort).sizeof * (info.components.length + num)))[0..info.components.length + num]; ushort[num] new_ids; static foreach (i, comp; Components) { new_ids[i] = comp.component_id; } change_entities_list.add(1); change_entities_list.add((cast(ubyte*)&entity_id)[0..8]); change_entities_list.add((cast(ubyte*)&num)[0..4]); change_entities_list.add(cast(ubyte[])new_ids); static foreach (i, comp; comps) { change_entities_list.add((cast(ubyte*)&comp)[0..comp.sizeof]); } } export void freeTemplate(EntityTemplate* template_); export ref Entity addEntity(EntityTemplate* tmpl); private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info); export void removeEntity(EntityID id); private void __removeEntity(EntityID id); private void removeEntityNoID(Entity* entity, EntitiesBlock* block, bool call_destructors = false); export EntitiesBlock* getMetaData(void* pointer); private void changeEntites(); private void updateBlocks(); private void removeEntities(); export void begin(); export void end(); struct ComponentInfo { ushort size; ushort aligment; ubyte[] init_data; void function(void* pointer) destroy_callback; } struct EntityInfo { ushort[] components; ushort[] deltas; ushort alignment; ushort size; EntitiesBlock* first_block; EntitiesBlock* first_with_free_space; Vector!CallData callers; } struct EntitiesBlock { uint dataDelta(); void* dataBegin(); EntityInfo* type_data; ushort entities_count; ushort added_count; uint id; EntitiesBlock* next_block; } struct CallData { uint system_id; System* system; EntityManager.EntityInfo* info; ushort[] deltas; } alias SytemFuncType = void function(ref EntityManager.CallData data, void* entity); enum page_size = 4096; enum pages_in_block = 128; IDManager id_manager; EntityAllocator allocator; Vector!EntityID entities_to_remove; Vector!(EntitiesBlock*) blocks_to_update; Vector!ubyte change_entities_list; HashMap!(ushort[], EntityInfo*) entities_infos; HashMap!(string, ushort) systems_map; HashMap!(string, ushort) components_map; Vector!System systems; Vector!ComponentInfo components; __gshared EntityManager instance; } version (Windows) { extern (Windows) bool DllMain(void* hInstance, uint ulReason, void*); }