-changes in gitignore

-changed "absent" to "excluded" everywhere
-added Events support:
 *systems are scanned by handleEvent() function
 *generate system callers for events
 *event sending have (untested) multithreaded support
 *EventInput structure in System has input components for event
This commit is contained in:
Mergul 2018-11-02 15:39:46 +01:00
parent 16a5696840
commit 3bc5ff2423
8 changed files with 689 additions and 310 deletions

View file

@ -57,12 +57,12 @@ class EntityManager
*/
void beginRegister()
{
assert(!register_state,"beginRegister() can't be called twice before endRegister();");
assert(!register_state, "beginRegister() can't be called twice before endRegister();");
register_state = true;
foreach(pass;passes)
foreach (pass; passes)
{
foreach(caller;pass.system_callers)
foreach (caller; pass.system_callers)
{
Mallocator.instance.dispose(caller);
}
@ -75,13 +75,13 @@ class EntityManager
*/
void endRegister()
{
assert(register_state,"beginRegister() should be called before endRegister();");
assert(register_state, "beginRegister() should be called before endRegister();");
register_state = false;
foreach(ref system;systems)
foreach (ref system; systems)
{
if (system.m_update is null)
continue;
continue;
bool added = false;
foreach (i, caller; passes[system.m_pass].system_callers)
@ -103,10 +103,45 @@ class EntityManager
sys_caller.job_group.caller = sys_caller;
passes[system.m_pass].system_callers.add(sys_caller);
}
foreach(info;&entities_infos.byValue)
foreach (info; &entities_infos.byValue)
{
addSystemCaller(*info,system.id);
addSystemCaller(*info, system.id);
}
}
event_manager.allocateData(cast(uint) threads.length);
foreach(ref info;events)
{
Mallocator.instance.dispose(info.callers);
}
ushort[] event_callers = (cast(ushort*)alloca(ushort.sizeof * events.length))[0..events.length];
foreach(ref caller; event_callers)caller = 0;
foreach(ref system;systems)
{
foreach(caller;system.m_event_callers)
{
event_callers[caller.id]++;
}
}
foreach(i,ref info; events)
{
info.callers = Mallocator.instance.makeArray!(EventCaller)(event_callers[i]);
}
foreach(ref caller; event_callers)caller = 0;
foreach(ref system;systems)
{
foreach(caller;system.m_event_callers)
{
events[caller.id].callers[event_callers[caller.id]].callback = caller.callback;
events[caller.id].callers[event_callers[caller.id]].system = &system;
event_callers[caller.id]++;
}
}
@ -119,10 +154,11 @@ class EntityManager
this(uint threads_count)
{
if (threads_count == 0)
threads_count = 0;
threads_count = 1;
threads = Mallocator.instance.makeArray!ThreadData(threads_count);
id_manager.initialize();
event_manager.initialize(this);
allocator = BlockAllocator(page_size, pages_in_block);
@ -144,7 +180,7 @@ class EntityManager
void registerSystem(Sys)(int priority, const(char)[] pass_name)
{
ushort pass = passes_map.get(pass_name, ushort.max);
assert(pass != ushort.max,"Update pass (Name "~pass_name~") doesn't exist.");
assert(pass != ushort.max, "Update pass (Name " ~ pass_name ~ ") doesn't exist.");
registerSystem!(Sys)(priority, pass);
}
@ -158,17 +194,18 @@ class EntityManager
*/
void registerSystem(Sys)(int priority, ushort pass = 0)
{
alias STC = ParameterStorageClass;
//alias STC = ParameterStorageClass;
assert(register_state,"asda");
assert(pass < passes.length,"Update pass (ID "~pass.to!string~") doesn't exist.");
assert(register_state,
"registerSystem must be called between beginRegister() and endRegister().");
assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist.");
System system;
system.m_pass = pass;
static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort))
{
static assert(0, "Add \"mixin ECS.System;\" in top of system structure;");//"System should have \"__gshared ushort system_id");
static assert(0, "Add \"mixin ECS.System;\" in top of system structure;"); //"System should have \"__gshared ushort system_id");
}
static if (!(hasMember!(Sys, "EntitiesData")))
@ -176,6 +213,126 @@ class EntityManager
static assert(0, "System should gave \"EntitiesData\" struct for input components");
}
//dfmt off
static if(hasMember!(Sys,"EventInput"))
{
static string genEventCompList()()
{
string ret = "Sys.EventInput input;\n";
string type;
//bool has = true;
foreach (member; __traits(allMembers, Sys.EventInput))
{
if(mixin("fullyQualifiedName!(ConstOf!(PointerTarget!(typeof(Sys.EventInput."~member~")))) == \"const(ecs.entity.Entity)\""))
{
ret ~= "input." ~ member ~ " = cast(Entity*) data.block.dataBegin() + data.id;\n";
continue;
}
bool has = false;
bool optional = false;
foreach(member2; __traits(allMembers, Sys.EntitiesData))
{
static if(mixin("isBasicType!(typeof(Sys.EntitiesData."~member2~"))")){}
else static if(mixin("fullyQualifiedName!(ConstOf!(PointerTarget!(typeof(Sys.EventInput."~member~")))) == fullyQualifiedName!(ConstOf!(ForeachType!(typeof(Sys.EntitiesData."~member2~"))))"))
{
has = true;
if(mixin("hasUDA!(Sys.EntitiesData."~member2~",\"optional\")"))optional = true;
break;
}
}
if(!has)assert(0);
if(optional)ret ~= "input." ~ member ~ " = null;\n";
else ret ~= "input." ~ member ~ " = cast(typeof(Sys.EventInput." ~ member
~ "))(cast(void*) data.block + info.deltas[typeof(Sys.EventInput."
~ member ~ ").component_id] + data.id * typeof(Sys.EventInput." ~ member
~ ").sizeof);\n";
}
return ret;
}
//pragma(msg,genEventCompList());
//pragma(msg,genEventCompList());
static string checkHandler()(string member)
{
string ret;
ret ~= "(Parameters!(Sys."~member~")).length == 2 && ";
ret ~= "((is(Parameters!(Sys."~member~")[0] == Sys.EventInput) && hasStaticMember!(Parameters!(Sys."~member~")[1],\"event_id\")) ||";
ret ~= " (is(Parameters!(Sys."~member~")[1] == Sys.EventInput) && hasStaticMember!(Parameters!(Sys."~member~")[0],\"event_id\")))";
return ret;
}
/*static struct Handler
{
ushort id;
void* callback;
}*/
static string catchEventHanlders()()
{
int event_handlers = 0;
string ret;
string event_param;
static if(__traits(hasMember, Sys, "handleEvent"))
{
foreach(func; __traits(getOverloads, Sys, "handleEvent"))
{
event_handlers++;//pragma(msg,"kupa");
}
//ret ~= "Handler[] handlers = (cast(Handler*)alloca("~event_handlers.to!string~" * (Handler).sizeof))[0 .. "~event_handlers.to!string~"];\n";
ret ~= "system.m_event_callers = Mallocator.instance.makeArray!(System.EventCaller)("~event_handlers.to!string~");";
event_handlers = 0;
foreach(j,func; __traits(getOverloads, Sys, "handleEvent"))
{
event_param = "Parameters!(__traits(getOverloads, Sys, \"handleEvent\")["~j.to!string~"])[1]";
ret ~= "static void callHandler"~event_handlers.to!string~"(ref EventCallData data)\n{\n";
ret ~= "Sys* s = cast(Sys*) data.system_pointer;
EntityInfo* info = data.block.type_info;";
ret ~= genEventCompList();
ret ~= "s.handleEvent(input, *cast("~event_param~"*)data.event);";
ret ~= "}\n";
ret ~= "system.m_event_callers["~event_handlers.to!string~"].callback = cast(void*)&callHandler"~event_handlers.to!string~";";
ret ~= "system.m_event_callers["~event_handlers.to!string~"].id = "~event_param~".event_id;";
event_handlers++;
}
/*ret ~= "ushort max_id = 0;";
ret ~= "foreach(handler;handlers)
{
if(handler.id > max_id)max_id = handler.id;
}";
ret ~= "system.m_event_callback = Mallocator.instance.makeArray!(System.EventHandler)(max_id);";
ret ~= "foreach(handler;handlers)
{
system.m_event_callback[handler.id] = handler.callback;
}";*/
}
/*static if(__traits(hasMember, Sys, "handleEvent"))//foreach(member; __traits(allMembers,Sys))
{
//static foreach()
static if (member == "handleEvent" && mixin("isFunction!(Sys."~member~")"))
{
static if(mixin(checkHandler(member)))
{
event_handlers++;
}
}
}*/
return ret;
}
//pragma(msg,catchEventHanlders());
mixin(catchEventHanlders());
}
//dfmt on
static string genCompList()()
{
@ -199,7 +356,7 @@ class EntityManager
uint req;
uint opt;
uint absent;
uint excluded;
uint read_only;
uint modified;
foreach (member; __traits(allMembers, Sys.EntitiesData))
@ -230,9 +387,9 @@ class EntityManager
attribs++;
//break;
}
else if (att == "absent")
else if (att == "excluded")
{
absent++;
excluded++;
attribs++;
//break;
}
@ -242,7 +399,7 @@ class EntityManager
}
}
assert(attribs <= 1,
"EntitiesData member can't have both \"@optional\" and \"@absent\".");
"EntitiesData member can't have both \"@optional\" and \"@excluded\".");
if (!attribs)
req++;
if (is_read_only)
@ -253,17 +410,17 @@ class EntityManager
}
}
static if (__traits(hasMember, Sys, "AbsentComponents"))
static if (__traits(hasMember, Sys, "ExcludedComponents"))
{
static if (is(Sys.AbsentComponents == enum))
static if (is(Sys.ExcludedComponents == enum))
{
absent += (Fields!(Sys.AbsentComponents)).length; //static assert(0,"Enum AbsentComponents are not implemented yet.");
excluded += (Fields!(Sys.ExcludedComponents)).length; //static assert(0,"Enum ExcludedComponents 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.ExcludedComponents)))
&& allSameType!(string, typeof(Sys.ExcludedComponents))
&& isExpressions!(Sys.ExcludedComponents))
{
absent += Sys.AbsentComponents.length;
excluded += Sys.ExcludedComponents.length;
}
}
@ -273,39 +430,39 @@ class EntityManager
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 ~ ");";
if (excluded > 0)
ret ~= "system.m_excluded_components = Mallocator.instance.makeArray!ushort("
~ excluded.to!string ~ ");";
if (read_only > 0)
ret ~= "system.m_read_only_components = Mallocator.instance.makeArray!ushort("
~ read_only.to!string ~ ");";
if (modified > 0)
ret ~= "system.m_modified_components = Mallocator.instance.makeArray!ushort("
~ modified.to!string ~ ");";
ret ~= "ushort comp;"; //uint opt = 0;uint req = 0;uint absent = 0;";
ret ~= "ushort comp;"; //uint opt = 0;uint req = 0;uint excluded = 0;";
opt = 0;
req = 0;
absent = 0;
excluded = 0;
read_only = 0;
modified = 0;
static if (__traits(hasMember, Sys, "AbsentComponents"))
static if (__traits(hasMember, Sys, "ExcludedComponents"))
{
static if (is(Sys.AbsentComponents == enum))
static if (is(Sys.ExcludedComponents == enum))
{
//static assert(0,"Enum AbsentComponents are not implemented yet.");
foreach (str; Fields!(Sys.AbsentComponents))
ret ~= "system.m_absent_components[" ~ (absent++)
//static assert(0,"Enum ExcludedComponents are not implemented yet.");
foreach (str; Fields!(Sys.ExcludedComponents))
ret ~= "system.m_excluded_components[" ~ (excluded++)
.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.ExcludedComponents)))
&& allSameType!(string, typeof(Sys.ExcludedComponents))
&& isExpressions!(Sys.ExcludedComponents))
{
foreach (str; Sys.AbsentComponents)
ret ~= "system.m_absent_components[" ~ (absent++)
foreach (str; Sys.ExcludedComponents)
ret ~= "system.m_excluded_components[" ~ (excluded++)
.to!string ~ "] = components_map.get(\"" ~ str ~ "\", ushort.max);";
}
}
@ -349,9 +506,9 @@ class EntityManager
has_att = true;
//break;
}
else if (att == "absent")
else if (att == "excluded")
{
ret ~= "system.m_absent_components[" ~ (absent++)
ret ~= "system.m_excluded_components[" ~ (excluded++)
.to!string ~ "] = comp;";
has_att = true;
//break;
@ -399,7 +556,7 @@ class EntityManager
ushort comp;
uint req = 0;
uint opt = 0;
uint absent = 0;
uint excluded = 0;
foreach (member; __traits(allMembers, Sys.EntitiesData))
{
if (is(typeof(__traits(getMember, Sys.EntitiesData,
@ -435,9 +592,9 @@ class EntityManager
has_att = true;
break;
}
else if (att == "absent")
else if (att == "excluded")
{
absent++;
excluded++;
has_att = true;
break;
}
@ -601,7 +758,7 @@ class EntityManager
static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort))
{
static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;");//"Component should have \"__gshared ushort component_id");
static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;"); //"Component should have \"__gshared ushort component_id");
}
static if (hasMember!(Comp, "onDestroy") && isFunction!(Comp.onDestroy)
@ -642,7 +799,7 @@ class EntityManager
static if (!(hasMember!(Ev, "event_id")) || !is(typeof(Ev.event_id) == ushort))
{
static assert(0, "Add \"mixin ECS.Event;\" in top of event structure;");//"Event should have \"__gshared ushort event_id");
static assert(0, "Add \"mixin ECS.Event;\" in top of event structure;"); //"Event should have \"__gshared ushort event_id");
}
static if (hasMember!(Ev, "onDestroy") && isFunction!(Ev.onDestroy)
@ -979,9 +1136,9 @@ class EntityManager
{
System* system = &systems[system_id];
if (system.m_absent_components)
if (system.m_excluded_components)
{
foreach (id; system.m_absent_components)
foreach (id; system.m_excluded_components)
{
foreach (id2; entity.components)
{
@ -1581,12 +1738,66 @@ class EntityManager
}
}
void updateEvents()
{
bool empty = true;
//uint index = event_manager.
while(1)
{
event_manager.swapCurrent();
//event_manager.clearEvents();
uint current_index;
if(event_manager.current_index == 0)current_index = cast(uint)threads.length;
else current_index = 0;
foreach(i,event;event_manager.events)
{
foreach(first_block;event.first_blocks[current_index .. current_index + threads.length])
{
EventManager.EventBlock* block = first_block;
if(block)empty = false;
while(block)
{
EventCallData call_data;
void* event_pointer = cast(void*)block + event.data_offset;
call_data.event = event_pointer;
foreach(j;0..block.count)
{
//void* event_pointer = cast(void*)block + event.data_offset;
EntityID entity_id = *cast(EntityID*)event_pointer;
Entity* entity = id_manager.getEntityPointer(entity_id);
call_data.block = getMetaData(entity);
static if (EntityID.sizeof == 8)
call_data.id = cast(ushort)((cast(void*)entity - call_data.block.dataBegin()) >> 3);
else
call_data.id = cast(ushort)((cast(void*)entity - call_data.block.dataBegin()) / EntityID.sizeof);
foreach(caller; events[i].callers)
{
call_data.system_pointer = caller.system.m_system_pointer;
(cast(void function(ref EventCallData))caller.callback)(call_data);
}
event_pointer += events[i].size;
}
block = block.next;
}
}
}
if(empty)break;
empty = true;
//event_manager.clearEvents();
}
//event_manager.swapCurrent();
}
export void commit()
{
updateEvents();
id_manager.optimize();
updateBlocks();
removeEntities();
changeEntities();
event_manager.clearEvents();
}
/************************************************************************************************************************
@ -1601,7 +1812,8 @@ class EntityManager
foreach (ref system; systems)
{
if (system.enabled && system.m_begin)
system.m_execute = (cast(bool function(void*)) system.m_begin)(system.m_system_pointer);
system.m_execute = (cast(bool function(void*)) system.m_begin)(
system.m_system_pointer);
}
}
@ -1619,7 +1831,7 @@ class EntityManager
commit();
//clearEvents();
//event_manager.clearEvents();
}
private void getThreadID()
@ -1630,6 +1842,11 @@ class EntityManager
thread_id = 0;
}
void sendEvent(Ev)(EntityID id, Ev event)
{
event_manager.sendEvent(id, event, thread_id);
}
/*private */
void generateDependencies()
{
@ -1795,10 +2012,25 @@ class EntityManager
void function(void* pointer) destroy_callback;
}
struct EventCaller
{
System* system;
void* callback;
}
struct EventCallData
{
EntitiesBlock* block;
void* system_pointer;
void* event;
ushort id;
}
struct EventInfo
{
ushort size;
ushort alignment;
EventCaller[] callers;
void function(void* pointer) destroy_callback;
}
@ -1951,12 +2183,13 @@ class EntityManager
{
~this()
{
if(dependencies)
if (dependencies)
{
Mallocator.instance.dispose(dependencies);
Mallocator.instance.dispose(exclusion);
}
if(job_group.dependencies)Mallocator.instance.dispose(job_group.dependencies);
if (job_group.dependencies)
Mallocator.instance.dispose(job_group.dependencies);
}
uint system_id;
@ -2011,8 +2244,8 @@ class EntityManager
IDManager id_manager;
BlockAllocator /*!(page_size, pages_in_block)*/ allocator;
//EventManager event_manager;
mixin EventManagerCode;
EventManager event_manager;
//mixin EventManagerCode;
//Vector!EntityID entities_to_remove;
//Vector!(EntitiesBlock*) blocks_to_update;