-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:
parent
8fdb56e840
commit
b3dce6560a
4 changed files with 180 additions and 60 deletions
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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 ~= "
|
||||||
if(comp == ushort.max)assert(0,\"Can't register system \\\"" ~ Sys.stringof
|
static if(isPointer!(types[" ~ i.to!string ~ "]))opt++;
|
||||||
~ "\\\" due to non existing component \\\"\"~types[" ~ i.to!string ~ "].stringof~\"\\\".\");
|
else static if(storages[" ~ i.to!string ~ "] == STC.ref_)req++;\n
|
||||||
system.m_components[" ~ (i - 1)
|
else static assert(0,\"Can't register system \\\"" ~ Sys.stringof
|
||||||
.to!string ~ "] = comp;";
|
~ "\\\". 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_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;
|
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,38 +350,48 @@ 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)
|
||||||
{
|
{
|
||||||
call_data.deltas = Mallocator.instance.makeArray(deltas); //Mallocator.instance.makeArray!ushort(system.m_components.length);
|
cmp_array = system.m_optional_components;
|
||||||
|
goto add_deltas;
|
||||||
uint index = 0;
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
call_data.deltas = Mallocator.instance.makeArray(deltas); //Mallocator.instance.makeArray!ushort(system.m_components.length);
|
||||||
|
|
||||||
|
uint index = 0;
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue