-components and infos are now stored in hash maps

-adding entities
-Template allocating and freeing
-Deltas calulating for components in EntityType
-Updating for every EntityType and System
-Generate deltas, components list, and functions callers for Systems
This commit is contained in:
Mergul 2018-09-09 23:28:18 +02:00
parent 9abc36be1c
commit a61a54b43f
5 changed files with 232 additions and 44 deletions

View file

@ -1,5 +1,7 @@
module ecs.entity; module ecs.entity;
import ecs.manager;
struct EntityID struct EntityID
{ {
uint id; uint id;
@ -13,6 +15,6 @@ struct Entity
struct EntityTemplate struct EntityTemplate
{ {
uint[] components; ubyte[] entity_data;
Entity* entity; EntityManager.EntityInfo* info;
} }

View file

@ -1,11 +1,17 @@
module ecs.manager; module ecs.manager;
import std.experimental.allocator.mallocator : Mallocator; import std.experimental.allocator.mallocator : Mallocator, AlignedMallocator;
import std.experimental.allocator; import std.experimental.allocator;
import std.traits; import std.traits;
import std.algorithm : max;
import std.conv : to;
import core.stdc.string;
import ecs.system; import ecs.system;
import ecs.entity; import ecs.entity;
import ecs.vector;
import ecs.hash_map;
alias gEM = EntityManager.instance; alias gEM = EntityManager.instance;
@ -19,92 +25,217 @@ class EntityManager
void registerSystem(Sys)(int priority) void registerSystem(Sys)(int priority)
{ {
alias types = Parameters!(Sys.update);
static string genCall()()
{
string ret = "s.update(";
foreach(i,param;Parameters!(Sys.update))
{
ret ~= "*cast(types["~i.to!string~"]*)(data_pointer + data.deltas["~i.to!string~"]),";
}
ret ~= ");";
return ret;
}
static string genCompList()()
{
string ret;
foreach(i,param;Parameters!(Sys.update))
{
ret ~= "system.components["~i.to!string~"] = components_map.get(types["~i.to!string~"].stringof);\n";
}
return ret;
}
static void callUpdate(ref CallData data, void* entity) static void callUpdate(ref CallData data, void* entity)
{ {
static if(hasMember!(Sys,"update")) static if (hasMember!(Sys, "update"))
{ {
Sys* s = cast(Sys*)data.system.system_pointer; Sys* s = cast(Sys*) data.system.system_pointer;
s.update();
EntitiesBlock* block = data.info.first_block;
void* data_pointer = block.dataBegin();
mixin(genCall());
} }
} }
System system; System system;
static if(hasMember!(Sys,"update")) static if (hasMember!(Sys, "update"))
{ {
system.update = &callUpdate; system.update = &callUpdate;
} }
system.system_pointer = cast(void*)Mallocator.instance.make!Sys; system.system_pointer = cast(void*) Mallocator.instance.make!Sys;
if(systems is null) system.components = Mallocator.instance.makeArray!uint(types.length);
mixin(genCompList());
if (systems is null)
{ {
systems = Mallocator.instance.makeArray!System(1); systems = Mallocator.instance.makeArray!System(1);
systems[0] = system; systems[0] = system;
} }
else else
{ {
Mallocator.instance.expandArray(systems,1); Mallocator.instance.expandArray(systems, 1);
systems[$-1] = system; systems[$ - 1] = system;
} }
} }
void registerComponent(Comp)() void registerComponent(Comp)()
{ {
uint size = Comp.sizeof; ushort size = Comp.sizeof;
ComponentInfo info; ComponentInfo info;
info.size = size; info.size = size;
info.aligment = 8; info.aligment = Comp.alignof;//8;
if(components is null) if (components is null)
{ {
components = Mallocator.instance.makeArray!ComponentInfo(1); components = Mallocator.instance.makeArray!ComponentInfo(1);
components[0] = info; components[0] = info;
} }
else else
{ {
Mallocator.instance.expandArray(components,1); Mallocator.instance.expandArray(components, 1);
components[$-1] = info; components[$ - 1] = info;
} }
components_map.add(Comp.stringof,cast(uint)(components.length-1));
} }
void update() void update()
{ {
foreach(ref system;systems) foreach(info;&entities_infos.byValue)
{ {
if(system.update is null)continue; foreach(data;info.callers)
CallData call_data = CallData(&system,null); {
system.update(call_data,null); data.system.update(data,null);//caller(call_data,null);
}
} }
} }
EntityTemplate* allocateTemplate(uint[] components_ids) static void alignNum(ref ushort num, ushort aligment)
{
int reminder = num % aligment;
if (reminder != 0)
{
num += aligment - reminder;
}
}
EntityTemplate* allocateTemplate(ushort[] components_ids)
{ {
uint size = 0; EntityInfo* info = entities_infos.get(components_ids, null);
foreach(id;components_ids) if (info is null)
{ {
size += components[id].size; info = Mallocator.instance.make!EntityInfo;
info.components = Mallocator.instance.makeArray(components_ids);
info.deltas = Mallocator.instance.makeArray!ushort(components_ids.length);
info.size = EntityID.sizeof;
info.alignment = EntityID.alignof;
foreach (i, id; components_ids)
{
info.alignment = max(info.alignment,components[id].aligment);
alignNum(info.size, components[id].aligment);
info.deltas[i] = info.size;
info.size += components[id].size;
}
alignNum(info.size, info.alignment);
foreach(ref system;systems)
{
if(system.update is null)continue;
CallData call_data = CallData(&system,info, null);
call_data.deltas = Mallocator.instance.makeArray!ushort(system.components.length);
foreach(i,id;system.components)
{
foreach(i2,id2;info.components)
{
if(id2 == id)
{
call_data.deltas[i] = info.deltas[i2];
break;
}
}
}
info.callers.add(call_data);
}
entities_infos.add(info.components,info);
} }
size += EntityID.sizeof;
ubyte[] entity_data = Mallocator.instance.makeArray!ubyte(size);
EntityTemplate* temp = Mallocator.instance.make!EntityTemplate; EntityTemplate* temp = Mallocator.instance.make!EntityTemplate;
temp.components = components_ids; temp.entity_data = Mallocator.instance.makeArray!ubyte(info.size);
temp.entity = cast(Entity*)entity_data.ptr; temp.info = info;
return temp; return temp;
} }
void freeTemplate(EntityTemplate* template_)
{
Mallocator.instance.dispose(template_.entity_data);
Mallocator.instance.dispose(template_);
}
void addEntity(EntityTemplate* tmpl)
{
if(tmpl.info.first_block is null)
{
tmpl.info.first_block = cast(EntitiesBlock*) AlignedMallocator.instance.alignedAllocate(4096,4096);
*tmpl.info.first_block = EntitiesBlock(tmpl.info);
}
void* start = tmpl.info.first_block.dataBegin() + tmpl.info.first_block.entities_count * tmpl.info.size;
memcpy(start, tmpl.entity_data.ptr, tmpl.info.size);
tmpl.info.first_block.entities_count++;
}
struct CallData struct CallData
{ {
System* system; System* system;
uint[] deltas; EntityInfo* info;
ushort[] deltas;
} }
struct ComponentInfo struct ComponentInfo
{ {
int size; ushort size;
int aligment; ushort aligment;
} }
struct EntityInfo
{
ushort[] components;
ushort[] deltas;
ushort alignment;
ushort size;
EntitiesBlock* first_block;
Vector!(CallData) callers;
}
struct EntitiesBlock
{
void* dataBegin()
{
ushort dif = EntitiesBlock.sizeof;
alignNum(dif,type_data.alignment);
return cast(void*)&this + dif;
}
EntityInfo* type_data;
uint entities_count;
EntitiesBlock* next_block;
///there is a loooot of data (4kB, pure magic)
}
alias SytemFuncType = void function(ref EntityManager.CallData data, void* entity);
HashMap!(ushort[], EntityInfo*) entities_infos;
HashMap!(string,uint) components_map;
System[] systems; System[] systems;
ComponentInfo[] components; ComponentInfo[] components;
__gshared EntityManager instance; __gshared EntityManager instance;

View file

@ -124,7 +124,7 @@ unittest {
} }
unittest { unittest {
import mutils.container.hash_map : HashMap; import ecs.hash_map : HashMap;
HashMap!(StringIntern, StringIntern) map; HashMap!(StringIntern, StringIntern) map;

View file

@ -12,5 +12,7 @@ struct System
///pointer to system implementation ///pointer to system implementation
void* system_pointer; void* system_pointer;
uint[] components;
void function(ref EntityManager.CallData data, void* entity) update; void function(ref EntityManager.CallData data, void* entity) update;
} }

View file

@ -32,6 +32,23 @@ unittest
} }
} }
struct TestComp2
{
__gshared static int component_id;
short b;
ubyte a;
static void serializeComponent(ref TestComp comp, SerializeVector output)
{
}
static void deserializeComponent(ref TestComp comp, ubyte[] data)
{
}
}
struct TestSystem struct TestSystem
{ {
@ -40,12 +57,35 @@ unittest
} }
void update()//ref TestComp comp) void update(ref TestComp test, ref TestComp2 test2)//ref TestComp comp)
{ {
//comp.a+=1000; import std.stdio;
//comp.b+=2000; writeln("Jakis tekst! ",test.b);
import std.stdio; test.a+=1000;
writeln("Jakis tekst!"); test.b+=2000;
writeln("Jakis tekst! ",test.b);
test2.b += 2;
test2.a = 1;
writeln("Jakis tekst! ",test2.b);
}
void handleEvent(Event event, ref TestComp comp)
{
}
}
struct TestSystem2
{
void initialize(ref TestComp comp)
{
}
void update(ref TestComp2 test2)//ref TestComp comp)
{
test2.b += 1000;
} }
void handleEvent(Event event, ref TestComp comp) void handleEvent(Event event, ref TestComp comp)
@ -57,13 +97,26 @@ unittest
EntityManager.initialize(); EntityManager.initialize();
assert(gEM !is null); assert(gEM !is null);
gEM.registerComponent!TestComp2;
gEM.registerComponent!TestComp; gEM.registerComponent!TestComp;
gEM.registerSystem!TestSystem(0);
gEM.registerSystem!TestSystem2(0);
uint[1] ids = [0]; ushort[2] ids = [0,1];
EntityTemplate* tmpl = gEM.allocateTemplate(ids); EntityTemplate* tmpl = gEM.allocateTemplate(ids);
*cast(EntityID*)tmpl.entity_data.ptr = EntityID(1,1);
gEM.registerSystem!TestSystem(0); gEM.addEntity(tmpl);
gEM.addEntity(tmpl);
//assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+24)) == EntityID(1,1));
//assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+48)) == EntityID(1,1));
gEM.update(); gEM.update();
gEM.update();
import std.stdio;
writeln((cast(uint*)tmpl.info.first_block)[0..48]);
gEM.freeTemplate(tmpl);
} }