-call update by Systems instead of EntityTypes (version UpdateBySystems)

-memory packing (every block in EntityType except last one are always full)
This commit is contained in:
Mergul 2018-10-10 18:35:20 +02:00
parent fddfc78ec1
commit 3a767babc0
3 changed files with 232 additions and 92 deletions

View file

@ -89,28 +89,30 @@ class EntityManager
{
static if (isFunction!(__traits(getMember, Sys.EntitiesData, member)))
static assert(0, "EntitiesData can't have any function!");
else static if(member == "length")
else static if (member == "length")
{
static assert(isIntegral!(typeof(__traits(getMember,Sys.EntitiesData, member))),"EntitiesData 'length' member must be integral type.");
static assert(typeof(__traits(getMember,Sys.EntitiesData, member)).sizeof > 1,"EntitiesData 'length' member can't be byte or ubyte.");
static assert(isIntegral!(typeof(__traits(getMember, Sys.EntitiesData,
member))), "EntitiesData 'length' member must be integral type.");
static assert(typeof(__traits(getMember, Sys.EntitiesData, member))
.sizeof > 1, "EntitiesData 'length' member can't be byte or ubyte.");
}
else static if (!(isArray!(typeof(__traits(getMember,
Sys.EntitiesData, member)))))
static assert(0, "EntitiesData members should be arrays of elements!");
}
string ret;// = "ushort comp;uint req;uint opt;uint absent;";
string ret; // = "ushort comp;uint req;uint opt;uint absent;";
uint req;
uint opt;
uint absent;
foreach (member; __traits(allMembers, Sys.EntitiesData))
{
if (member == "length" || is(typeof(__traits(getMember, Sys.EntitiesData,
member)) == Entity[]) || is(typeof(__traits(getMember,
if (member == "length" || is(typeof(__traits(getMember,
Sys.EntitiesData, member)) == Entity[]) || is(typeof(__traits(getMember,
Sys.EntitiesData, member)) == const(Entity)[]))
{
}
else
{
@ -134,52 +136,66 @@ class EntityManager
break;
}
}
if (!has_att)req++;
//ret ~= "req++;";
if (!has_att)
req++;
//ret ~= "req++;";
}
}
}
static if(__traits(hasMember, Sys, "AbsentComponents"))
static if (__traits(hasMember, Sys, "AbsentComponents"))
{
static if(is(Sys.AbsentComponents == enum))
static if (is(Sys.AbsentComponents == enum))
{
absent += (Fields!(Sys.AbsentComponents)).length;//static assert(0,"Enum AbsentComponents are not implemented yet.");
absent += (Fields!(Sys.AbsentComponents)).length; //static assert(0,"Enum AbsentComponents are not implemented yet.");
}
else static if(__traits(compiles,allSameType!(string,typeof(Sys.AbsentComponents))) && allSameType!(string,typeof(Sys.AbsentComponents)) &&
isExpressions!(Sys.AbsentComponents))
else static if (__traits(compiles, allSameType!(string, typeof(Sys.AbsentComponents)))
&& allSameType!(string, typeof(Sys.AbsentComponents))
&& isExpressions!(Sys.AbsentComponents))
{
absent += Sys.AbsentComponents.length;
}
}
if(req > 0)ret ~= "system.m_components = Mallocator.instance.makeArray!ushort("~req.to!string~");";
if(opt > 0)ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort("~opt.to!string~");";
if(absent > 0)ret ~= "system.m_absent_components = Mallocator.instance.makeArray!ushort("~absent.to!string~");";
ret ~= "ushort comp;";//uint opt = 0;uint req = 0;uint absent = 0;";
if (req > 0)
ret ~= "system.m_components = Mallocator.instance.makeArray!ushort("
~ req.to!string ~ ");";
if (opt > 0)
ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort("
~ opt.to!string ~ ");";
if (absent > 0)
ret ~= "system.m_absent_components = Mallocator.instance.makeArray!ushort("
~ absent.to!string ~ ");";
ret ~= "ushort comp;"; //uint opt = 0;uint req = 0;uint absent = 0;";
opt = 0;
req = 0;
absent = 0;
static if(__traits(hasMember, Sys, "AbsentComponents"))
static if (__traits(hasMember, Sys, "AbsentComponents"))
{
static if(is(Sys.AbsentComponents == enum))
static if (is(Sys.AbsentComponents == enum))
{
//static assert(0,"Enum AbsentComponents are not implemented yet.");
foreach(str;Fields!(Sys.AbsentComponents))ret ~= "system.m_absent_components["~(absent++).to!string~"] = components_map.get(\""~str.stringof~"\", ushort.max);";
foreach (str; Fields!(Sys.AbsentComponents))
ret ~= "system.m_absent_components[" ~ (absent++)
.to!string ~ "] = components_map.get(\""
~ str.stringof ~ "\", ushort.max);";
}
else static if(__traits(compiles,allSameType!(string,typeof(Sys.AbsentComponents))) && allSameType!(string,typeof(Sys.AbsentComponents)) &&
isExpressions!(Sys.AbsentComponents))
else static if (__traits(compiles, allSameType!(string, typeof(Sys.AbsentComponents)))
&& allSameType!(string, typeof(Sys.AbsentComponents))
&& isExpressions!(Sys.AbsentComponents))
{
foreach(str;Sys.AbsentComponents)ret ~= "system.m_absent_components["~(absent++).to!string~"] = components_map.get(\""~str~"\", ushort.max);";
foreach (str; Sys.AbsentComponents)
ret ~= "system.m_absent_components[" ~ (absent++)
.to!string ~ "] = components_map.get(\"" ~ str ~ "\", ushort.max);";
}
}
foreach (member; __traits(allMembers, Sys.EntitiesData))
{
if (member == "length" || is(typeof(__traits(getMember, Sys.EntitiesData,
member)) == Entity[]) || is(typeof(__traits(getMember,
if (member == "length" || is(typeof(__traits(getMember,
Sys.EntitiesData, member)) == Entity[]) || is(typeof(__traits(getMember,
Sys.EntitiesData, member)) == const(Entity)[]))
{
@ -204,20 +220,22 @@ class EntityManager
{
if (att == "optional")
{
ret ~= "system.m_optional_components["~(opt++).to!string~"] = comp;}";
ret ~= "system.m_optional_components[" ~ (opt++)
.to!string ~ "] = comp;}";
has_att = true;
break;
}
else if (att == "absent")
{
ret ~= "system.m_absent_components["~(absent++).to!string~"] = comp;}";
ret ~= "system.m_absent_components[" ~ (absent++)
.to!string ~ "] = comp;}";
has_att = true;
break;
}
}
if (!has_att)
{
ret ~= "system.m_components["~(req++).to!string~"] = comp;}";
ret ~= "system.m_components[" ~ (req++).to!string ~ "] = comp;}";
}
}
}
@ -256,10 +274,9 @@ class EntityManager
ret ~= "input_data." ~ member
~ " = (cast(Entity*) block.dataBegin())[0 .. block.entities_count];";
}
else if(member == "length")
else if (member == "length")
{
ret ~= "input_data." ~ member
~ " = block.entities_count;";
ret ~= "input_data." ~ member ~ " = block.entities_count;";
}
else
{
@ -392,6 +409,28 @@ class EntityManager
addEntityCaller(*info, cast(uint) systems.length - 1);
}
}
version (UpdateBySystems)
{
bool added = false;
foreach (i, ref caller; 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);
added = true;
break;
}
}
if (!added)
{
SystemCaller* sys_caller = Mallocator.instance.make!SystemCaller;
sys_caller.system_id = Sys.system_id;
system_callers.add(sys_caller);
}
}
}
updateEntityCallers();
@ -492,12 +531,34 @@ class EntityManager
*/
export void update()
{
foreach (info; &entities_infos.byValue)
version (UpdateBySystems)
{
foreach (data; info.callers)
foreach (caller; system_callers)
{
if (data.system.enabled)
(cast(SytemFuncType) data.system.m_update)(data); //caller(call_data,null);
System* sys = &systems[caller.system_id];
if (sys.enabled)
{
if (sys.m_begin)
sys.m_begin(sys.m_system_pointer);
foreach (info; caller.infos)
{
CallData data = CallData(caller.system_id, sys, info);
(cast(SytemFuncType) data.system.m_update)(data);
}
if (sys.m_end)
sys.m_end(sys.m_system_pointer);
}
}
}
else
{
foreach (info; &entities_infos.byValue)
{
foreach (data; info.callers)
{
if (data.system.enabled)
(cast(SytemFuncType) data.system.m_update)(data); //caller(call_data,null);
}
}
}
}
@ -630,6 +691,16 @@ class EntityManager
addEntityCaller(*info, i);
}
version (UpdateBySystems)
{
foreach (uint i, ref system; systems)
{
if (system.m_update is null)
continue;
addSystemCaller(*info, i);
}
}
updateEntityCallers();
entities_infos.add(info.components, info);
@ -648,18 +719,19 @@ class EntityManager
}
}
export void addEntityCaller(ref EntityInfo entity, uint system_id)
export void addSystemCaller(ref EntityInfo entity, uint system_id)
{
System* system = &systems[system_id];
CallData call_data = CallData(system_id, system, &entity);
//CallData call_data = CallData(system_id, system, &entity);
if(system.m_absent_components)
if (system.m_absent_components)
{
foreach (id; system.m_absent_components)
{
foreach (id2; entity.components)
{
if(id == id2)return;
if (id == id2)
return;
}
}
}
@ -668,10 +740,56 @@ class EntityManager
{
foreach (i2, id2; entity.components)
{
if (id2 == id)goto is_;
if (id2 == id)
goto is_;
}
return;
is_:
is_:
}
uint index = 0;
for (; index < system_callers.length; index++)
{
if (system_callers[index].system_id == system_id)
break;
}
system_callers[index].infos.add(&entity);
/*for (; index < entity.callers.length; index++)
{
CallData* caller = &entity.callers[index];
if (caller.system.priority >= call_data.system.priority)
break;
}
entity.callers.add(call_data, index);*/
}
export void addEntityCaller(ref EntityInfo entity, uint system_id)
{
System* system = &systems[system_id];
CallData call_data = CallData(system_id, system, &entity);
if (system.m_absent_components)
{
foreach (id; system.m_absent_components)
{
foreach (id2; entity.components)
{
if (id == id2)
return;
}
}
}
foreach (id; system.m_components)
{
foreach (i2, id2; entity.components)
{
if (id2 == id)
goto is_;
}
return;
is_:
}
uint index = 0;
@ -1002,7 +1120,7 @@ class EntityManager
private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info)
{
EntitiesBlock* previous_block;
EntitiesBlock* block = info.first_with_free_space;
EntitiesBlock* block = info.last_block;
while (1)
{
@ -1021,7 +1139,7 @@ class EntityManager
block.prev_block = previous_block;
block.id = cast(ushort)(previous_block.id + 1);
}
info.first_with_free_space = block;
info.last_block = block;
break; // new block certainly has free space
}
// check if there is enought space
@ -1034,7 +1152,6 @@ class EntityManager
continue;
}
info.first_with_free_space = block;
break; // block exists and bounds check passed
}
@ -1071,11 +1188,7 @@ class EntityManager
void* data_begin = block.dataBegin();
EntityInfo* info = block.type_info;
block.entities_count--;
//set "first_with_free_space" if should it be
if (info.first_with_free_space.id > block.id)
info.first_with_free_space = block;
info.last_block.entities_count--;
static if (EntityID.sizeof == 8)
uint pos = cast(uint)((cast(void*) entity - data_begin) >> 3);
@ -1096,43 +1209,36 @@ class EntityManager
}
}
if(block !is info.last_block || pos != block.entities_count)
{
foreach (comp; info.components)
{
void* src = cast(void*) info.last_block + info.deltas[comp];
void* dst = cast(void*) block + info.deltas[comp];
uint size = components[comp].size;
memcpy(dst + pos * size, src + info.last_block.entities_count * size, size);
}
block = info.last_block;
entity.id = *cast(EntityID*)(block.dataBegin() + block.entities_count * EntityID.sizeof);
entity.updateID();
}
block = info.last_block;
if (block.entities_count == 0)
{
info.last_block = block.prev_block;
if (info.first_block is block)
{
info.first_block = block.next_block;
}
if (info.first_with_free_space is block)
{
info.first_with_free_space = block.next_block; //info.first_block;
info.first_block = null;
}
if (block.prev_block)
{
block.prev_block.next_block = block.next_block;
}
if (block.next_block)
{
block.next_block.prev_block = block.prev_block;
}
block.prev_block.next_block = null;
}
allocator.freeBlock(block);
return;
}
if (pos == block.entities_count)
return;
foreach (comp; info.components)
{
void* ptr = cast(void*) block + info.deltas[comp];
uint size = components[comp].size;
memcpy(ptr + pos * size, ptr + block.entities_count * size, size);
}
entity.id = *cast(EntityID*)(data_begin + block.entities_count * EntityID.sizeof);
//update pointer for moved entity ID
//entity = cast(Entity*) dst;
entity.updateID();
}
/************************************************************************************************************************
@ -1211,10 +1317,18 @@ class EntityManager
updateBlocks();
removeEntities();
changeEntites();
foreach (ref system; instance.systems)
version (UpdateBySystems)
{
if (system.m_begin)
system.m_begin(system.m_system_pointer);
}
else
{
foreach (ref system; instance.systems)
{
if (system.m_begin)
system.m_begin(system.m_system_pointer);
}
}
}
@ -1223,11 +1337,19 @@ class EntityManager
*/
export void end()
{
foreach (ref system; instance.systems)
version (UpdateBySystems)
{
if (system.m_end)
system.m_end(system.m_system_pointer);
}
else
{
foreach (ref system; instance.systems)
{
if (system.m_end)
system.m_end(system.m_system_pointer);
}
}
updateBlocks();
removeEntities();
changeEntites();
@ -1262,6 +1384,12 @@ class EntityManager
*/
struct EntityInfo
{
///Returns number of blocks
uint blocksCount()
{
return last_block.id;
}
///entity components
ushort[] components;
@ -1279,8 +1407,8 @@ class EntityManager
///pointer to first block/page
EntitiesBlock* first_block;
///a hint for allocations
EntitiesBlock* first_with_free_space; // a hint for allocations, should have empty space in it but doesn't have to
///pointer to last block
EntitiesBlock* last_block;
///array of CallData. Contain data for System calls.
Vector!(CallData) callers;
}
@ -1335,6 +1463,15 @@ class EntityManager
EntityManager.EntityInfo* info;
}
struct SystemCaller
{
uint system_id;
System* system;
Vector!(EntityInfo*) infos;
}
Vector!(SystemCaller*) system_callers;
alias SytemFuncType = void function(ref EntityManager.CallData data);
//alias sendSelfEvent = instance.event_manager.sendSelfEvent;
@ -1357,7 +1494,7 @@ class EntityManager
Vector!ubyte change_entities_list;
HashMap!(ushort[], EntityInfo*) entities_infos;
HashMap!(const (char)[], ushort) systems_map;
HashMap!(const(char)[], ushort) systems_map;
HashMap!(string, ushort) components_map;
HashMap!(string, ushort) events_map;
Vector!System systems;