bubel-ecs/source/ecs/ecs.d
DanielMz25 6217aec6be -changed README
-license changed to BSD (maybe temporary)
-added configurations to dub.json
-initial ECS implementation (WIP):
	-Manager, System, Entity, Component
	-registering components
	-registering systems
	-calling update
2018-09-07 20:54:29 +02:00

339 lines
6.4 KiB
D

module ecs.ecs;
import std.stdio;
version(Design):
alias SytemFuncType = void function(ref SystemCallData data, void* componentsStart);
struct HasComponentsStore
{
ulong[4] bits; //256 components
bool has(HasComponentsStore components)
{
return true;
}
bool notIn(HasComponentsStore components)
{
return true;
}
int length()
{
assert(0);
}
}
// Informacje o kompnencie
struct ComponentInfo
{
int size;
int aligment;
SerializeJSON funsSerJ;
SerializeBiN funcSerB;
}
struct System
{
HasComponentsStore requiredComponents;
HasComponentsStore absenComponents;
HasComponentsStore maybeComponents;
bool enabled;
int priority;
SytemFuncType func;
}
// Informacje o systemie dla konkretnego entitiesa
struct SystemCallData
{
System* system;
int[] componentsDt;
}
// Informacje o entitiesie danego typu
struct EntityTypeData
{
HasComponentsStore components;
int[] deltas;
int totalSize;
int totalAligment = 8;
SystemCallData[] systems;
}
struct EntitiesBlock
{
EntityTypeData* typeData;
Entity* freeEntitySlot;
EntitiesBlock* nextBlock;
}
struct EntityID
{
ulong id = ulong.max;
static immutable notUsedValue = EntityID(ulong.max);
}
// Dane konkretnego Entitiesa
struct Entity
{
EntityID entityID = EntityID.notUsedValue;
union
{
string name;
Entity* nextFreeSlot;
}
//string eventOnDestroy;
uint group;
EntityID entityID;
//ubyte[XX] thereIsComponentsMemory;
}
struct Template
{
HasComponentsStore hasComp;
Entity* entity;
}
struct Manager
{
EntityAllocator entityArrayAllcoator;
ComponentInfo[] components;
System[] systems;
HashMap!(HasComponentsStore, EntitiesBlock*) entitiesDatas;
HashMapTwoWays!(string, Entity*) nameMap;
HashMapTwoWays!(EntityID, Entity*) idMap;
EntitiesBlock* getEntitiesBlock(HasComponentsStore hasComponents)
{
EntitiesBlock* block = entitiesDatas.get(hasComponents, null);
if (block is null)
{
// If such component combination was never present, add it
block = addNewBlock(hasComponents, block);
return block;
}
// Iterate over list of components until free slot is found or lists ends
do
{
if (block.freeEntitySlot !is null)
{
return block;
}
if (block.nextBlock is null)
{
block = addNewBlock(hasComponents);
return block;
}
block = block.nextBlock;
}
while (block.nextBlock !is null);
}
EntitiesBlock* addNewBlock(HasComponentsStore hasComponents, EntitiesBlock* firstBlock)
{
// Get last block so order of blocks is preserved, and first blocks are filled first
EntitiesBlock* lastBlock = firstBlock;
if (lastBlock !is null)
{
while (lastBlock.nextBlock !is null)
{
lastBlock = lastBlock.nextBlock;
}
}
assert(lastBlock is null || lastBlock.nextBlock is null);
ubyte[] memory = new ubyte[](4096);
EntitiesBlock* block = cast(EntitiesBlock*) memory.ptr;
if (lastBlock is null)
{
EntityTypeData* entityTypeData = newEntityTypeData(hasComponents);
block.typeData = entityTypeData;
block.nextBlock = null;
entitiesDatas.add(hasComponents, block);
}
else
{
lastBlock.nextBlock = block;
block.typeData = lastBlock.typeData;
block.nextBlock = null;
}
}
void alignNum(ref int num, int aligment)
{
int reminder = num % aligment;
if (reminder != 0)
{
num += aligment - reminder;
}
}
EntityTypeData* newEntityTypeData(HasComponentsStore hasComponents)
{
EntityTypeData* typeData = new EntityTypeData();
typeData.components = hasComponents;
ComponentInfo[] components = getComponentsInfo(hasComponents);
typeData.deltas.length = hasComponents.length;
foreach (i, comp; components)
{
typeData.deltas[i] = typeData.totalSize;
typeData.totalAligment.max(comp.aligment);
typeData.totalSize += comp.size;
alignNum(typeData.totalSize, comp.aligment);
}
alignNum(typeData.totalSize, typeData.totalAligment);
foreach (sys; systems)
{
if (!typeData.hasComp.has(sys.requiredComponents)
|| !typeData.hasComp.notIn(sys.absenComponents))
{
continue;
}
entTypeData.systems ~= sys;
}
return typeData;
}
void addEntity(Template* templ)
{
EntitiesBlock* block = getEntitiesBlock(templ.hasComp);
Entity* newEntity = block.freeEntitySlot;
block.freeEntitySlot = newEntity.nextFreeSlot;
// from to size
memcpy(temp.entity, newEntity, block.typeData.totalSize);
}
void addSystem(Func)(int priority)
{
HasComponentsStore requiredComponents;
HasComponentsStore absenComponents;
HasComponentsStore maybeComponents;
void systemCaller(ref SystemCallData data, void * componentsStart)
{
Func(cast(FUnc.par1Type)(componentsStart + data.componentsDt[0]),
cast(FUnc.par1Type)(componentsStart + data.componentsDt[1])/*...*/);
}
System* system = new System(&systemCaller, entTypeData);
systems ~= system;
foreach (ref entTypeData; entitiesDatas)
{
if (!entTypeData.hasComp.has(requiredComponents)
|| !entTypeData.hasComp.notIn(absenComponents))
{
continue;
}
entTypeData.systems ~= system;
}
}
}
void someSystem(CompA a, CompB b, CompC* c)
{
}
void main()
{
writeln("Edit source/app.d to start your project.");
}
class System
{
void start()
{
}
void end()
{
}
void update(ref ObjRend a)
{
}
void useEvent(EventData evvv, ref ObjRend a)
{
}
}
alias SerializeVector = ubyte[];
__gshared EntityManager gEntityManager;
unittest
{
struct ComponentA
{
__gshared static int component_id;
int a;
ulong b;
static void serializeComponent(ref ComponentA comp, SerializeVector output)
{
}
static void deerializeComponent(ref ComponentA comp, ubyte[] data)
{
}
}
gEM.addComponet!ComponentA();
assert(ComponentA.component_id == 0);
ComponentData* ccc = &gEM.componnets[ComponentA.component_id];
assert(ccc.totalAligment == 8);
assert(ccc.totalSize == 8);
HasComponentsStore hasComponents;
hasComponents.addComponet(ComponentA.component_id);
EntityTempalte* tmpl = gEM.allocateTemplate(hasComponents);
ComponentA* comp = tmpl.getComponent!ComponentA(ComponentA.component_id);
comp.a = 111;
comp.b = 222;
gEM.addEntity(tmpl);
struct SystemAdd
{
void update(ref ComponentA a)
{
a.a+=1000;
b.b+=2000;
}
void handleEvent(EventData evvv, ref ComponentA a)
{
}
}
int priority=10;
gEM.registerSystem!(SystemAdd)(priority);
gEM.updateStepAll();
foreach(EntityID id; gEM.IterateByAllEntiteis){
assert(id.getComponent(ComponentA.component_id));
ComponentA* ccc=id.getComponent(ComponentA.component_id);
assert(ccc.a==1111);
assert(ccc.b==2222);
}
}