-BlockAllocator is no longer template
-Multithreaded IDManager.getNewID() *use implementation with free IDs stack (instead of classic pool) -support for multiple UpdatePasses. Passes are added by name, and must be called between begin() end() functions. -removed mutex from addEntity() -commit() function added. Used to commit all changes made while update() call. Called automatically by begin() end() functions.
This commit is contained in:
parent
430ce8074c
commit
d3f7593afc
6 changed files with 406 additions and 189 deletions
|
|
@ -5,8 +5,11 @@ import ecs.manager;
|
||||||
import std.experimental.allocator;
|
import std.experimental.allocator;
|
||||||
import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;
|
import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;
|
||||||
|
|
||||||
struct BlockAllocator(uint block_size, uint blocks_in_allocation)
|
struct BlockAllocator//(uint block_size, uint blocks_in_allocation)
|
||||||
{
|
{
|
||||||
|
private uint block_size;
|
||||||
|
private uint blocks_in_allocation;
|
||||||
|
|
||||||
void* next_block = null;
|
void* next_block = null;
|
||||||
|
|
||||||
void* getBlock()
|
void* getBlock()
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,10 @@ mixin template EventManagerCode()
|
||||||
|
|
||||||
//@disable this();
|
//@disable this();
|
||||||
|
|
||||||
this(EntityManager m)
|
/*this(EntityManager m)
|
||||||
{
|
{
|
||||||
manager = m;
|
manager = m;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
void sendSelfEvent(Ev)(EntityID id, Ev event)
|
void sendSelfEvent(Ev)(EntityID id, Ev event)
|
||||||
{
|
{
|
||||||
|
|
@ -120,6 +120,6 @@ mixin template EventManagerCode()
|
||||||
EventList current_events;
|
EventList current_events;
|
||||||
EventList process_events;
|
EventList process_events;
|
||||||
|
|
||||||
BlockAllocator!(events_block_size, events_blocks_in_allocation) allocator;
|
BlockAllocator/*!(events_block_size, events_blocks_in_allocation)*/ allocator;
|
||||||
EntityManager manager;
|
EntityManager manager;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,15 @@
|
||||||
module ecs.id_manager;
|
module ecs.id_manager;
|
||||||
|
|
||||||
|
import std.experimental.allocator;
|
||||||
|
import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;
|
||||||
|
|
||||||
import ecs.entity;
|
import ecs.entity;
|
||||||
import ecs.vector;
|
import ecs.vector;
|
||||||
|
|
||||||
|
import core.atomic;
|
||||||
|
import core.stdc.string : memcpy;
|
||||||
|
import core.sync.mutex;
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
*IDManager is responsible for assignment and removing IDs. IDs are unique throughtout a whole duration of the program.
|
*IDManager is responsible for assignment and removing IDs. IDs are unique throughtout a whole duration of the program.
|
||||||
*/
|
*/
|
||||||
|
|
@ -11,19 +18,64 @@ struct IDManager
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
*Get new ID.
|
*Get new ID.
|
||||||
*/
|
*/
|
||||||
EntityID getNewID()
|
pragma(inline, false) EntityID getNewID()
|
||||||
{
|
{
|
||||||
if (m_next_id >= m_ids_array.length)
|
//uint current = m_next_id;
|
||||||
m_ids_array.add(Data());
|
//uint next;// = m_ids_array[m_next_id].next_id;
|
||||||
|
begin:
|
||||||
|
//if (current == uint.max)//> m_last_id)
|
||||||
|
int current = m_stack_top.atomicOp!"-="(1) + 1;
|
||||||
|
if(current < 0)
|
||||||
|
{
|
||||||
|
uint add_id = m_last_id.atomicOp!"+="(1) - 1;
|
||||||
|
|
||||||
|
if (add_id >= m_ids_array.length)
|
||||||
|
{
|
||||||
|
uint local_id = add_id - cast(uint) m_ids_array.length;
|
||||||
|
uint block_id = local_id >> 16;
|
||||||
|
if (block_id >= m_blocks_count)
|
||||||
|
{
|
||||||
|
add_mutex.lock();
|
||||||
|
if(block_id >= m_blocks_count)
|
||||||
|
{
|
||||||
|
m_blocks[m_blocks_count].alloc();
|
||||||
|
m_blocks_count++;
|
||||||
|
}
|
||||||
|
add_mutex.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EntityID id;
|
EntityID id;
|
||||||
id.id = m_next_id;
|
id.id = add_id;
|
||||||
id.counter = /*++*/m_ids_array[m_next_id].counter;
|
id.counter = 0;
|
||||||
m_next_id = m_ids_array[m_next_id].next_id;
|
|
||||||
if (m_next_id == uint.max)
|
|
||||||
m_next_id = cast(uint) m_ids_array.length;
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//current += 1;
|
||||||
|
uint index = m_free_stack[current];
|
||||||
|
EntityID id;
|
||||||
|
id.id = index;
|
||||||
|
id.counter = m_ids_array[index].counter;
|
||||||
|
//current = m_ids_array[index].next_id;
|
||||||
|
return id;
|
||||||
|
|
||||||
|
/*next = m_ids_array[current].next_id;
|
||||||
|
if(cas(&m_next_id,current,next))
|
||||||
|
{
|
||||||
|
EntityID id;
|
||||||
|
id.id = current;
|
||||||
|
id.counter = m_ids_array[current].counter;
|
||||||
|
m_next_id = m_ids_array[current].next_id;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current = next;
|
||||||
|
goto begin;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
*Release ID.
|
*Release ID.
|
||||||
*/
|
*/
|
||||||
|
|
@ -33,9 +85,12 @@ struct IDManager
|
||||||
if (data.counter != id.counter)
|
if (data.counter != id.counter)
|
||||||
return;
|
return;
|
||||||
data.counter++;
|
data.counter++;
|
||||||
data.next_id = m_next_id;
|
//data.next_id = m_next_id;
|
||||||
data.entity = null;
|
data.entity = null;
|
||||||
m_next_id = id.id;
|
///m_next_id = id.id;
|
||||||
|
|
||||||
|
m_stack_top.atomicOp!"+="(1);
|
||||||
|
m_free_stack[m_stack_top] = id.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
|
|
@ -43,7 +98,15 @@ struct IDManager
|
||||||
*/
|
*/
|
||||||
void update(ref Entity entity)
|
void update(ref Entity entity)
|
||||||
{
|
{
|
||||||
if(entity.id.counter == m_ids_array[entity.id.id].counter)m_ids_array[entity.id.id].entity = &entity;
|
if (entity.id.id >= cast(uint) m_ids_array.length)
|
||||||
|
{
|
||||||
|
uint local_id = entity.id.id - cast(uint) m_ids_array.length;
|
||||||
|
uint block_id = local_id >> 16;
|
||||||
|
local_id -= block_id << 16;
|
||||||
|
m_blocks[block_id].data[local_id].entity = &entity;
|
||||||
|
}
|
||||||
|
else //if (entity.id.counter == m_ids_array[entity.id.id].counter)
|
||||||
|
m_ids_array[entity.id.id].entity = &entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
|
|
@ -51,6 +114,19 @@ struct IDManager
|
||||||
*/
|
*/
|
||||||
export Entity* getEntityPointer(EntityID id)
|
export Entity* getEntityPointer(EntityID id)
|
||||||
{
|
{
|
||||||
|
if (id.id >= m_ids_array.length)
|
||||||
|
{
|
||||||
|
uint local_id = id.id - cast(uint) m_ids_array.length;
|
||||||
|
uint block_id = local_id >> 16;
|
||||||
|
assert(block_id < m_blocks_count);
|
||||||
|
if (block_id >= m_blocks_count)
|
||||||
|
return null;
|
||||||
|
local_id -= block_id << 16;
|
||||||
|
if (m_blocks[block_id].data[local_id].counter != id.counter)
|
||||||
|
return null;
|
||||||
|
return m_blocks[block_id].data[local_id].entity;
|
||||||
|
}
|
||||||
|
|
||||||
Data* data = &m_ids_array[id.id];
|
Data* data = &m_ids_array[id.id];
|
||||||
if (data.counter != id.counter)
|
if (data.counter != id.counter)
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -67,16 +143,81 @@ struct IDManager
|
||||||
return data.counter == id.counter;
|
return data.counter == id.counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initialize()
|
||||||
|
{
|
||||||
|
m_ids_array = Mallocator.instance.makeArray!Data(65536);
|
||||||
|
m_free_stack = Mallocator.instance.makeArray!uint(65536);
|
||||||
|
m_blocks = Mallocator.instance.makeArray!Block(64);
|
||||||
|
m_blocks_count = 1;
|
||||||
|
m_blocks[0].alloc();
|
||||||
|
|
||||||
|
add_mutex = Mallocator.instance.make!Mutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void optimize()
|
||||||
|
{
|
||||||
|
if(m_stack_top < -1)m_stack_top = -1;
|
||||||
|
if(m_last_id > m_ids_array.length)
|
||||||
|
{
|
||||||
|
uint begin = cast(uint)m_ids_array.length;
|
||||||
|
Data[] new_array = Mallocator.instance.makeArray!Data(begin + (m_blocks_count << 16));
|
||||||
|
memcpy(new_array.ptr, m_ids_array.ptr, m_ids_array.length * Data.sizeof);
|
||||||
|
Mallocator.instance.dispose(m_ids_array);
|
||||||
|
m_ids_array = new_array;
|
||||||
|
|
||||||
|
uint[] new_stack = Mallocator.instance.makeArray!uint(m_ids_array.length);
|
||||||
|
memcpy(new_stack.ptr,m_free_stack.ptr,m_free_stack.length * uint.sizeof);
|
||||||
|
Mallocator.instance.dispose(m_free_stack);
|
||||||
|
m_free_stack = new_stack;
|
||||||
|
|
||||||
|
foreach(block;m_blocks[0..m_blocks_count-1])
|
||||||
|
{
|
||||||
|
memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, block.data.ptr, 65536 * Data.sizeof);
|
||||||
|
begin += 65536;
|
||||||
|
}
|
||||||
|
memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, m_blocks[m_blocks_count-1].data.ptr, (m_last_id - begin) * Data.sizeof);
|
||||||
|
foreach(block;m_blocks[1..m_blocks_count])block.free();
|
||||||
|
m_blocks_count = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static struct Block
|
||||||
|
{
|
||||||
|
void alloc()
|
||||||
|
{
|
||||||
|
assert(data is null);
|
||||||
|
data = Mallocator.instance.makeArray!Data(65536);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free()
|
||||||
|
{
|
||||||
|
assert(data !is null);
|
||||||
|
Mallocator.instance.dispose(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Data[] data; //65536
|
||||||
|
}
|
||||||
|
|
||||||
private static struct Data
|
private static struct Data
|
||||||
{
|
{
|
||||||
uint counter = 0;
|
uint counter = 0;
|
||||||
uint next_id = uint.max;
|
//uint next_id = uint.max;
|
||||||
Entity* entity = null;
|
Entity* entity = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint m_next_id;
|
Mutex add_mutex;
|
||||||
Vector!Data m_ids_array;
|
//shared uint m_next_id = 0;
|
||||||
|
|
||||||
|
//shared uint m_last_id = 0;
|
||||||
|
Data[] m_ids_array = null;
|
||||||
|
uint m_blocks_count = 0;
|
||||||
|
Block[] m_blocks;
|
||||||
|
//shared int m_stack_top = -1;
|
||||||
|
uint[] m_free_stack = null;
|
||||||
|
|
||||||
|
align(64) shared uint m_last_id = 0;
|
||||||
|
align(64) shared int m_stack_top = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
|
|
|
||||||
|
|
@ -59,10 +59,30 @@ class EntityManager
|
||||||
threads_count = 0;
|
threads_count = 0;
|
||||||
threads = Mallocator.instance.makeArray!ThreadData(threads_count);
|
threads = Mallocator.instance.makeArray!ThreadData(threads_count);
|
||||||
|
|
||||||
add_mutex = Mallocator.instance.make!Mutex;
|
id_manager.initialize();
|
||||||
|
|
||||||
|
allocator = BlockAllocator(page_size,pages_in_block);
|
||||||
|
|
||||||
|
//add_mutex = Mallocator.instance.make!Mutex;
|
||||||
entity_block_alloc_mutex = Mallocator.instance.make!Mutex;
|
entity_block_alloc_mutex = Mallocator.instance.make!Mutex;
|
||||||
//event_manager = EventManager(this);
|
//event_manager = EventManager(this);
|
||||||
//event_manager.manager = this;
|
//event_manager.manager = this;
|
||||||
|
|
||||||
|
UpdatePass* pass = Mallocator.instance.make!UpdatePass;
|
||||||
|
pass.name = Mallocator.instance.makeArray("update");
|
||||||
|
passes.add(pass);
|
||||||
|
|
||||||
|
passes_map.add(cast(string)pass.name, cast(ushort)(passes.length - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************************************
|
||||||
|
*Same as "void registerSystem(Sys)(int priority, int pass = 0)" but use pass name instead of id.
|
||||||
|
*/
|
||||||
|
void registerSystem(Sys)(int priority, const (char)[] pass_name)
|
||||||
|
{
|
||||||
|
ushort pass = passes_map.get(pass_name, ushort.max);
|
||||||
|
assert(pass != ushort.max);
|
||||||
|
registerSystem!(Sys)(priority, pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
|
|
@ -73,11 +93,14 @@ class EntityManager
|
||||||
*params:
|
*params:
|
||||||
*priority = system priority. Priority determines order of execution of systems updates.
|
*priority = system priority. Priority determines order of execution of systems updates.
|
||||||
*/
|
*/
|
||||||
void registerSystem(Sys)(int priority)
|
void registerSystem(Sys)(int priority, ushort pass = 0)
|
||||||
{
|
{
|
||||||
alias STC = ParameterStorageClass;
|
alias STC = ParameterStorageClass;
|
||||||
|
|
||||||
|
assert(pass < passes.length);
|
||||||
|
|
||||||
System system;
|
System system;
|
||||||
|
system.m_pass = pass;
|
||||||
|
|
||||||
static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort))
|
static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort))
|
||||||
{
|
{
|
||||||
|
|
@ -450,10 +473,6 @@ class EntityManager
|
||||||
|
|
||||||
mixin(genCompList());
|
mixin(genCompList());
|
||||||
|
|
||||||
/*if(system.m_components)qsort(system.m_components.ptr, system.m_components.length, ushort.sizeof, &compareUShorts);
|
|
||||||
if(system.m_optional_components)qsort(system.m_optional_components.ptr, system.m_optional_components.length, ushort.sizeof, &compareUShorts);
|
|
||||||
if(system.m_absent_components)qsort(system.m_absent_components.ptr, system.m_absent_components.length, ushort.sizeof, &compareUShorts);*/
|
|
||||||
|
|
||||||
ushort sys_id = systems_map.get(Sys.stringof, ushort.max);
|
ushort sys_id = systems_map.get(Sys.stringof, ushort.max);
|
||||||
if (sys_id < systems.length)
|
if (sys_id < systems.length)
|
||||||
{
|
{
|
||||||
|
|
@ -492,13 +511,13 @@ class EntityManager
|
||||||
version (UpdateBySystems)
|
version (UpdateBySystems)
|
||||||
{
|
{
|
||||||
bool added = false;
|
bool added = false;
|
||||||
foreach (i, ref caller; system_callers)
|
foreach (i, ref caller; passes[pass].system_callers)
|
||||||
{
|
{
|
||||||
if (systems[caller.system_id].priority > priority)
|
if (systems[caller.system_id].priority > priority)
|
||||||
{
|
{
|
||||||
SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller;
|
SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller;
|
||||||
sys_caller.system_id = Sys.system_id;
|
sys_caller.system_id = Sys.system_id;
|
||||||
system_callers.add(sys_caller, i);
|
passes[pass].system_callers.add(sys_caller, i);
|
||||||
added = true;
|
added = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -507,7 +526,7 @@ class EntityManager
|
||||||
{
|
{
|
||||||
SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller;
|
SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller;
|
||||||
sys_caller.system_id = Sys.system_id;
|
sys_caller.system_id = Sys.system_id;
|
||||||
system_callers.add(sys_caller);
|
passes[pass].system_callers.add(sys_caller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -525,6 +544,15 @@ class EntityManager
|
||||||
return cast(Sys*) systems[Sys.system_id].m_system_pointer;
|
return cast(Sys*) systems[Sys.system_id].m_system_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ushort registerPass(const (char)[] name)
|
||||||
|
{
|
||||||
|
UpdatePass* pass = Mallocator.instance.make!UpdatePass;
|
||||||
|
pass.name = Mallocator.instance.makeArray(name);
|
||||||
|
passes.add(pass);
|
||||||
|
passes_map.add(name,cast(ushort)(passes.length - 1));
|
||||||
|
return cast(ushort)(passes.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
*Register component into EntityManager.
|
*Register component into EntityManager.
|
||||||
*/
|
*/
|
||||||
|
|
@ -564,7 +592,7 @@ class EntityManager
|
||||||
{
|
{
|
||||||
components.add(info);
|
components.add(info);
|
||||||
Comp.component_id = cast(ushort)(components.length - 1);
|
Comp.component_id = cast(ushort)(components.length - 1);
|
||||||
string name = Mallocator.instance.makeArray(Comp.stringof);
|
const (char)[] name = Mallocator.instance.makeArray(Comp.stringof);
|
||||||
components_map.add(name, cast(ushort)(components.length - 1));
|
components_map.add(name, cast(ushort)(components.length - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -605,14 +633,25 @@ class EntityManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/************************************************************************************************************************
|
||||||
|
*Same as "void update(int pass = 0)" but use pass name instead of id.
|
||||||
|
*/
|
||||||
|
void update(const (char)[] pass_name)
|
||||||
|
{
|
||||||
|
ushort pass = passes_map.get(pass_name, ushort.max);
|
||||||
|
assert(pass != ushort.max);
|
||||||
|
update(pass);
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
*Update systems. Should be called only between begin() and end().
|
*Update systems. Should be called only between begin() and end().
|
||||||
*/
|
*/
|
||||||
export void update()
|
export void update(ushort pass = 0)
|
||||||
{
|
{
|
||||||
|
assert(pass < passes.length);
|
||||||
version (UpdateBySystems)
|
version (UpdateBySystems)
|
||||||
{
|
{
|
||||||
foreach (caller; system_callers)
|
foreach (caller; passes[pass].system_callers)
|
||||||
{
|
{
|
||||||
System* sys = &systems[caller.system_id];
|
System* sys = &systems[caller.system_id];
|
||||||
if (sys.enabled)
|
if (sys.enabled)
|
||||||
|
|
@ -644,14 +683,25 @@ class EntityManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateMT()
|
/************************************************************************************************************************
|
||||||
|
*Same as "void updateMT(int pass = 0)" but use pass name instead of id.
|
||||||
|
*/
|
||||||
|
void updateMT(const (char)[] pass_name)
|
||||||
{
|
{
|
||||||
|
ushort pass = passes_map.get(pass_name, ushort.max);
|
||||||
|
assert(pass != ushort.max);
|
||||||
|
updateMT(pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateMT(ushort pass = 0)
|
||||||
|
{
|
||||||
|
assert(pass < passes.length);
|
||||||
assert(m_dispatch_jobs,
|
assert(m_dispatch_jobs,
|
||||||
"Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc().");
|
"Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc().");
|
||||||
Vector!CallData tmp_datas;
|
Vector!CallData tmp_datas;
|
||||||
tmp_datas.reserve(8);
|
tmp_datas.reserve(8);
|
||||||
|
|
||||||
foreach (caller; system_callers)
|
foreach (caller; passes[pass].system_callers)
|
||||||
{
|
{
|
||||||
System* sys = &systems[caller.system_id];
|
System* sys = &systems[caller.system_id];
|
||||||
if (sys.enabled)
|
if (sys.enabled)
|
||||||
|
|
@ -978,14 +1028,14 @@ class EntityManager
|
||||||
}
|
}
|
||||||
|
|
||||||
uint index = 0;
|
uint index = 0;
|
||||||
for (; index < system_callers.length; index++)
|
for (; index < passes[system.m_pass].system_callers.length; index++)
|
||||||
{
|
{
|
||||||
if (system_callers[index].system_id == system_id)
|
if (passes[system.m_pass].system_callers[index].system_id == system_id)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index < system_callers.length)
|
if (index < passes[system.m_pass].system_callers.length)
|
||||||
system_callers[index].infos.add(&entity);
|
passes[system.m_pass].system_callers[index].infos.add(&entity);
|
||||||
/*for (; index < entity.callers.length; index++)
|
/*for (; index < entity.callers.length; index++)
|
||||||
{
|
{
|
||||||
CallData* caller = &entity.callers[index];
|
CallData* caller = &entity.callers[index];
|
||||||
|
|
@ -1137,10 +1187,6 @@ class EntityManager
|
||||||
del_ids[i] = comp.component_id;
|
del_ids[i] = comp.component_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*change_entities_list.add(0);
|
|
||||||
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[])del_ids);*/
|
|
||||||
removeComponents(entity_id, del_ids);
|
removeComponents(entity_id, del_ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1361,9 +1407,9 @@ class EntityManager
|
||||||
threads[thread_id].blocks_to_update.add(block);
|
threads[thread_id].blocks_to_update.add(block);
|
||||||
|
|
||||||
Entity* entity = cast(Entity*) start;
|
Entity* entity = cast(Entity*) start;
|
||||||
add_mutex.lock_nothrow();
|
//add_mutex.lock_nothrow();
|
||||||
entity.id = id_manager.getNewID();
|
entity.id = id_manager.getNewID();
|
||||||
add_mutex.unlock_nothrow();
|
//add_mutex.unlock_nothrow();
|
||||||
entity.updateID();
|
entity.updateID();
|
||||||
|
|
||||||
return *entity;
|
return *entity;
|
||||||
|
|
@ -1605,51 +1651,43 @@ class EntityManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export void commit()
|
||||||
|
{
|
||||||
|
id_manager.optimize();
|
||||||
|
updateBlocks();
|
||||||
|
removeEntities();
|
||||||
|
changeEntities();
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
*Begin of update process. Should be called before any update is called.
|
*Begin of update process. Should be called before any update is called.
|
||||||
*/
|
*/
|
||||||
export void begin()
|
export void begin()
|
||||||
{
|
{
|
||||||
updateBlocks();
|
|
||||||
removeEntities();
|
commit();
|
||||||
changeEntities();
|
|
||||||
m_call_data_allocator.clear();
|
m_call_data_allocator.clear();
|
||||||
|
|
||||||
/*version (UpdateBySystems)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{*/
|
|
||||||
foreach (ref system; instance.systems)
|
foreach (ref system; instance.systems)
|
||||||
{
|
{
|
||||||
if (system.m_begin)
|
if (system.m_begin)
|
||||||
(cast(void function(void*)) system.m_begin)(system.m_system_pointer);
|
(cast(void function(void*)) system.m_begin)(system.m_system_pointer);
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
*End of update process. Should be called after every update function.
|
*End of update process. Should be called after every update function.
|
||||||
*/
|
*/
|
||||||
export void end()
|
export void end()
|
||||||
{
|
|
||||||
/*version (UpdateBySystems)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{*/
|
|
||||||
foreach (ref system; instance.systems)
|
foreach (ref system; instance.systems)
|
||||||
{
|
{
|
||||||
if (system.m_end)
|
if (system.m_end)
|
||||||
(cast(void function(void*)) system.m_end)(system.m_system_pointer);
|
(cast(void function(void*)) system.m_end)(system.m_system_pointer);
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
|
|
||||||
updateBlocks();
|
commit();
|
||||||
removeEntities();
|
|
||||||
changeEntities();
|
|
||||||
|
|
||||||
//clearEvents();
|
//clearEvents();
|
||||||
}
|
}
|
||||||
|
|
@ -1665,20 +1703,24 @@ class EntityManager
|
||||||
/*private */
|
/*private */
|
||||||
void generateDependencies()
|
void generateDependencies()
|
||||||
{
|
{
|
||||||
foreach (caller; system_callers)
|
foreach(pass_id,pass;passes)
|
||||||
|
{
|
||||||
|
foreach (caller; pass.system_callers)
|
||||||
{
|
{
|
||||||
caller.system = &systems[caller.system_id];
|
caller.system = &systems[caller.system_id];
|
||||||
if(caller.exclusion)Mallocator.instance.dispose(caller.exclusion);
|
if (caller.exclusion)
|
||||||
if(caller.dependencies)Mallocator.instance.dispose(caller.dependencies);
|
Mallocator.instance.dispose(caller.exclusion);
|
||||||
|
if (caller.dependencies)
|
||||||
|
Mallocator.instance.dispose(caller.dependencies);
|
||||||
}
|
}
|
||||||
uint index = 0;
|
uint index = 0;
|
||||||
SystemCaller*[] exclusion;
|
SystemCaller*[] exclusion;
|
||||||
exclusion = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * system_callers.length))[0
|
exclusion = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * pass.system_callers.length))[0
|
||||||
.. system_callers.length];
|
.. pass.system_callers.length];
|
||||||
foreach (caller; system_callers)
|
foreach (caller; pass.system_callers)
|
||||||
{
|
{
|
||||||
index = 0;
|
index = 0;
|
||||||
out_for: foreach (caller2; system_callers)
|
out_for: foreach (caller2; pass.system_callers)
|
||||||
{
|
{
|
||||||
if ( /*caller.system.priority != caller2.system.priority ||*/ caller is caller2)
|
if ( /*caller.system.priority != caller2.system.priority ||*/ caller is caller2)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -1714,9 +1756,10 @@ class EntityManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (index > 0)
|
||||||
if(index > 0)caller.exclusion = Mallocator.instance.makeArray(exclusion[0..index]);
|
caller.exclusion = Mallocator.instance.makeArray(exclusion[0 .. index]);
|
||||||
else caller.exclusion = null;
|
else
|
||||||
|
caller.exclusion = null;
|
||||||
|
|
||||||
/*import std.stdio;
|
/*import std.stdio;
|
||||||
write("Exclusive systems for system ", caller.system.name, ": ");
|
write("Exclusive systems for system ", caller.system.name, ": ");
|
||||||
|
|
@ -1744,7 +1787,7 @@ class EntityManager
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort(system_callers.array.ptr, system_callers.length, (SystemCaller*)
|
qsort(pass.system_callers.array.ptr, pass.system_callers.length, (SystemCaller*)
|
||||||
.sizeof, &compareSystems);
|
.sizeof, &compareSystems);
|
||||||
|
|
||||||
/*static struct CallerData
|
/*static struct CallerData
|
||||||
|
|
@ -1753,21 +1796,22 @@ class EntityManager
|
||||||
//bool
|
//bool
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
/*caller_data = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * system_callers.length))[0
|
/*caller_data = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * pass.system_callers.length))[0
|
||||||
.. system_callers.length];*/
|
.. pass.system_callers.length];*/
|
||||||
|
|
||||||
foreach(uint i,caller;system_callers)caller.job_group.id = i;
|
foreach (uint i, caller; pass.system_callers)
|
||||||
|
caller.job_group.id = i;
|
||||||
|
|
||||||
int priority = int.min;
|
int priority = int.min;
|
||||||
uint beg = 0;
|
uint beg = 0;
|
||||||
index = 0;
|
index = 0;
|
||||||
foreach(uint i,caller;system_callers)
|
foreach (uint i, caller; pass.system_callers)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
if(priority == int.min)priority = caller.system.priority;
|
if(priority == int.min)priority = caller.system.priority;
|
||||||
if(priority != caller.system.priority)
|
if(priority != caller.system.priority)
|
||||||
{
|
{
|
||||||
foreach(caller2;system_callers[beg..i])
|
foreach(caller2;pass.system_callers[beg..i])
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1777,7 +1821,8 @@ class EntityManager
|
||||||
index = 0;
|
index = 0;
|
||||||
foreach (ex; caller.exclusion)
|
foreach (ex; caller.exclusion)
|
||||||
{
|
{
|
||||||
if(ex.job_group.id > caller.job_group.id)continue;
|
if (ex.job_group.id > caller.job_group.id)
|
||||||
|
continue;
|
||||||
|
|
||||||
exclusion[index++] = ex;
|
exclusion[index++] = ex;
|
||||||
}
|
}
|
||||||
|
|
@ -1792,7 +1837,8 @@ class EntityManager
|
||||||
caller.job_group.dependencies[j] = &dep.job_group;
|
caller.job_group.dependencies[j] = &dep.job_group;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else caller.dependencies = null;
|
else
|
||||||
|
caller.dependencies = null;
|
||||||
|
|
||||||
/*import std.stdio;
|
/*import std.stdio;
|
||||||
write("Dependencies for system ", caller.system.name, ": ");
|
write("Dependencies for system ", caller.system.name, ": ");
|
||||||
|
|
@ -1801,6 +1847,7 @@ class EntityManager
|
||||||
writeln();*/
|
writeln();*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
*Component info;
|
*Component info;
|
||||||
|
|
@ -1963,11 +2010,24 @@ class EntityManager
|
||||||
Vector!(EntitiesBlock*) blocks_to_update;
|
Vector!(EntitiesBlock*) blocks_to_update;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct UpdatePass
|
||||||
|
{
|
||||||
|
~this()
|
||||||
|
{
|
||||||
|
assert(name);
|
||||||
|
if(name)Mallocator.instance.dispose(name);
|
||||||
|
}
|
||||||
|
char[] name;
|
||||||
|
Vector!(SystemCaller*) system_callers;
|
||||||
|
}
|
||||||
|
|
||||||
static uint thread_id;
|
static uint thread_id;
|
||||||
|
|
||||||
ThreadData[] threads;
|
ThreadData[] threads;
|
||||||
|
|
||||||
Vector!(SystemCaller*) system_callers;
|
Vector!(UpdatePass*) passes;
|
||||||
|
|
||||||
|
//Vector!(SystemCaller*) system_callers;
|
||||||
|
|
||||||
alias SytemFuncType = void function(ref EntityManager.CallData data);
|
alias SytemFuncType = void function(ref EntityManager.CallData data);
|
||||||
|
|
||||||
|
|
@ -1981,7 +2041,7 @@ class EntityManager
|
||||||
enum pages_in_block = 128;
|
enum pages_in_block = 128;
|
||||||
|
|
||||||
IDManager id_manager;
|
IDManager id_manager;
|
||||||
BlockAllocator!(page_size, pages_in_block) allocator;
|
BlockAllocator/*!(page_size, pages_in_block)*/ allocator;
|
||||||
|
|
||||||
//EventManager event_manager;
|
//EventManager event_manager;
|
||||||
mixin EventManagerCode;
|
mixin EventManagerCode;
|
||||||
|
|
@ -1995,13 +2055,14 @@ class EntityManager
|
||||||
|
|
||||||
HashMap!(ushort[], EntityInfo*) entities_infos;
|
HashMap!(ushort[], EntityInfo*) entities_infos;
|
||||||
HashMap!(const(char)[], ushort) systems_map;
|
HashMap!(const(char)[], ushort) systems_map;
|
||||||
HashMap!(string, ushort) components_map;
|
HashMap!(const(char)[], ushort) components_map;
|
||||||
HashMap!(string, ushort) events_map;
|
HashMap!(const(char)[], ushort) events_map;
|
||||||
|
HashMap!(const(char)[], ushort) passes_map;
|
||||||
Vector!System systems;
|
Vector!System systems;
|
||||||
Vector!ComponentInfo components;
|
Vector!ComponentInfo components;
|
||||||
Vector!EventInfo events;
|
Vector!EventInfo events;
|
||||||
|
|
||||||
Mutex add_mutex;
|
//Mutex add_mutex;
|
||||||
Mutex entity_block_alloc_mutex;
|
Mutex entity_block_alloc_mutex;
|
||||||
|
|
||||||
CallDataAllocator m_call_data_allocator;
|
CallDataAllocator m_call_data_allocator;
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,8 @@ package:
|
||||||
int m_priority;
|
int m_priority;
|
||||||
///pointer to system implementation
|
///pointer to system implementation
|
||||||
void* m_system_pointer;
|
void* m_system_pointer;
|
||||||
|
///system pass index
|
||||||
|
int m_pass;
|
||||||
|
|
||||||
///system name
|
///system name
|
||||||
const (char)[] name;
|
const (char)[] name;
|
||||||
|
|
@ -66,7 +68,7 @@ package:
|
||||||
|
|
||||||
EntityManager.Job[] jobs;
|
EntityManager.Job[] jobs;
|
||||||
|
|
||||||
System*[] m_dependencies;
|
//System*[] m_dependencies;
|
||||||
ushort[] m_read_only_components;
|
ushort[] m_read_only_components;
|
||||||
ushort[] m_modified_components;
|
ushort[] m_modified_components;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ int main()
|
||||||
|
|
||||||
void initialize(ref Entity entity, ref TestComp comp)
|
void initialize(ref Entity entity, ref TestComp comp)
|
||||||
{
|
{
|
||||||
|
int o = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(EntitiesData data)
|
void update(EntitiesData data)
|
||||||
|
|
@ -284,6 +284,8 @@ import std.meta;
|
||||||
gEM.setJobDispachFunc(&dispatch);
|
gEM.setJobDispachFunc(&dispatch);
|
||||||
assert(gEM !is null);
|
assert(gEM !is null);
|
||||||
|
|
||||||
|
gEM.registerPass("fixed");
|
||||||
|
|
||||||
MonoTime time = MonoTime.currTime;
|
MonoTime time = MonoTime.currTime;
|
||||||
|
|
||||||
gEM.registerComponent!TestComp2;
|
gEM.registerComponent!TestComp2;
|
||||||
|
|
@ -299,7 +301,7 @@ import std.meta;
|
||||||
|
|
||||||
time = MonoTime.currTime;
|
time = MonoTime.currTime;
|
||||||
|
|
||||||
gEM.registerSystem!TestSystemWithHighPriority(100);
|
gEM.registerSystem!TestSystemWithHighPriority(100,"fixed");
|
||||||
gEM.registerSystem!TestSystem(0);
|
gEM.registerSystem!TestSystem(0);
|
||||||
//gEM.registerSystem!TestSystemWithHighPriority(100);
|
//gEM.registerSystem!TestSystemWithHighPriority(100);
|
||||||
//gEM.registerSystem!TestSystem2(0);
|
//gEM.registerSystem!TestSystem2(0);
|
||||||
|
|
@ -346,6 +348,7 @@ import std.meta;
|
||||||
gEM.removeEntity(idss[j]);
|
gEM.removeEntity(idss[j]);
|
||||||
gEM.end();
|
gEM.end();
|
||||||
}
|
}
|
||||||
|
gEM.commit();
|
||||||
|
|
||||||
dur = (MonoTime.currTime - time).total!"usecs";
|
dur = (MonoTime.currTime - time).total!"usecs";
|
||||||
writeln("Entities adding: ", dur, " usecs");
|
writeln("Entities adding: ", dur, " usecs");
|
||||||
|
|
@ -373,12 +376,18 @@ import std.meta;
|
||||||
|
|
||||||
Entity entity2;
|
Entity entity2;
|
||||||
|
|
||||||
|
time = MonoTime.currTime;
|
||||||
|
|
||||||
foreach (i; 0 .. 500_000)
|
foreach (i; 0 .. 500_000)
|
||||||
{
|
{
|
||||||
entity2 = gEM.addEntity(tmpl);
|
entity2 = gEM.addEntity(tmpl);
|
||||||
gEM.addEntity(tmpl2);
|
gEM.addEntity(tmpl2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gEM.commit();
|
||||||
|
dur = (MonoTime.currTime - time).total!"usecs";
|
||||||
|
writeln("Entities adding2: ", dur, " usecs");
|
||||||
|
|
||||||
time = MonoTime.currTime;
|
time = MonoTime.currTime;
|
||||||
|
|
||||||
gEM.begin();
|
gEM.begin();
|
||||||
|
|
@ -441,6 +450,7 @@ import std.meta;
|
||||||
|
|
||||||
gEM.begin();
|
gEM.begin();
|
||||||
gEM.update();
|
gEM.update();
|
||||||
|
gEM.update("fixed");
|
||||||
gEM.end();
|
gEM.end();
|
||||||
|
|
||||||
writeEntityComponents(gEM.getEntity(entity.id));
|
writeEntityComponents(gEM.getEntity(entity.id));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue