-suport system callback: onCreate, onDestroy, onBegin, onEnd

-support for optional Components for System
-Components IDs in Systems are now stored as ushorts
This commit is contained in:
Mergul 2018-09-16 22:40:55 +02:00
parent 8fdb56e840
commit b3dce6560a
4 changed files with 180 additions and 60 deletions

View file

@ -2,8 +2,8 @@ module ecs.entity_allocator;
import ecs.manager;
import std.experimental.allocator.mallocator : Mallocator, AlignedMallocator;
import std.experimental.allocator;
import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;
struct EntityAllocator
{

View file

@ -27,8 +27,19 @@ class EntityManager
instance = Mallocator.instance.make!EntityManager;
}
static void destory()
static void destroy()
{
foreach(ref system;instance.systems)
{
system.disable();
}
foreach(ref system;instance.systems)
{
if(system.m_destroy)system.m_destroy(system.m_system_pointer);
}
Mallocator.instance.dispose(instance);
instance = null;
}
@ -36,16 +47,34 @@ class EntityManager
void registerSystem(Sys)(int priority)
{
alias types = Parameters!(Sys.update);
alias storages = ParameterStorageClassTuple!(Sys.update);
alias STC = ParameterStorageClass;
System system;
static string genCall()()
{
string ret = "s.update(*cast(Entity*)data_pointer,";
foreach (i; 1 .. (Parameters!(Sys.update)).length)
/*foreach (i; 1 .. (Parameters!(Sys.update)).length)
{
ret ~= "*cast(types[" ~ i.to!string ~ "]*)(data_pointer + data.deltas[" ~ (i - 1)
ret ~= "*cast(types[" ~ i.to!string ~ "]*)(pointers[" ~ (i - 1)
.to!string ~ "]),";
}*/
uint i = 0;
uint req = 0;
uint opt = 0;
static foreach(param;(Parameters!(Sys.update))[1..$])
{
i++;
if(isPointer!param)
{
ret ~= "cast(types[" ~ i.to!string ~ "])(optional_pointers[" ~ (opt++).to!string ~ "]),";
}
else
{
ret ~= "*cast(types[" ~ i.to!string ~ "]*)(pointers[" ~ (req++).to!string ~ "]),";
}
}
ret ~= ");";
return ret;
@ -53,16 +82,53 @@ class EntityManager
static string genCompList()()
{
string ret = "uint comp;";
string ret = "ushort comp;uint req;uint opt;";
foreach (i; 1 .. (Parameters!(Sys.update)).length)
{
ret ~= "comp = components_map.get(types[" ~ i.to!string ~ "].stringof, ushort.max);\n
ret ~= "
static if(isPointer!(types[" ~ i.to!string ~ "]))opt++;
else static if(storages[" ~ i.to!string ~ "] == STC.ref_)req++;\n
else static assert(0,\"Can't register system \\\"" ~ Sys.stringof
~ "\\\". Unsupported parameter type \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\");";
}
ret ~= "system.m_components = Mallocator.instance.makeArray!ushort(req);";
ret ~= "system.m_optional_components = Mallocator.instance.makeArray!ushort(opt);";
ret ~= "opt = 0;req = 0;";
foreach (i; 1 .. (Parameters!(Sys.update)).length)
{
ret ~= "
static if(isPointer!(types[" ~ i.to!string ~ "]))
{
comp = components_map.get(PointerTarget!(types[" ~ i.to!string ~ "]).stringof, ushort.max);\n
if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof
~ "\\\" due to non existing component \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\");
system.m_components[" ~ (i - 1)
.to!string ~ "] = comp;";
system.m_optional_components[opt++] = comp;
}
else static if(storages[" ~ i.to!string ~ "] == STC.ref_)
{
comp = components_map.get(types[" ~ i.to!string ~ "].stringof, ushort.max);\n
if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof
~ "\\\" due to non existing component \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\");
system.m_components[req++] = comp;
}";
}
return ret;
}
static string catchFunc()(string member, string func)
{
string ret =
"static if (hasMember!(Sys, \""~func~"\"))
{
static void call"~func~"(void* system_pointer)
{
Sys* s = cast(Sys*) system_pointer;
s."~func~"();
}
system."~member~" = &call"~func~";
}";
return ret;
}
@ -74,14 +140,30 @@ class EntityManager
{
Sys* s = cast(Sys*) data.system.m_system_pointer;
void*[] pointers = (cast(void**)alloca(data.system.m_components.length * (void*).sizeof))[0 .. data.system.m_components.length];
void*[] optional_pointers = (cast(void**)alloca(data.system.m_optional_components.length * (void*).sizeof))[0 .. data.system.m_optional_components.length];
EntitiesBlock* block = data.info.first_block;
while (block !is null)
{
uint size = block.type_data.size;
void* data_pointer = block.dataBegin();
foreach(i, ref pointer;pointers)
{
pointer = data_pointer + data.deltas[i];
}
foreach(i, ref pointer;optional_pointers)
{
uint ind = cast(uint)(i + pointers.length);
if(data.deltas[ind] != uint.max)pointer = data_pointer + data.deltas[ind];
else pointer = null;
}
foreach (i; 0 .. block.entities_count)
{
mixin(genCall());
data_pointer += data.info.size;
data_pointer += size;//data.info.size;
foreach(ref pointer;pointers)pointer += size;
foreach(ref pointer;optional_pointers)if(pointer != null)pointer += size;
}
block = block.next_block;
}
@ -92,37 +174,23 @@ class EntityManager
system.m_update = &callUpdate;
}
static if (hasMember!(Sys, "onEnable"))
{
static void callEnable(void* system_pointer)
{
Sys* s = cast(Sys*) system_pointer;
s.onEnable();
}
system.m_enable = &callEnable;
}
static if (hasMember!(Sys, "onDisable"))
{
static void callDisable(void* system_pointer)
{
Sys* s = cast(Sys*) system_pointer;
s.onDisable();
}
system.m_disable = &callDisable;
}
mixin(catchFunc("m_enable","onEnable"));
mixin(catchFunc("m_disable","onDisable"));
mixin(catchFunc("m_create","onCreate"));
mixin(catchFunc("m_destroy","onDestroy"));
mixin(catchFunc("m_begin","onBegin"));
mixin(catchFunc("m_end","onEnd"));
system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys;
system.m_priority = priority;
system.m_components = Mallocator.instance.makeArray!uint(types.length - 1);
//system.m_components = Mallocator.instance.makeArray!uint(types.length - 1);
mixin(genCompList());
systems.add(system);
if(system.m_create)system.m_create(system.m_system_pointer);
systems[$ - 1].enable();
foreach (info; &entities_infos.byValue)
@ -151,7 +219,6 @@ class EntityManager
{
(cast(Comp*) pointer).onDestroy();
}
info.destroy_callback = &callDestroy;
}
@ -162,7 +229,7 @@ class EntityManager
components.add(info);
Comp.component_id = cast(ushort)(components.length - 1);
components_map.add(Comp.stringof, cast(uint)(components.length - 1));
components_map.add(Comp.stringof, cast(ushort)(components.length - 1));
}
void update()
@ -283,27 +350,38 @@ class EntityManager
{
System* system = &systems[system_id];
CallData call_data = CallData(system_id, system, &entity, null);
ushort[] deltas = (cast(ushort*) alloca(system.m_components.length * ushort.sizeof))[0
.. system.m_components.length];
foreach (i, id; system.m_components)
uint num = cast(uint)(system.m_components.length + system.m_optional_components.length);
ushort[] deltas = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num];
uint delta_id = 0;
ushort[] cmp_array = system.m_components;
add_deltas:
foreach (id; cmp_array)
{
deltas[i] = ushort.max;
deltas[delta_id] = ushort.max;
foreach (i2, id2; entity.components)
{
if (id2 == id)
{
deltas[i] = entity.deltas[id2];
deltas[delta_id] = entity.deltas[id2];
break;
}
}
if (deltas[i] == ushort.max)
if (deltas[delta_id] == ushort.max)
{
deltas = null;
break;
}
delta_id++;
}
if (deltas)
if(deltas is null)return;
if(cmp_array.ptr == system.m_components.ptr)
{
cmp_array = system.m_optional_components;
goto add_deltas;
}
call_data.deltas = Mallocator.instance.makeArray(deltas); //Mallocator.instance.makeArray!ushort(system.m_components.length);
uint index = 0;
@ -315,7 +393,6 @@ class EntityManager
}
entity.callers.add(call_data, index);
}
}
Entity* getEntity(EntityID id)
{
@ -640,11 +717,18 @@ class EntityManager
void begin()
{
foreach(ref system;instance.systems)
{
if(system.m_begin)system.m_begin(system.m_system_pointer);
}
}
void end()
{
foreach(ref system;instance.systems)
{
if(system.m_end)system.m_end(system.m_system_pointer);
}
removeEntites();
}
@ -737,7 +821,7 @@ class EntityManager
Vector!EntityID entities_to_remove;
HashMap!(ushort[], EntityInfo*) entities_infos;
HashMap!(string, uint) components_map;
HashMap!(string, ushort) components_map;
Vector!System systems;
Vector!ComponentInfo components;
__gshared EntityManager instance;

View file

@ -38,11 +38,18 @@ package:
///pointer to system implementation
void* m_system_pointer;
uint[] m_components;
ushort[] m_components;
ushort[] m_optional_components;
//void function(ref EntityManager.CallData data, void* entity) update;
void* m_update; ///workaroud for DMD bug with upper line
void function(void* system_pointer) m_enable;
void function(void* system_pointer) m_disable;
void function(void* system_pointer) m_create;
void function(void* system_pointer) m_destroy;
void function(void* system_pointer) m_begin;
void function(void* system_pointer) m_end;
}

