-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:
Mergul 2018-10-25 11:46:08 +02:00
parent 430ce8074c
commit d3f7593afc
6 changed files with 406 additions and 189 deletions

View file

@ -59,10 +59,30 @@ class EntityManager
threads_count = 0;
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;
//event_manager = EventManager(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:
*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;
assert(pass < passes.length);
System system;
system.m_pass = pass;
static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort))
{
@ -450,10 +473,6 @@ class EntityManager
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);
if (sys_id < systems.length)
{
@ -492,13 +511,13 @@ class EntityManager
version (UpdateBySystems)
{
bool added = false;
foreach (i, ref caller; system_callers)
foreach (i, ref caller; passes[pass].system_callers)
{
if (systems[caller.system_id].priority > priority)
{
SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller;
sys_caller.system_id = Sys.system_id;
system_callers.add(sys_caller, i);
passes[pass].system_callers.add(sys_caller, i);
added = true;
break;
}
@ -507,7 +526,7 @@ class EntityManager
{
SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller;
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;
}
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.
*/
@ -564,7 +592,7 @@ class EntityManager
{
components.add(info);
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));
}
}
@ -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().
*/
export void update()
export void update(ushort pass = 0)
{
assert(pass < passes.length);
version (UpdateBySystems)
{
foreach (caller; system_callers)
foreach (caller; passes[pass].system_callers)
{
System* sys = &systems[caller.system_id];
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,
"Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc().");
Vector!CallData tmp_datas;
tmp_datas.reserve(8);
foreach (caller; system_callers)
foreach (caller; passes[pass].system_callers)
{
System* sys = &systems[caller.system_id];
if (sys.enabled)
@ -766,7 +816,7 @@ class EntityManager
nextJob();
caller.job_group.jobs = sys.jobs[0 .. job_id];
m_dispatch_jobs(caller.job_group);//sys.jobs[0 .. job_id]);
m_dispatch_jobs(caller.job_group); //sys.jobs[0 .. job_id]);
}
}
}
@ -978,14 +1028,14 @@ class EntityManager
}
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;
}
if (index < system_callers.length)
system_callers[index].infos.add(&entity);
if (index < passes[system.m_pass].system_callers.length)
passes[system.m_pass].system_callers[index].infos.add(&entity);
/*for (; index < entity.callers.length; index++)
{
CallData* caller = &entity.callers[index];
@ -1137,10 +1187,6 @@ class EntityManager
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);
}
@ -1361,9 +1407,9 @@ class EntityManager
threads[thread_id].blocks_to_update.add(block);
Entity* entity = cast(Entity*) start;
add_mutex.lock_nothrow();
//add_mutex.lock_nothrow();
entity.id = id_manager.getNewID();
add_mutex.unlock_nothrow();
//add_mutex.unlock_nothrow();
entity.updateID();
return *entity;
@ -1605,28 +1651,28 @@ class EntityManager
}
}
export void commit()
{
id_manager.optimize();
updateBlocks();
removeEntities();
changeEntities();
}
/************************************************************************************************************************
*Begin of update process. Should be called before any update is called.
*/
export void begin()
{
updateBlocks();
removeEntities();
changeEntities();
commit();
m_call_data_allocator.clear();
/*version (UpdateBySystems)
{
}
else
{*/
foreach (ref system; instance.systems)
{
if (system.m_begin)
(cast(void function(void*)) system.m_begin)(system.m_system_pointer);
}
//}
}
/************************************************************************************************************************
@ -1634,22 +1680,14 @@ class EntityManager
*/
export void end()
{
/*version (UpdateBySystems)
{
}
else
{*/
foreach (ref system; instance.systems)
{
if (system.m_end)
(cast(void function(void*)) system.m_end)(system.m_system_pointer);
}
//}
updateBlocks();
removeEntities();
changeEntities();
commit();
//clearEvents();
}
@ -1665,140 +1703,149 @@ class EntityManager
/*private */
void generateDependencies()
{
foreach (caller; system_callers)
foreach(pass_id,pass;passes)
{
caller.system = &systems[caller.system_id];
if(caller.exclusion)Mallocator.instance.dispose(caller.exclusion);
if(caller.dependencies)Mallocator.instance.dispose(caller.dependencies);
}
uint index = 0;
SystemCaller*[] exclusion;
exclusion = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * system_callers.length))[0
.. system_callers.length];
foreach (caller; system_callers)
{
index = 0;
out_for: foreach (caller2; system_callers)
foreach (caller; pass.system_callers)
{
if (/*caller.system.priority != caller2.system.priority ||*/ caller is caller2)
continue;
foreach (cmp; caller.system.m_read_only_components)
{
foreach (cmp2; caller2.system.m_modified_components)
{
if (cmp == cmp2)
{
exclusion[index++] = caller2;
continue out_for;
}
}
}
foreach (cmp; caller.system.m_modified_components)
{
foreach (cmp2; caller2.system.m_read_only_components)
{
if (cmp == cmp2)
{
exclusion[index++] = caller2;
continue out_for;
}
}
foreach (cmp2; caller2.system.m_modified_components)
{
if (cmp == cmp2)
{
exclusion[index++] = caller2;
continue out_for;
}
}
}
caller.system = &systems[caller.system_id];
if (caller.exclusion)
Mallocator.instance.dispose(caller.exclusion);
if (caller.dependencies)
Mallocator.instance.dispose(caller.dependencies);
}
if(index > 0)caller.exclusion = Mallocator.instance.makeArray(exclusion[0..index]);
else caller.exclusion = null;
/*import std.stdio;
write("Exclusive systems for system ", caller.system.name, ": ");
foreach (ex; exclusion[0 .. index])
write(ex.system.name, " ");
writeln();*/
}
extern (C) static int compareSystems(const void* a, const void* b)
{
SystemCaller* _a = *cast(SystemCaller**) a;
SystemCaller* _b = *cast(SystemCaller**) b;
if (_a.system.priority < _b.system.priority)
return -1;
else if (_a.system.priority == _b.system.priority)
uint index = 0;
SystemCaller*[] exclusion;
exclusion = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * pass.system_callers.length))[0
.. pass.system_callers.length];
foreach (caller; pass.system_callers)
{
if (_a.exclusion.length < _b.exclusion.length)
index = 0;
out_for: foreach (caller2; pass.system_callers)
{
if ( /*caller.system.priority != caller2.system.priority ||*/ caller is caller2)
continue;
foreach (cmp; caller.system.m_read_only_components)
{
foreach (cmp2; caller2.system.m_modified_components)
{
if (cmp == cmp2)
{
exclusion[index++] = caller2;
continue out_for;
}
}
}
foreach (cmp; caller.system.m_modified_components)
{
foreach (cmp2; caller2.system.m_read_only_components)
{
if (cmp == cmp2)
{
exclusion[index++] = caller2;
continue out_for;
}
}
foreach (cmp2; caller2.system.m_modified_components)
{
if (cmp == cmp2)
{
exclusion[index++] = caller2;
continue out_for;
}
}
}
}
if (index > 0)
caller.exclusion = Mallocator.instance.makeArray(exclusion[0 .. index]);
else
caller.exclusion = null;
/*import std.stdio;
write("Exclusive systems for system ", caller.system.name, ": ");
foreach (ex; exclusion[0 .. index])
write(ex.system.name, " ");
writeln();*/
}
extern (C) static int compareSystems(const void* a, const void* b)
{
SystemCaller* _a = *cast(SystemCaller**) a;
SystemCaller* _b = *cast(SystemCaller**) b;
if (_a.system.priority < _b.system.priority)
return -1;
else if (_a.exclusion.length == _b.exclusion.length)
return 0;
else if (_a.system.priority == _b.system.priority)
{
if (_a.exclusion.length < _b.exclusion.length)
return -1;
else if (_a.exclusion.length == _b.exclusion.length)
return 0;
else
return 1;
}
else
return 1;
}
else
return 1;
}
qsort(system_callers.array.ptr, system_callers.length, (SystemCaller*)
.sizeof, &compareSystems);
qsort(pass.system_callers.array.ptr, pass.system_callers.length, (SystemCaller*)
.sizeof, &compareSystems);
/*static struct CallerData
{
uint id;
//bool
}*/
/*caller_data = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * system_callers.length))[0
.. system_callers.length];*/
foreach(uint i,caller;system_callers)caller.job_group.id = i;
int priority = int.min;
uint beg = 0;
index = 0;
foreach(uint i,caller;system_callers)
{
/*
if(priority == int.min)priority = caller.system.priority;
if(priority != caller.system.priority)
/*static struct CallerData
{
foreach(caller2;system_callers[beg..i])
{
}
priority = caller.system.priority;
beg = i;
uint id;
//bool
}*/
/*caller_data = (cast(SystemCaller**) alloca((SystemCaller*).sizeof * pass.system_callers.length))[0
.. pass.system_callers.length];*/
foreach (uint i, caller; pass.system_callers)
caller.job_group.id = i;
int priority = int.min;
uint beg = 0;
index = 0;
foreach(ex;caller.exclusion)
foreach (uint i, caller; pass.system_callers)
{
if(ex.job_group.id > caller.job_group.id)continue;
exclusion[index++] = ex;
}
if(index > 0)
{
caller.dependencies = Mallocator.instance.makeArray(exclusion[0..index]);
caller.job_group.dependencies = Mallocator.instance.makeArray!(JobGroup*)(index);
foreach(j,dep;caller.dependencies)
/*
if(priority == int.min)priority = caller.system.priority;
if(priority != caller.system.priority)
{
caller.job_group.dependencies[j] = &dep.job_group;
}
}
else caller.dependencies = null;
foreach(caller2;pass.system_callers[beg..i])
{
}
priority = caller.system.priority;
beg = i;
}*/
index = 0;
foreach (ex; caller.exclusion)
{
if (ex.job_group.id > caller.job_group.id)
continue;
/*import std.stdio;
write("Dependencies for system ", caller.system.name, ": ");
foreach (ex; caller.dependencies)
write(ex.system.name, " ");
writeln();*/
exclusion[index++] = ex;
}
if (index > 0)
{
caller.dependencies = Mallocator.instance.makeArray(exclusion[0 .. index]);
caller.job_group.dependencies = Mallocator.instance.makeArray!(JobGroup*)(index);
foreach (j, dep; caller.dependencies)
{
caller.job_group.dependencies[j] = &dep.job_group;
}
}
else
caller.dependencies = null;
/*import std.stdio;
write("Dependencies for system ", caller.system.name, ": ");
foreach (ex; caller.dependencies)
write(ex.system.name, " ");
writeln();*/
}
}
}
@ -1963,11 +2010,24 @@ class EntityManager
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;
ThreadData[] threads;
Vector!(SystemCaller*) system_callers;
Vector!(UpdatePass*) passes;
//Vector!(SystemCaller*) system_callers;
alias SytemFuncType = void function(ref EntityManager.CallData data);
@ -1981,7 +2041,7 @@ class EntityManager
enum pages_in_block = 128;
IDManager id_manager;
BlockAllocator!(page_size, pages_in_block) allocator;
BlockAllocator/*!(page_size, pages_in_block)*/ allocator;
//EventManager event_manager;
mixin EventManagerCode;
@ -1995,13 +2055,14 @@ class EntityManager
HashMap!(ushort[], EntityInfo*) entities_infos;
HashMap!(const(char)[], ushort) systems_map;
HashMap!(string, ushort) components_map;
HashMap!(string, ushort) events_map;
HashMap!(const(char)[], ushort) components_map;
HashMap!(const(char)[], ushort) events_map;
HashMap!(const(char)[], ushort) passes_map;
Vector!System systems;
Vector!ComponentInfo components;
Vector!EventInfo events;
Mutex add_mutex;
//Mutex add_mutex;
Mutex entity_block_alloc_mutex;
CallDataAllocator m_call_data_allocator;