-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 ecs.manager;
import std.experimental.allocator.mallocator : Mallocator, AlignedMallocator;
import std.experimental.allocator; import std.experimental.allocator;
import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;
struct EntityAllocator struct EntityAllocator
{ {

View file

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

View file

@ -38,11 +38,18 @@ package:
///pointer to system implementation ///pointer to system implementation
void* m_system_pointer; void* m_system_pointer;
uint[] m_components; ushort[] m_components;
ushort[] m_optional_components;
//void function(ref EntityManager.CallData data, void* entity) update; //void function(ref EntityManager.CallData data, void* entity) update;
void* m_update; ///workaroud for DMD bug with upper line void* m_update; ///workaroud for DMD bug with upper line
void function(void* system_pointer) m_enable; void function(void* system_pointer) m_enable;
void function(void* system_pointer) m_disable; 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 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 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)&test % TestComp.alignof == 0);
assert(cast(size_t)&test2 % TestComp2.alignof == 0); assert(cast(size_t)&test2 % TestComp2.alignof == 0);
@ -100,6 +120,7 @@ int main()
test2.a = 8; test2.a = 8;
//writeln("Jakis tekst! ",test2.b); //writeln("Jakis tekst! ",test2.b);
//writeln("Low priority tekst! "); //writeln("Low priority tekst! ");
if(test3)test3.gg = 200;
} }
void handleEvent(Event event, ref TestComp comp) void handleEvent(Event event, ref TestComp comp)
@ -247,7 +268,9 @@ int main()
Entity entity = gEM.addEntity(tmpl); Entity entity = gEM.addEntity(tmpl);
gEM.begin();
gEM.update(); gEM.update();
gEM.end();
Entity* pp = gEM.getEntity(entity.id); Entity* pp = gEM.getEntity(entity.id);
writeln((cast(uint*) pp)[0 .. 14], " ", pp); writeln((cast(uint*) pp)[0 .. 14], " ", pp);
@ -257,19 +280,25 @@ int main()
gEM.addComponents(entity.id, TestComp3()); gEM.addComponents(entity.id, TestComp3());
pp = gEM.getEntity(entity.id); pp = gEM.getEntity(entity.id);
gEM.begin();
gEM.update(); gEM.update();
gEM.end();
writeln((cast(uint*) pp)[0 .. 14], " ", pp); writeln((cast(uint*) pp)[0 .. 14], " ", pp);
gEM.removeComponents!(TestComp)(entity.id); gEM.removeComponents!(TestComp)(entity.id);
pp = gEM.getEntity(entity.id); pp = gEM.getEntity(entity.id);
gEM.begin();
gEM.update(); gEM.update();
gEM.end();
writeln((cast(uint*) pp)[0 .. 14], " ", pp); writeln((cast(uint*) pp)[0 .. 14], " ", pp);
//import std.stdio; //import std.stdio;
//writeln((cast(uint*)tmpl.info.first_block)[0..48]); //writeln((cast(uint*)tmpl.info.first_block)[0..48]);
gEM.freeTemplate(tmpl); gEM.freeTemplate(tmpl);
EntityManager.destroy();
return 0; return 0;
} }