View file

@ -81,12 +81,32 @@ int main()
struct TestSystem
{
void onCreate()
{
writeln("On Test System create.");
}
void onDestroy()
{
writeln("On Test System destroy.");
}
void onBegin()
{
writeln("On Test System begin.");
}
void onEnd()
{
writeln("On Test System end.");
}
void initialize(ref Entity entity, ref TestComp comp)
{
}
void update(ref Entity entity, ref TestComp test, ref TestComp2 test2) //ref TestComp comp)
void update(ref Entity entity, ref TestComp test, ref TestComp2 test2, TestComp3* test3) //ref TestComp comp)
{
assert(cast(size_t)&test % TestComp.alignof == 0);
assert(cast(size_t)&test2 % TestComp2.alignof == 0);
@ -100,6 +120,7 @@ int main()
test2.a = 8;
//writeln("Jakis tekst! ",test2.b);
//writeln("Low priority tekst! ");
if(test3)test3.gg = 200;
}
void handleEvent(Event event, ref TestComp comp)
@ -247,7 +268,9 @@ int main()
Entity entity = gEM.addEntity(tmpl);
gEM.begin();
gEM.update();
gEM.end();
Entity* pp = gEM.getEntity(entity.id);
writeln((cast(uint*) pp)[0 .. 14], " ", pp);
@ -257,19 +280,25 @@ int main()
gEM.addComponents(entity.id, TestComp3());
pp = gEM.getEntity(entity.id);
gEM.begin();
gEM.update();
gEM.end();
writeln((cast(uint*) pp)[0 .. 14], " ", pp);
gEM.removeComponents!(TestComp)(entity.id);
pp = gEM.getEntity(entity.id);
gEM.begin();
gEM.update();
gEM.end();
writeln((cast(uint*) pp)[0 .. 14], " ", pp);
//import std.stdio;
//writeln((cast(uint*)tmpl.info.first_block)[0..48]);
gEM.freeTemplate(tmpl);
EntityManager.destroy();
return 0;
}