From 4ad81fe116eeec1a151f04d19986225fad3d5b95 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 19 Sep 2018 17:50:05 +0200 Subject: [PATCH] -changes in EntityAlocator * renamed to BlockAllocator * now it's template with compile time assingable block_size and block_in_allocation variables -WIP Event management * probably working sendSelfEvent() * registerEvent() -added win_dll.d as Windows DLL require functionality --- dub.json | 5 +- .../{entity_allocator.d => block_allocator.d} | 20 +-- source/ecs/events.d | 118 ++++++++++++++++- source/ecs/manager.d | 119 ++++++++++++------ source/win_dll.d | 30 +++++ tests/tests.d | 29 ++++- 6 files changed, 264 insertions(+), 57 deletions(-) rename source/ecs/{entity_allocator.d => block_allocator.d} (51%) create mode 100644 source/win_dll.d diff --git a/dub.json b/dub.json index 2312e33..03ad2af 100755 --- a/dub.json +++ b/dub.json @@ -15,7 +15,10 @@ { "name" : "tests", "sourcePaths" : ["source\/","tests\/"], - "targetType" : "executable" + "targetType" : "executable", + "excludedSourceFiles":[ + "source\/win_dll.d" + ] }, { "name" : "dynlib", diff --git a/source/ecs/entity_allocator.d b/source/ecs/block_allocator.d similarity index 51% rename from source/ecs/entity_allocator.d rename to source/ecs/block_allocator.d index 9c9b0ff..cfb1d13 100644 --- a/source/ecs/entity_allocator.d +++ b/source/ecs/block_allocator.d @@ -1,11 +1,11 @@ -module ecs.entity_allocator; +module ecs.block_allocator; import ecs.manager; import std.experimental.allocator; import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; -struct EntityAllocator +struct BlockAllocator(uint block_size, uint blocks_in_allocation) { void* next_block; @@ -18,17 +18,23 @@ struct EntityAllocator return ret; } + void freeBlock(void* block) + { + *cast(void**)block = next_block; + next_block = block; + } + private void allocBlock() { next_block = cast(void*) AlignedMallocator.instance.alignedAllocate( - EntityManager.page_size * EntityManager.pages_in_block, EntityManager.page_size); - foreach (i; 0 .. EntityManager.pages_in_block - 1) + block_size * blocks_in_allocation, block_size); + foreach (i; 0 .. blocks_in_allocation - 1) { - void** pointer = cast(void**)(next_block + i * EntityManager.page_size); - *pointer = next_block + (i + 1) * EntityManager.page_size; + void** pointer = cast(void**)(next_block + i * block_size); + *pointer = next_block + (i + 1) * block_size; } void** pointer = cast(void**)( - next_block + (EntityManager.pages_in_block - 1) * EntityManager.page_size); + next_block + (blocks_in_allocation - 1) * block_size); *pointer = null; } } diff --git a/source/ecs/events.d b/source/ecs/events.d index 3807456..3a09bc8 100644 --- a/source/ecs/events.d +++ b/source/ecs/events.d @@ -1,11 +1,125 @@ module ecs.events; +import ecs.manager; +import ecs.block_allocator; +import ecs.entity; + +import std.algorithm.comparison : max; + +/* struct Event { uint type; -} +}*/ -class EventManager +mixin template EventManagerCode() { + //@disable this(); + + this(EntityManager m) + { + manager = m; + } + + void sendSelfEvent(Ev)(EntityID id, Ev event) + { + ushort size = cast(ushort)(Ev.sizeof); // + EntityID.sizeof + ushort.sizeof); + ushort alignment = cast(ushort)(Ev.alignof); + + EventList* list = &process_events; + + if (list.current_block is null) + { + list.current_block = cast(EventBlock*) allocator.getBlock(); + list.first_block = list.current_block; + list.current_block.index = cast(ushort)((void*).sizeof + ushort.sizeof); + } + + ushort index = cast(ushort)( + list.current_block.index + ushort.sizeof + EntityID.sizeof + ushort.sizeof); + + ushort aligned_index = index; //cast(ushort)(list.current_block.index); + alignNum(aligned_index, alignment); + + if (aligned_index + Ev.sizeof > events_block_size) + { + list.current_block.next = cast(EventBlock*) allocator.getBlock(); + list.current_block = list.current_block.next; + list.current_block.index = cast(ushort)((void*).sizeof + ushort.sizeof); + + index = cast(ushort)((void*) + .sizeof + ushort.sizeof + ushort.sizeof + EntityID.sizeof + ushort.sizeof); // + EntityID.sizeof + ushort.sizeof; + + aligned_index = index; + alignNum(aligned_index, alignment); + /*if(alignment > EntityID.sizeof + uint.sizeof)aligned_index = alignment; + else aligned_index = uint.sizeof * 4;*/ + } + + EventBlock* block = list.current_block; + + ushort align_ = cast(ushort)(aligned_index - index); + *cast(ushort*)&block.data[block.index] = align_; + index = cast(ushort)(aligned_index - (EntityID.sizeof + ushort.sizeof)); + *cast(ushort*)&block.data[index] = Ev.event_id; + *cast(EntityID*)&block.data[index + 2] = id; + *cast(Ev*)&block.data[aligned_index] = event; + block.index = cast(ushort)(aligned_index + Ev.sizeof); + } + + void clearEvents() + { + EventList tmp = current_events; + current_events = process_events; + process_events = tmp; + + EventBlock* block = process_events.first_block; + + /*if(block) + { + import std.stdio; + writeln(block.data); + }*/ + + while (block) + { + EventBlock* free = block; + block = block.next; + allocator.freeBlock(free); + } + process_events.first_block = null; + process_events.current_block = null; + } + + ///Single page size. Must be power of two. + enum events_block_size = 1 << 12; + ///Number of pages in block. + enum events_blocks_in_allocation = 128; + + struct EventBlock + { + union + { + struct + { + EventBlock* next; + ushort index = 2; + } + + ubyte[events_block_size] data; + } + } + + struct EventList + { + EventBlock* first_block; + EventBlock* current_block; + } + + EventList current_events; + EventList process_events; + + BlockAllocator!(events_block_size, events_blocks_in_allocation) allocator; + EntityManager manager; } diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 4b7b295..4c245f6 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -10,11 +10,12 @@ import core.stdc.stdlib; import core.stdc.string; import ecs.entity; -import ecs.entity_allocator; +import ecs.block_allocator; import ecs.hash_map; import ecs.id_manager; import ecs.system; import ecs.vector; +import ecs.events; alias gEM = EntityManager.instance; alias SerializeVector = ecs.vector.Vector!ubyte; @@ -24,11 +25,14 @@ class EntityManager export static void initialize() { - instance = Mallocator.instance.make!EntityManager; + if (instance is null) + instance = Mallocator.instance.make!EntityManager; } export static void destroy() { + if (instance is null) + return; foreach (ref system; instance.systems) { @@ -45,6 +49,12 @@ class EntityManager instance = null; } + this() + { + //event_manager = EventManager(this); + //event_manager.manager = this; + } + void registerSystem(Sys)(int priority) { alias types = Parameters!(Sys.update); @@ -205,14 +215,14 @@ class EntityManager mixin(genCompList()); ushort sys_id = systems_map.get(Sys.stringof, ushort.max); - if(sys_id < systems.length) + if (sys_id < systems.length) { system.enable(); systems[sys_id] = system; } else { - systems_map.add(Sys.stringof,cast(ushort)systems.length); + systems_map.add(Sys.stringof, cast(ushort) systems.length); systems.add(system); @@ -232,7 +242,6 @@ class EntityManager void registerComponent(Comp)() { - ComponentInfo info; static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort)) @@ -253,12 +262,12 @@ class EntityManager } info.size = Comp.sizeof; - info.aligment = Comp.alignof; //8; + info.alignment = Comp.alignof; //8; info.init_data = Mallocator.instance.makeArray!ubyte(Comp.sizeof); *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); ushort comp_id = components_map.get(Comp.stringof, ushort.max); - if(comp_id < components.length) + if (comp_id < components.length) { Comp.component_id = comp_id; } @@ -270,6 +279,42 @@ class EntityManager } } + void registerEvent(Ev)() + { + EventInfo info; + + static if (!(hasMember!(Ev, "event_id")) || !is(typeof(Ev.event_id) == ushort)) + { + static assert(0, "Event should have \"__gshared ushort event_id"); + } + + static if (hasMember!(Ev, "onDestroy") && isFunction!(Ev.onDestroy) + && is(ReturnType!(Ev.onDestroy) == void) && Parameters!(Ev.onDestroy).length == 0) + { + static void callDestroy(void* pointer) + { + (cast(Ev*) pointer).onDestroy(); + } + + info.destroy_callback = &callDestroy; + } + + info.size = Ev.sizeof; + info.alignment = Ev.alignof; + + ushort event_id = events_map.get(Ev.stringof, ushort.max); + if (event_id < events.length) + { + Ev.event_id = event_id; + } + else + { + events.add(info); + Ev.event_id = cast(ushort)(events.length - 1); + events_map.add(Ev.stringof, cast(ushort)(events.length - 1)); + } + } + export void update() { foreach (info; &entities_infos.byValue) @@ -282,9 +327,9 @@ class EntityManager } } - static void alignNum(ref ushort num, ushort aligment) + static void alignNum(ref ushort num, ushort alignment) { - num = cast(ushort)((num + aligment - 1) & (-cast(int) aligment)); //num += aligment - (num & (aligment - 1)); + num = cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); //num += alignment - (num & (alignment - 1)); } extern (C) static int compareUShorts(const void* a, const void* b) @@ -352,8 +397,8 @@ class EntityManager foreach (i, id; ids) { - info.alignment = max(info.alignment, components[id].aligment); - alignNum(info.size, components[id].aligment); + info.alignment = max(info.alignment, components[id].alignment); + alignNum(info.size, components[id].alignment); info.deltas[id] = info.size; info.size += components[id].size; } @@ -874,16 +919,25 @@ class EntityManager updateBlocks(); changeEntites(); removeEntities(); + + clearEvents(); } struct ComponentInfo { ushort size; - ushort aligment; + ushort alignment; ubyte[] init_data; void function(void* pointer) destroy_callback; } + struct EventInfo + { + ushort size; + ushort alignment; + void function(void* pointer) destroy_callback; + } + /************************************************************************************************************************ *Entity type info. */ @@ -893,7 +947,7 @@ class EntityManager ushort[] components; ///deltas in memory for components ushort[] deltas; - ///aligment of whole entity + ///alignment of whole entity ushort alignment; ///size of entity (with alignment respect) ushort size; @@ -956,13 +1010,20 @@ class EntityManager alias SytemFuncType = void function(ref EntityManager.CallData data, void* entity); + //alias sendSelfEvent = instance.event_manager.sendSelfEvent; + + //alias event_manager this; + ///Single page size. Must be power of two. enum page_size = 4096; ///Number of pages in block. enum pages_in_block = 128; IDManager id_manager; - EntityAllocator allocator; + BlockAllocator!(page_size, pages_in_block) allocator; + + //EventManager event_manager; + mixin EventManagerCode; Vector!EntityID entities_to_remove; Vector!(EntitiesBlock*) blocks_to_update; @@ -971,37 +1032,13 @@ class EntityManager HashMap!(ushort[], EntityInfo*) entities_infos; HashMap!(string, ushort) systems_map; HashMap!(string, ushort) components_map; + HashMap!(string, ushort) events_map; Vector!System systems; Vector!ComponentInfo components; - __gshared EntityManager instance; - + Vector!EventInfo events; + __gshared EntityManager instance = null; } -version(Windows) -extern(Windows) bool DllMain(void* hInstance, uint ulReason, void*) { -import core.sys.windows.windows; -import core.sys.windows.dll; - switch (ulReason) -{ - default: assert(0); -case DLL_PROCESS_ATTACH: - dll_process_attach( hInstance, true ); - break; - -case DLL_PROCESS_DETACH: - dll_process_detach( hInstance, true ); - break; - -case DLL_THREAD_ATTACH: - dll_thread_attach( true, true ); - break; - -case DLL_THREAD_DETACH: - dll_thread_detach( true, true ); - break; - } - return true; -} /* static ulong defaultHashFunc(T)(auto ref T t) { diff --git a/source/win_dll.d b/source/win_dll.d new file mode 100644 index 0000000..c417b45 --- /dev/null +++ b/source/win_dll.d @@ -0,0 +1,30 @@ +module win_dll; + +version(Windows): + +import core.sys.windows.dll; +import core.sys.windows.windows; + +extern(Windows) bool DllMain(void* hInstance, uint ulReason, void*) +{ + switch (ulReason) + { + default: assert(0); + case DLL_PROCESS_ATTACH: + dll_process_attach( hInstance, true ); + break; + + case DLL_PROCESS_DETACH: + dll_process_detach( hInstance, true ); + break; + + case DLL_THREAD_ATTACH: + dll_thread_attach( true, true ); + break; + + case DLL_THREAD_DETACH: + dll_thread_detach( true, true ); + break; + } + return true; +} \ No newline at end of file diff --git a/tests/tests.d b/tests/tests.d index c0f9b05..3d755be 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -10,6 +10,19 @@ import std.stdio; int main() { + + struct TestEvent + { + __gshared ushort event_id; + int a; + } + + struct TestEvent2 + { + __gshared ushort event_id; + float a; + } + struct TestComp { __gshared ushort component_id; @@ -124,7 +137,7 @@ int main() test3.gg = 200; } - void handleEvent(Event event, ref TestComp comp) + void handleEvent(TestEvent event, ref TestComp test, ref TestComp2 test2, TestComp3* test3) { } @@ -145,10 +158,10 @@ int main() //writeln("High priority tekst! "); } - void handleEvent(Event event, ref TestComp comp) + /*void handleEvent(Event event, ref TestComp comp) { - } + }*/ } struct TestSystem2 @@ -177,12 +190,13 @@ int main() { //writeln("TestSystem2 update"); test.gg += 14; + gEM.sendSelfEvent!(TestEvent)(entity.id, TestEvent()); } - void handleEvent(Event event, ref TestComp comp) + /*void handleEvent(Event event, ref TestComp comp) { - } + }*/ } EntityManager.initialize(); @@ -195,6 +209,9 @@ int main() gEM.registerComponent!TestComp; gEM.registerComponent!TestComp3; + gEM.registerEvent!TestEvent; + gEM.registerEvent!TestEvent2; + ulong dur = (MonoTime.currTime - time).total!"usecs"; writeln("Components register: ", dur, " usecs"); @@ -288,7 +305,7 @@ int main() writeln((cast(uint*) pp)[0 .. 14], " ", pp); - gEM.removeComponents!(TestComp)(entity.id); + //gEM.removeComponents!(TestComp)(entity.id); gEM.begin(); gEM.update();