module ecs.events; import ecs.manager; import ecs.block_allocator; import ecs.entity; import std.experimental.allocator; import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator; import std.algorithm.comparison : max; /*struct Event { uint id; }*/ //mixin template EventManagerCode() struct EventManager { //@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); } 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 initialize(EntityManager m) nothrow @nogc { allocator = BlockAllocator(events_block_size, events_blocks_in_allocation); manager = m; } void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) nothrow @nogc { uint block_id = current_index+thread_id; EventData* data = &events[Ev.event_id]; EventBlock* block = data.blocks[block_id]; EntityManager.EventInfo* info = &gEM.events[Ev.event_id]; event.entity_id = id; if(block is null) { block = cast(EventBlock*) allocator.getBlock(); *block = EventBlock(); data.first_blocks[block_id] = block; data.blocks[block_id] = block; } if(block.count >= data.max_events) { EventBlock* new_block = cast(EventBlock*) allocator.getBlock(); *new_block = EventBlock(); block.next = new_block; block = new_block; data.blocks[block_id] = block; } /*void* start = cast(void*)block + data.data_offset + block.count * info.size; Ev* event_ptr = cast(Ev*)start; *event_ptr = event;*/ Ev* event_array = cast(Ev*)(cast(void*)block + data.data_offset); event_array[block.count] = event; block.count++; } void swapCurrent() nothrow @nogc { uint threads_count = cast(uint)manager.threads.length; if(current_index == 0)current_index = threads_count; else current_index = 0; foreach(ref event;events) { foreach(ref first_block; event.first_blocks[current_index .. current_index + threads_count]) { EventBlock* block = first_block; while(block) { EventBlock* to_dispose = block; block = block.next; allocator.freeBlock(to_dispose); } first_block = null; } foreach(ref block; event.blocks[current_index .. current_index + threads_count]) { block = null; } } } void clearEvents() nothrow @nogc { uint threads_count = cast(uint)manager.threads.length; foreach(ref event;events) { foreach(ref first_block; event.first_blocks) { EventBlock* block = first_block; while(block) { EventBlock* to_dispose = block; block = block.next; allocator.freeBlock(to_dispose); } first_block = null; } foreach(ref block; event.blocks) { block = null; } } /*EventList tmp = current_events; current_events = process_events; process_events = tmp; EventBlock* block = process_events.first_block; while (block) { EventBlock* free = block; block = block.next; allocator.freeBlock(free); } process_events.first_block = null; process_events.current_block = null;*/ } void allocateData(uint threads_count) nothrow @nogc { if(events) { foreach(ref event;events) { Mallocator.instance.dispose(event.blocks); Mallocator.instance.dispose(event.first_blocks); } Mallocator.instance.dispose(events); } events = Mallocator.instance.makeArray!EventData(gEM.events.length); foreach(i,ref event;events) { event.blocks = Mallocator.instance.makeArray!(EventBlock*)(threads_count*2); event.first_blocks = Mallocator.instance.makeArray!(EventBlock*)(threads_count*2); event.data_offset = EventBlock.sizeof;//gEM.events[i]. gEM.alignNum(event.data_offset, gEM.events[i].alignment); event.max_events = cast(ushort)((events_block_size - event.data_offset) / gEM.events[i].size); } } ///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; }*/ EventBlock* next; ushort count = 0; } /*struct EventList { EventBlock* first_block; EventBlock* current_block; }*/ struct EventData { ushort data_offset; ushort max_events; EventBlock*[] blocks; EventBlock*[] first_blocks; //EventBlock*[] current_blocks; } /*EventList current_events; EventList process_events;*/ uint current_index = 0; EventData[] events; BlockAllocator/*!(events_block_size, events_blocks_in_allocation)*/ allocator; EntityManager manager; }