-Systems, Components and Events now must have proper mixin. Mixins are located in ecs.core module. (i.e. mixin ECS.Component)
-Multithreading support: *multithreaded update - updateMT(), function generates jobs to execute *added dispatch callback function to dispatch generated jobs (setJobDispachFunc) *added getID callback for get thread ID by EntityManager -added Job structure. Job has one function "execute()". -calling partial info update (required to multithreading) -multithreaded removeEntity, addCompoenents, removeComponents. Every thread has own data and remove/change lists. -multithreaded addEntity (WIP) -fixed issue with duplicating components -simpler and faster "findBlockWithFreeSpace" function -CallDataAllocator, allocator for CallDatas (used for Jobs) -fixed some bugs/issues
This commit is contained in:
parent
3a767babc0
commit
5dd24b6462
6 changed files with 519 additions and 135 deletions
29
source/ecs/core.d
Normal file
29
source/ecs/core.d
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
module ecs.core;
|
||||||
|
|
||||||
|
public import ecs.manager;
|
||||||
|
|
||||||
|
static struct ECS
|
||||||
|
{
|
||||||
|
mixin template System(uint jobs_count = 32)
|
||||||
|
{
|
||||||
|
__gshared ushort system_id;
|
||||||
|
EntityManager.Job[] _ecs_jobs;
|
||||||
|
|
||||||
|
void __ecsInitialize()
|
||||||
|
{
|
||||||
|
import std.experimental.allocator.mallocator;
|
||||||
|
import std.experimental.allocator;
|
||||||
|
_ecs_jobs = Mallocator.instance.makeArray!(EntityManager.Job)(jobs_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin template Component()
|
||||||
|
{
|
||||||
|
__gshared ushort component_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin template Event()
|
||||||
|
{
|
||||||
|
__gshared ushort event_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ import std.traits;
|
||||||
|
|
||||||
import core.stdc.stdlib;
|
import core.stdc.stdlib;
|
||||||
import core.stdc.string;
|
import core.stdc.string;
|
||||||
|
import core.atomic;
|
||||||
|
|
||||||
import ecs.entity;
|
import ecs.entity;
|
||||||
import ecs.block_allocator;
|
import ecs.block_allocator;
|
||||||
|
|
@ -22,11 +23,10 @@ alias SerializeVector = ecs.vector.Vector!ubyte;
|
||||||
|
|
||||||
class EntityManager
|
class EntityManager
|
||||||
{
|
{
|
||||||
|
export static void initialize(uint threads_count)
|
||||||
export static void initialize()
|
|
||||||
{
|
{
|
||||||
if (instance is null)
|
if (instance is null)
|
||||||
instance = Mallocator.instance.make!EntityManager;
|
instance = Mallocator.instance.make!EntityManager(threads_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
export static void destroy()
|
export static void destroy()
|
||||||
|
|
@ -42,7 +42,7 @@ class EntityManager
|
||||||
foreach (ref system; instance.systems)
|
foreach (ref system; instance.systems)
|
||||||
{
|
{
|
||||||
if (system.m_destroy)
|
if (system.m_destroy)
|
||||||
system.m_destroy(system.m_system_pointer);
|
(cast(void function(void*))system.m_destroy)(system.m_system_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mallocator.instance.dispose(instance);
|
Mallocator.instance.dispose(instance);
|
||||||
|
|
@ -52,8 +52,10 @@ class EntityManager
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
*Default constructor.
|
*Default constructor.
|
||||||
*/
|
*/
|
||||||
this()
|
this(uint threads_count)
|
||||||
{
|
{
|
||||||
|
if(threads_count == 0)threads_count = 0;
|
||||||
|
threads = Mallocator.instance.makeArray!ThreadData(threads_count);
|
||||||
//event_manager = EventManager(this);
|
//event_manager = EventManager(this);
|
||||||
//event_manager.manager = this;
|
//event_manager.manager = this;
|
||||||
}
|
}
|
||||||
|
|
@ -272,11 +274,11 @@ class EntityManager
|
||||||
Sys.EntitiesData, member)) == const(Entity)[]))
|
Sys.EntitiesData, member)) == const(Entity)[]))
|
||||||
{
|
{
|
||||||
ret ~= "input_data." ~ member
|
ret ~= "input_data." ~ member
|
||||||
~ " = (cast(Entity*) block.dataBegin())[0 .. block.entities_count];";
|
~ " = (cast(Entity*) block.dataBegin())[offset .. entities_count];";
|
||||||
}
|
}
|
||||||
else if (member == "length")
|
else if (member == "length")
|
||||||
{
|
{
|
||||||
ret ~= "input_data." ~ member ~ " = block.entities_count;";
|
ret ~= "input_data." ~ member ~ " = cast(typeof(input_data.length))(entities_count - offset);";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -292,7 +294,7 @@ class EntityManager
|
||||||
~ opt.to!string ~ "]] != 0)input_data." ~ member
|
~ opt.to!string ~ "]] != 0)input_data." ~ member
|
||||||
~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member
|
~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member
|
||||||
~ "))*)(cast(void*) block + info.deltas[ data.system.m_optional_components["
|
~ "))*)(cast(void*) block + info.deltas[ data.system.m_optional_components["
|
||||||
~ opt.to!string ~ "]]))[0 .. block.entities_count];
|
~ opt.to!string ~ "]]))[offset .. entities_count];
|
||||||
else input_data."
|
else input_data."
|
||||||
~ member ~ " = null;";
|
~ member ~ " = null;";
|
||||||
opt++;
|
opt++;
|
||||||
|
|
@ -310,7 +312,7 @@ class EntityManager
|
||||||
{
|
{
|
||||||
ret ~= "input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member
|
ret ~= "input_data." ~ member ~ " = (cast(ForeachType!(typeof(Sys.EntitiesData." ~ member
|
||||||
~ "))*)(cast(void*) block + info.deltas[ data.system.m_components["
|
~ "))*)(cast(void*) block + info.deltas[ data.system.m_components["
|
||||||
~ req.to!string ~ "]]))[0 .. block.entities_count];";
|
~ req.to!string ~ "]]))[offset .. entities_count];";
|
||||||
req++;
|
req++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -319,22 +321,47 @@ class EntityManager
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//pragma(msg,genFillInputData);
|
||||||
|
|
||||||
static void callUpdate(ref CallData data)
|
static void callUpdate(ref CallData data)
|
||||||
{
|
{
|
||||||
Sys* s = cast(Sys*) data.system.m_system_pointer;
|
Sys* s = cast(Sys*) data.system.m_system_pointer;
|
||||||
|
|
||||||
Sys.EntitiesData input_data;
|
Sys.EntitiesData input_data;
|
||||||
|
EntityInfo* info = data.info; //block.type_info;
|
||||||
|
|
||||||
EntitiesBlock* block = data.info.first_block;
|
EntitiesBlock* block;
|
||||||
while (block !is null)
|
if (data.first_block)
|
||||||
|
block = data.first_block;
|
||||||
|
else
|
||||||
|
block = info.first_block;
|
||||||
|
|
||||||
|
uint offset = data.begin;
|
||||||
|
uint entities_count;
|
||||||
|
uint blocks;
|
||||||
|
if (data.blocks)
|
||||||
|
blocks = data.blocks;
|
||||||
|
else
|
||||||
|
blocks = uint.max;
|
||||||
|
|
||||||
|
while (block !is null && blocks > 0)
|
||||||
{
|
{
|
||||||
EntityInfo* info = block.type_info;
|
if (blocks == 1)
|
||||||
|
{
|
||||||
|
if (data.end)
|
||||||
|
entities_count = data.end;
|
||||||
|
else entities_count = block.entities_count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
entities_count = block.entities_count;
|
||||||
|
|
||||||
mixin(genFillInputData());
|
mixin(genFillInputData());
|
||||||
|
|
||||||
s.update(input_data);
|
s.update(input_data);
|
||||||
|
|
||||||
block = block.next_block;
|
block = block.next_block;
|
||||||
|
offset = 0;
|
||||||
|
blocks--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -368,6 +395,8 @@ class EntityManager
|
||||||
|
|
||||||
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;
|
||||||
|
(cast(Sys*) system.m_system_pointer).__ecsInitialize();
|
||||||
|
system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs;
|
||||||
|
|
||||||
mixin(genCompList());
|
mixin(genCompList());
|
||||||
|
|
||||||
|
|
@ -383,7 +412,7 @@ class EntityManager
|
||||||
/*if (systems[sys_id].m_destroy)
|
/*if (systems[sys_id].m_destroy)
|
||||||
systems[sys_id].m_destroy(systems[sys_id].m_system_pointer);*/
|
systems[sys_id].m_destroy(systems[sys_id].m_system_pointer);*/
|
||||||
if (system.m_create)
|
if (system.m_create)
|
||||||
system.m_create(system.m_system_pointer);
|
(cast(void function(void*))system.m_create)(system.m_system_pointer);
|
||||||
|
|
||||||
systems[sys_id] = system;
|
systems[sys_id] = system;
|
||||||
Sys.system_id = sys_id;
|
Sys.system_id = sys_id;
|
||||||
|
|
@ -396,7 +425,7 @@ class EntityManager
|
||||||
systems.add(system);
|
systems.add(system);
|
||||||
|
|
||||||
if (system.m_create)
|
if (system.m_create)
|
||||||
system.m_create(system.m_system_pointer);
|
(cast(void function(void*))system.m_create)(system.m_system_pointer);
|
||||||
|
|
||||||
systems[$ - 1].enable();
|
systems[$ - 1].enable();
|
||||||
|
|
||||||
|
|
@ -538,15 +567,16 @@ class EntityManager
|
||||||
System* sys = &systems[caller.system_id];
|
System* sys = &systems[caller.system_id];
|
||||||
if (sys.enabled)
|
if (sys.enabled)
|
||||||
{
|
{
|
||||||
if (sys.m_begin)
|
//if (sys.m_begin)
|
||||||
sys.m_begin(sys.m_system_pointer);
|
// sys.m_begin(sys.m_system_pointer);
|
||||||
foreach (info; caller.infos)
|
foreach (info; caller.infos)
|
||||||
{
|
{
|
||||||
CallData data = CallData(caller.system_id, sys, info);
|
CallData data = CallData(caller.system_id, sys, info);
|
||||||
(cast(SytemFuncType) data.system.m_update)(data);
|
data.update();
|
||||||
|
//(cast(SytemFuncType) data.system.m_update)(data);
|
||||||
}
|
}
|
||||||
if (sys.m_end)
|
//if (sys.m_end)
|
||||||
sys.m_end(sys.m_system_pointer);
|
// sys.m_end(sys.m_system_pointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -557,22 +587,158 @@ class EntityManager
|
||||||
foreach (data; info.callers)
|
foreach (data; info.callers)
|
||||||
{
|
{
|
||||||
if (data.system.enabled)
|
if (data.system.enabled)
|
||||||
(cast(SytemFuncType) data.system.m_update)(data); //caller(call_data,null);
|
data.update();
|
||||||
|
//(cast(SytemFuncType) data.system.m_update)(data); //caller(call_data,null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateMT()
|
||||||
|
{
|
||||||
|
assert(m_dispatch_jobs,
|
||||||
|
"Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc().");
|
||||||
|
Vector!CallData tmp_datas;
|
||||||
|
tmp_datas.reserve(8);
|
||||||
|
|
||||||
|
foreach (caller; system_callers)
|
||||||
|
{
|
||||||
|
System* sys = &systems[caller.system_id];
|
||||||
|
if (sys.enabled)
|
||||||
|
{
|
||||||
|
uint entities_count = 0;
|
||||||
|
foreach (info; caller.infos)
|
||||||
|
{
|
||||||
|
uint blocks_count = info.blocksCount();
|
||||||
|
if(blocks_count == 0)continue;
|
||||||
|
if (blocks_count > 1)
|
||||||
|
entities_count += (blocks_count - 1) * info.max_entities;
|
||||||
|
entities_count += info.last_block.entities_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entities_count)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint jobs_count = cast(uint) sys.jobs.length;
|
||||||
|
uint entities_per_job = entities_count / jobs_count + 1;
|
||||||
|
|
||||||
|
if (entities_per_job <= 4)
|
||||||
|
{
|
||||||
|
jobs_count = entities_count / 4;
|
||||||
|
if(jobs_count == 0)jobs_count = 1;
|
||||||
|
entities_per_job = entities_count / jobs_count + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint job_id = 0;
|
||||||
|
entities_count = 0;
|
||||||
|
|
||||||
|
void nextJob()
|
||||||
|
{
|
||||||
|
CallData[] callers = m_call_data_allocator.getCallData(cast(uint)tmp_datas.length);
|
||||||
|
callers[0..$] = tmp_datas[0..$];
|
||||||
|
tmp_datas.clear();
|
||||||
|
sys.jobs[job_id].callers = callers;
|
||||||
|
job_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (info; caller.infos)
|
||||||
|
{
|
||||||
|
uint blocks_count = info.blocksCount();
|
||||||
|
EntitiesBlock* first_block = info.first_block;
|
||||||
|
uint first_elem = 0;
|
||||||
|
begin:
|
||||||
|
if (first_block is null || blocks_count == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((blocks_count - 1) * info.max_entities + entities_count
|
||||||
|
+ info.last_block.entities_count - first_elem >= entities_per_job)
|
||||||
|
{
|
||||||
|
int reamaining_entities = (entities_per_job - entities_count - (first_block.entities_count - first_elem));
|
||||||
|
if(reamaining_entities >= 0)
|
||||||
|
{
|
||||||
|
int full_blocks_count = reamaining_entities / info.max_entities;
|
||||||
|
EntitiesBlock* block = first_block;
|
||||||
|
foreach (i; 0 .. full_blocks_count + 1)
|
||||||
|
block = block.next_block;
|
||||||
|
|
||||||
|
if (
|
||||||
|
full_blocks_count * info.max_entities
|
||||||
|
+ entities_count + (first_block.entities_count - first_elem) >= entities_per_job)
|
||||||
|
{
|
||||||
|
CallData data = CallData(caller.system_id, sys, info, first_block,
|
||||||
|
cast(ushort) (full_blocks_count + 1), cast(ushort) first_elem, 0);
|
||||||
|
tmp_datas.add(data);
|
||||||
|
first_elem = 0;
|
||||||
|
blocks_count -= full_blocks_count + 1;
|
||||||
|
first_block = block;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entities_count += full_blocks_count * info.max_entities + (first_block.entities_count - first_elem);// - first_elem;
|
||||||
|
uint last_elem = entities_per_job - entities_count;// + first_elem - 1;
|
||||||
|
CallData data = CallData(caller.system_id, sys, info, first_block,
|
||||||
|
cast(ushort)(full_blocks_count + 2),
|
||||||
|
cast(ushort) first_elem, cast(ushort) last_elem);
|
||||||
|
tmp_datas.add(data);
|
||||||
|
first_elem = last_elem;
|
||||||
|
blocks_count -= full_blocks_count + 1;
|
||||||
|
assert(first_elem <= block.entities_count);
|
||||||
|
first_block = block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint last_elem = entities_per_job - entities_count;
|
||||||
|
CallData data = CallData(caller.system_id, sys, info, first_block,
|
||||||
|
1, cast(ushort) first_elem, cast(ushort)(first_elem + last_elem));
|
||||||
|
tmp_datas.add(data);
|
||||||
|
first_elem += last_elem;
|
||||||
|
assert(first_elem <= first_block.entities_count);
|
||||||
|
}
|
||||||
|
nextJob();
|
||||||
|
entities_count = 0;
|
||||||
|
goto begin;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CallData data = CallData(caller.system_id, sys, info,
|
||||||
|
first_block, cast(ushort) blocks_count, cast(ushort) first_elem);
|
||||||
|
tmp_datas.add(data);
|
||||||
|
entities_count += (blocks_count - 1)
|
||||||
|
* info.max_entities + info.last_block.entities_count - first_elem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextJob();
|
||||||
|
|
||||||
|
m_dispatch_jobs(sys.jobs[0..job_id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Job
|
||||||
|
{
|
||||||
|
CallData[] callers;
|
||||||
|
|
||||||
|
void execute()
|
||||||
|
{
|
||||||
|
EntityManager.instance.getThreadID();
|
||||||
|
foreach (ref caller; callers)
|
||||||
|
{
|
||||||
|
caller.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setJobDispachFunc(void delegate(Job[]) func)
|
||||||
|
{
|
||||||
|
m_dispatch_jobs = func;
|
||||||
|
}
|
||||||
|
|
||||||
static void alignNum(ref ushort num, ushort alignment)
|
static void alignNum(ref ushort num, ushort alignment)
|
||||||
{
|
{
|
||||||
num = cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); //num += alignment - (num & (alignment - 1));
|
num = cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); //num += alignment - (num & (alignment - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static ushort alignedNum(ushort num, ushort alignment)
|
|
||||||
{
|
|
||||||
return cast(ushort)((num + alignment - 1) & (-cast(int) alignment));
|
|
||||||
}*/
|
|
||||||
|
|
||||||
extern (C) static int compareUShorts(const void* a, const void* b)
|
extern (C) static int compareUShorts(const void* a, const void* b)
|
||||||
{
|
{
|
||||||
ushort _a = *cast(ushort*) a;
|
ushort _a = *cast(ushort*) a;
|
||||||
|
|
@ -754,7 +920,7 @@ class EntityManager
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
system_callers[index].infos.add(&entity);
|
if(index < system_callers.length)system_callers[index].infos.add(&entity);
|
||||||
/*for (; index < entity.callers.length; index++)
|
/*for (; index < entity.callers.length; index++)
|
||||||
{
|
{
|
||||||
CallData* caller = &entity.callers[index];
|
CallData* caller = &entity.callers[index];
|
||||||
|
|
@ -822,11 +988,12 @@ class EntityManager
|
||||||
*/
|
*/
|
||||||
export void removeComponents(EntityID entity_id, ushort[] del_ids)
|
export void removeComponents(EntityID entity_id, ushort[] del_ids)
|
||||||
{
|
{
|
||||||
|
ThreadData* data = &threads[thread_id];
|
||||||
uint num = cast(uint) del_ids.length;
|
uint num = cast(uint) del_ids.length;
|
||||||
change_entities_list.add(0);
|
data.change_entities_list.add(0);
|
||||||
change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]);
|
data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]);
|
||||||
change_entities_list.add((cast(ubyte*)&num)[0 .. 4]);
|
data.change_entities_list.add((cast(ubyte*)&num)[0 .. 4]);
|
||||||
change_entities_list.add(cast(ubyte[]) del_ids);
|
data.change_entities_list.add(cast(ubyte[]) del_ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void __removeComponents(EntityID entity_id, ushort[] del_ids)
|
private void __removeComponents(EntityID entity_id, ushort[] del_ids)
|
||||||
|
|
@ -961,34 +1128,42 @@ class EntityManager
|
||||||
|
|
||||||
uint j = 0;
|
uint j = 0;
|
||||||
uint k = 0;
|
uint k = 0;
|
||||||
foreach (ref id; ids)
|
uint len = 0;
|
||||||
|
//foreach (ref id; ids)
|
||||||
|
for(;len<ids.length;len++)
|
||||||
{
|
{
|
||||||
|
ushort* id = &ids[len];
|
||||||
if (k >= new_ids.length)
|
if (k >= new_ids.length)
|
||||||
{
|
{
|
||||||
id = info.components[j++];
|
if(j >= info.components.length)break;
|
||||||
continue;
|
*id = info.components[j++];
|
||||||
|
//continue;
|
||||||
}
|
}
|
||||||
if (j >= info.components.length)
|
else if (j >= info.components.length)
|
||||||
{
|
{
|
||||||
id = new_ids[k++];
|
*id = new_ids[k++];
|
||||||
continue;
|
//continue;
|
||||||
}
|
}
|
||||||
debug if (new_ids[k] == info.components[j])
|
else if(new_ids[k] == info.components[j])
|
||||||
assert(0, "Trying to add already existing component!");
|
|
||||||
if (new_ids[k] < info.components[j])
|
|
||||||
{
|
{
|
||||||
id = new_ids[k++];
|
*id = info.components[j++];
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
/*debug if (new_ids[k] == info.components[j])
|
||||||
|
assert(0, "Trying to add already existing component!");*/
|
||||||
|
else if (new_ids[k] < info.components[j])
|
||||||
|
{
|
||||||
|
*id = new_ids[k++];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
id = info.components[j++];
|
*id = info.components[j++];
|
||||||
}
|
}
|
||||||
|
if(len == info.components.length)return;
|
||||||
|
|
||||||
EntityInfo* new_info = getEntityInfo(ids);
|
EntityInfo* new_info = getEntityInfo(ids[0..len]);
|
||||||
|
|
||||||
EntitiesBlock* new_block = findBlockWithFreeSpace(new_info);
|
EntitiesBlock* new_block = findBlockWithFreeSpace(new_info);
|
||||||
|
|
||||||
//removeEntityNoID(entity, block);
|
|
||||||
|
|
||||||
void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof;
|
void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof;
|
||||||
|
|
||||||
Entity* new_entity = cast(Entity*) start;
|
Entity* new_entity = cast(Entity*) start;
|
||||||
|
|
@ -1001,10 +1176,10 @@ class EntityManager
|
||||||
uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) >> 3);
|
uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) >> 3);
|
||||||
else
|
else
|
||||||
uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) / EntityID.sizeof());
|
uint ind = cast(uint)((cast(void*) entity - block.dataBegin()) / EntityID.sizeof());
|
||||||
foreach (ref id; ids)
|
foreach (ref id; ids[0..len])
|
||||||
{
|
{
|
||||||
void* dst = cast(void*) new_block + new_info.deltas[id] + (
|
void* dst = cast(void*) new_block + new_info.deltas[id] + (
|
||||||
new_block.entities_count + new_block.added_count) * components[id].size;
|
new_block.entities_count /*+ new_block.added_count*/) * components[id].size;
|
||||||
uint size = components[id].size;
|
uint size = components[id].size;
|
||||||
if (k >= new_ids.length)
|
if (k >= new_ids.length)
|
||||||
{
|
{
|
||||||
|
|
@ -1060,14 +1235,14 @@ class EntityManager
|
||||||
{
|
{
|
||||||
pointers[i] = ∁
|
pointers[i] = ∁
|
||||||
}*/
|
}*/
|
||||||
|
ThreadData* data = &threads[thread_id];
|
||||||
change_entities_list.add(1);
|
data.change_entities_list.add(1);
|
||||||
change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]);
|
data.change_entities_list.add((cast(ubyte*)&entity_id)[0 .. 8]);
|
||||||
change_entities_list.add((cast(ubyte*)&num)[0 .. 4]);
|
data.change_entities_list.add((cast(ubyte*)&num)[0 .. 4]);
|
||||||
change_entities_list.add(cast(ubyte[]) new_ids);
|
data.change_entities_list.add(cast(ubyte[]) new_ids);
|
||||||
static foreach (i, comp; comps)
|
static foreach (i, comp; comps)
|
||||||
{
|
{
|
||||||
change_entities_list.add((cast(ubyte*)&comp)[0 .. comp.sizeof]);
|
data.change_entities_list.add((cast(ubyte*)&comp)[0 .. comp.sizeof]);
|
||||||
}
|
}
|
||||||
|
|
||||||
//__addComponents(entity_id, new_ids, pointers);
|
//__addComponents(entity_id, new_ids, pointers);
|
||||||
|
|
@ -1093,9 +1268,30 @@ class EntityManager
|
||||||
*/
|
*/
|
||||||
export ref Entity addEntity(EntityTemplate* tmpl)
|
export ref Entity addEntity(EntityTemplate* tmpl)
|
||||||
{
|
{
|
||||||
EntitiesBlock* block = findBlockWithFreeSpace(tmpl.info);
|
|
||||||
uint id = (block.entities_count + block.added_count);
|
|
||||||
EntityInfo* info = tmpl.info;
|
EntityInfo* info = tmpl.info;
|
||||||
|
EntitiesBlock* last_block = info.last_block;
|
||||||
|
ushort index = 0;
|
||||||
|
if(last_block)/*index = */
|
||||||
|
{
|
||||||
|
//index = last_block.added_count;
|
||||||
|
index = last_block.added_count.atomicOp!"+="(1);
|
||||||
|
}
|
||||||
|
EntitiesBlock* block = findBlockWithFreeSpace(tmpl.info,index);
|
||||||
|
if(block != last_block)
|
||||||
|
{
|
||||||
|
//index = block.added_count;
|
||||||
|
/*if(last_block)
|
||||||
|
{
|
||||||
|
//last_block.added_count.atomicOp!"-="(1);
|
||||||
|
last_block.added_count = cast(ushort)(info.max_entities - last_block.entities_count);
|
||||||
|
}*/
|
||||||
|
index = block.added_count.atomicOp!"+="(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//index--;
|
||||||
|
//index = cast(ushort)(block.added_count - 1);
|
||||||
|
uint id = (block.entities_count + index - 1);//block.added_count);
|
||||||
|
//EntityInfo* info = tmpl.info;
|
||||||
|
|
||||||
void* data_begin = block.dataBegin();
|
void* data_begin = block.dataBegin();
|
||||||
void* start = data_begin + EntityID.sizeof * id;
|
void* start = data_begin + EntityID.sizeof * id;
|
||||||
|
|
@ -1106,23 +1302,45 @@ class EntityManager
|
||||||
tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size);
|
tmpl.entity_data.ptr + info.tmpl_deltas[comp], components[comp].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!block.added_count)
|
//if (!block.added_count)
|
||||||
|
//if(block.added_count == 1)
|
||||||
|
if(index == 1)
|
||||||
blocks_to_update.add(block);
|
blocks_to_update.add(block);
|
||||||
|
|
||||||
Entity* entity = cast(Entity*) start;
|
Entity* entity = cast(Entity*) start;
|
||||||
entity.id = id_manager.getNewID();
|
entity.id = id_manager.getNewID();
|
||||||
entity.updateID();
|
entity.updateID();
|
||||||
block.added_count++;
|
//block.added_count++;
|
||||||
|
//import core.atomic;
|
||||||
|
|
||||||
//block.entities_count++;
|
//block.entities_count++;
|
||||||
return *entity;
|
return *entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info)
|
private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info, uint new_index = 1)
|
||||||
{
|
{
|
||||||
EntitiesBlock* previous_block;
|
//EntitiesBlock* previous_block;
|
||||||
EntitiesBlock* block = info.last_block;
|
EntitiesBlock* block = info.last_block;
|
||||||
|
|
||||||
while (1)
|
if(block is null)
|
||||||
|
{
|
||||||
|
block = cast(EntitiesBlock*) allocator.getBlock(); //AlignedMallocator.instance.alignedAllocate(page_size, page_size);
|
||||||
|
*block = EntitiesBlock(info);
|
||||||
|
block.id = 0;
|
||||||
|
info.first_block = block;
|
||||||
|
info.last_block = block;
|
||||||
|
}
|
||||||
|
else if(block.entities_count + new_index/*block.added_count*/ > info.max_entities)
|
||||||
|
{
|
||||||
|
EntitiesBlock* new_block = cast(EntitiesBlock*) allocator.getBlock(); //AlignedMallocator.instance.alignedAllocate(page_size, page_size);
|
||||||
|
*new_block = EntitiesBlock(info);
|
||||||
|
new_block.prev_block = block;
|
||||||
|
block.next_block = new_block;
|
||||||
|
new_block.id = cast(ushort)(block.id + 1);
|
||||||
|
block = new_block;
|
||||||
|
info.last_block = block;
|
||||||
|
}//*/
|
||||||
|
/*while (1)
|
||||||
{
|
{
|
||||||
if (block is null)
|
if (block is null)
|
||||||
{
|
{
|
||||||
|
|
@ -1143,8 +1361,6 @@ class EntityManager
|
||||||
break; // new block certainly has free space
|
break; // new block certainly has free space
|
||||||
}
|
}
|
||||||
// check if there is enought space
|
// check if there is enought space
|
||||||
/*if (block.dataDelta() + (
|
|
||||||
block.entities_count + block.added_count + 1) * info.size > page_size)*/
|
|
||||||
if (block.entities_count + block.added_count >= block.type_info.max_entities)
|
if (block.entities_count + block.added_count >= block.type_info.max_entities)
|
||||||
{
|
{
|
||||||
previous_block = block;
|
previous_block = block;
|
||||||
|
|
@ -1153,7 +1369,7 @@ class EntityManager
|
||||||
}
|
}
|
||||||
|
|
||||||
break; // block exists and bounds check passed
|
break; // block exists and bounds check passed
|
||||||
}
|
}//*/
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
@ -1166,7 +1382,7 @@ class EntityManager
|
||||||
*/
|
*/
|
||||||
export void removeEntity(EntityID id)
|
export void removeEntity(EntityID id)
|
||||||
{
|
{
|
||||||
entities_to_remove.add(id);
|
threads[thread_id].entities_to_remove.add(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void __removeEntity(EntityID id)
|
private void __removeEntity(EntityID id)
|
||||||
|
|
@ -1209,7 +1425,7 @@ class EntityManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(block !is info.last_block || pos != block.entities_count)
|
if (block !is info.last_block || pos != block.entities_count)
|
||||||
{
|
{
|
||||||
foreach (comp; info.components)
|
foreach (comp; info.components)
|
||||||
{
|
{
|
||||||
|
|
@ -1236,6 +1452,7 @@ class EntityManager
|
||||||
if (block.prev_block)
|
if (block.prev_block)
|
||||||
{
|
{
|
||||||
block.prev_block.next_block = null;
|
block.prev_block.next_block = null;
|
||||||
|
block.prev_block.added_count = 0;
|
||||||
}
|
}
|
||||||
allocator.freeBlock(block);
|
allocator.freeBlock(block);
|
||||||
}
|
}
|
||||||
|
|
@ -1253,41 +1470,44 @@ class EntityManager
|
||||||
}
|
}
|
||||||
|
|
||||||
private void changeEntites()
|
private void changeEntites()
|
||||||
|
{
|
||||||
|
foreach(ref thread;threads)
|
||||||
{
|
{
|
||||||
uint index = 0;
|
uint index = 0;
|
||||||
uint len = cast(uint) change_entities_list.length;
|
uint len = cast(uint) thread.change_entities_list.length;
|
||||||
while (index < len)
|
while (index < len)
|
||||||
{
|
{
|
||||||
if (!change_entities_list[index++])
|
if (!thread.change_entities_list[index++])
|
||||||
{
|
{
|
||||||
EntityID id = *cast(EntityID*)&change_entities_list[index];
|
EntityID id = *cast(EntityID*)&thread.change_entities_list[index];
|
||||||
index += EntityID.sizeof;
|
index += EntityID.sizeof;
|
||||||
uint num = *cast(uint*)&change_entities_list[index];
|
uint num = *cast(uint*)&thread.change_entities_list[index];
|
||||||
index += uint.sizeof;
|
index += uint.sizeof;
|
||||||
ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num];
|
ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num];
|
||||||
ids[0 .. $] = (cast(ushort*)&change_entities_list[index])[0 .. num];
|
ids[0 .. $] = (cast(ushort*)&thread.change_entities_list[index])[0 .. num];
|
||||||
index += ushort.sizeof * num;
|
index += ushort.sizeof * num;
|
||||||
__removeComponents(id, ids);
|
__removeComponents(id, ids);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EntityID id = *cast(EntityID*)&change_entities_list[index];
|
EntityID id = *cast(EntityID*)&thread.change_entities_list[index];
|
||||||
index += EntityID.sizeof;
|
index += EntityID.sizeof;
|
||||||
uint num = *cast(uint*)&change_entities_list[index];
|
uint num = *cast(uint*)&thread.change_entities_list[index];
|
||||||
index += uint.sizeof;
|
index += uint.sizeof;
|
||||||
ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num];
|
ushort[] ids = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num];
|
||||||
ids[0 .. $] = (cast(ushort*)&change_entities_list[index])[0 .. num];
|
ids[0 .. $] = (cast(ushort*)&thread.change_entities_list[index])[0 .. num];
|
||||||
index += ushort.sizeof * num;
|
index += ushort.sizeof * num;
|
||||||
void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num];
|
void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num];
|
||||||
foreach (i; 0 .. num)
|
foreach (i; 0 .. num)
|
||||||
{
|
{
|
||||||
pointers[i] = &change_entities_list[index];
|
pointers[i] = &thread.change_entities_list[index];
|
||||||
index += components[ids[i]].size;
|
index += components[ids[i]].size;
|
||||||
}
|
}
|
||||||
__addComponents(id, ids, pointers);
|
__addComponents(id, ids, pointers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
change_entities_list.clear();
|
thread.change_entities_list.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateBlocks()
|
private void updateBlocks()
|
||||||
|
|
@ -1295,18 +1515,26 @@ class EntityManager
|
||||||
foreach (block; blocks_to_update)
|
foreach (block; blocks_to_update)
|
||||||
{
|
{
|
||||||
block.entities_count += block.added_count;
|
block.entities_count += block.added_count;
|
||||||
block.added_count = 0;
|
if(block.entities_count > block.type_info.max_entities)
|
||||||
|
{
|
||||||
|
block.entities_count = block.type_info.max_entities;
|
||||||
|
}
|
||||||
|
//block.added_count = 0;
|
||||||
|
block.added_count.atomicStore(cast(ushort)0);
|
||||||
}
|
}
|
||||||
blocks_to_update.clear();
|
blocks_to_update.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeEntities()
|
private void removeEntities()
|
||||||
{
|
{
|
||||||
foreach (id; entities_to_remove)
|
foreach(i,ref thread;threads)
|
||||||
|
{
|
||||||
|
foreach (id; thread.entities_to_remove)
|
||||||
{
|
{
|
||||||
__removeEntity(id);
|
__removeEntity(id);
|
||||||
}
|
}
|
||||||
entities_to_remove.clear();
|
thread.entities_to_remove.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
|
|
@ -1317,19 +1545,20 @@ class EntityManager
|
||||||
updateBlocks();
|
updateBlocks();
|
||||||
removeEntities();
|
removeEntities();
|
||||||
changeEntites();
|
changeEntites();
|
||||||
|
m_call_data_allocator.clear();
|
||||||
|
|
||||||
version (UpdateBySystems)
|
/*version (UpdateBySystems)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{*/
|
||||||
foreach (ref system; instance.systems)
|
foreach (ref system; instance.systems)
|
||||||
{
|
{
|
||||||
if (system.m_begin)
|
if (system.m_begin)
|
||||||
system.m_begin(system.m_system_pointer);
|
(cast(void function(void*))system.m_begin)(system.m_system_pointer);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
|
|
@ -1337,18 +1566,18 @@ class EntityManager
|
||||||
*/
|
*/
|
||||||
export void end()
|
export void end()
|
||||||
{
|
{
|
||||||
version (UpdateBySystems)
|
/*version (UpdateBySystems)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{*/
|
||||||
foreach (ref system; instance.systems)
|
foreach (ref system; instance.systems)
|
||||||
{
|
{
|
||||||
if (system.m_end)
|
if (system.m_end)
|
||||||
system.m_end(system.m_system_pointer);
|
(cast(void function(void*))system.m_end)(system.m_system_pointer);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
//}
|
||||||
|
|
||||||
updateBlocks();
|
updateBlocks();
|
||||||
removeEntities();
|
removeEntities();
|
||||||
|
|
@ -1357,6 +1586,12 @@ class EntityManager
|
||||||
//clearEvents();
|
//clearEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void getThreadID()
|
||||||
|
{
|
||||||
|
if(m_thread_id_func)thread_id = m_thread_id_func();
|
||||||
|
else thread_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
*Component info;
|
*Component info;
|
||||||
*/
|
*/
|
||||||
|
|
@ -1387,7 +1622,9 @@ class EntityManager
|
||||||
///Returns number of blocks
|
///Returns number of blocks
|
||||||
uint blocksCount()
|
uint blocksCount()
|
||||||
{
|
{
|
||||||
return last_block.id;
|
if(last_block)
|
||||||
|
return last_block.id + 1;
|
||||||
|
else return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
///entity components
|
///entity components
|
||||||
|
|
@ -1438,7 +1675,8 @@ class EntityManager
|
||||||
///number of entities in block
|
///number of entities in block
|
||||||
ushort entities_count = 0;
|
ushort entities_count = 0;
|
||||||
///number of new entities in block
|
///number of new entities in block
|
||||||
ushort added_count = 0;
|
shared ushort added_count = 0;
|
||||||
|
//ushort added_count = 0;
|
||||||
///block id
|
///block id
|
||||||
ushort id = 0;
|
ushort id = 0;
|
||||||
///maximum number of entities in block
|
///maximum number of entities in block
|
||||||
|
|
@ -1452,15 +1690,32 @@ class EntityManager
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
*Structure with data used to calling System calls.
|
*Structure with data used to calling System calls.
|
||||||
|
*
|
||||||
|
*<i>first_block</i>, <i>begin</i>, <i>end</i>, <i>blocks</i> parameters are used
|
||||||
|
*to call partial info update
|
||||||
*/
|
*/
|
||||||
struct CallData
|
struct CallData
|
||||||
{
|
{
|
||||||
|
void update()
|
||||||
|
{
|
||||||
|
(cast(SytemFuncType) system.m_update)(this);
|
||||||
|
}
|
||||||
|
|
||||||
///system ID. Used to update system pointer after system reload.
|
///system ID. Used to update system pointer after system reload.
|
||||||
uint system_id;
|
uint system_id;
|
||||||
///pointer to used system
|
///pointer to used system
|
||||||
System* system;
|
System* system;
|
||||||
///poiner to Entity type info
|
///poiner to Entity type info
|
||||||
EntityManager.EntityInfo* info;
|
EntityManager.EntityInfo* info;
|
||||||
|
|
||||||
|
///pointer to first block into process (if 0 then first block will be used)
|
||||||
|
EntitiesBlock* first_block;
|
||||||
|
///number of blocks to update (if 0 then update all)
|
||||||
|
ushort blocks;
|
||||||
|
///index of first element in first block
|
||||||
|
ushort begin;
|
||||||
|
///index of last element in last block
|
||||||
|
ushort end;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SystemCaller
|
struct SystemCaller
|
||||||
|
|
@ -1470,6 +1725,16 @@ class EntityManager
|
||||||
Vector!(EntityInfo*) infos;
|
Vector!(EntityInfo*) infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ThreadData
|
||||||
|
{
|
||||||
|
Vector!EntityID entities_to_remove;
|
||||||
|
Vector!ubyte change_entities_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint thread_id;
|
||||||
|
|
||||||
|
ThreadData[] threads;
|
||||||
|
|
||||||
Vector!(SystemCaller*) system_callers;
|
Vector!(SystemCaller*) system_callers;
|
||||||
|
|
||||||
alias SytemFuncType = void function(ref EntityManager.CallData data);
|
alias SytemFuncType = void function(ref EntityManager.CallData data);
|
||||||
|
|
@ -1489,9 +1754,12 @@ class EntityManager
|
||||||
//EventManager event_manager;
|
//EventManager event_manager;
|
||||||
mixin EventManagerCode;
|
mixin EventManagerCode;
|
||||||
|
|
||||||
Vector!EntityID entities_to_remove;
|
//Vector!EntityID entities_to_remove;
|
||||||
Vector!(EntitiesBlock*) blocks_to_update;
|
Vector!(EntitiesBlock*) blocks_to_update;
|
||||||
Vector!ubyte change_entities_list;
|
//Vector!ubyte change_entities_list;
|
||||||
|
|
||||||
|
void delegate(Job[] jobs) m_dispatch_jobs;
|
||||||
|
uint delegate() m_thread_id_func;
|
||||||
|
|
||||||
HashMap!(ushort[], EntityInfo*) entities_infos;
|
HashMap!(ushort[], EntityInfo*) entities_infos;
|
||||||
HashMap!(const(char)[], ushort) systems_map;
|
HashMap!(const(char)[], ushort) systems_map;
|
||||||
|
|
@ -1500,6 +1768,60 @@ class EntityManager
|
||||||
Vector!System systems;
|
Vector!System systems;
|
||||||
Vector!ComponentInfo components;
|
Vector!ComponentInfo components;
|
||||||
Vector!EventInfo events;
|
Vector!EventInfo events;
|
||||||
|
|
||||||
|
CallDataAllocator m_call_data_allocator;
|
||||||
|
struct CallDataAllocator
|
||||||
|
{
|
||||||
|
struct Block
|
||||||
|
{
|
||||||
|
CallData[256] data;
|
||||||
|
uint allocated = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector!(Block*) blocks;
|
||||||
|
uint id;
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
if(blocks.length > 0)
|
||||||
|
foreach (block; blocks[0 .. id + 1])
|
||||||
|
{
|
||||||
|
block.allocated = 0;
|
||||||
|
}
|
||||||
|
id = 0;
|
||||||
|
//blocks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
CallData[] getCallData(uint num)
|
||||||
|
{
|
||||||
|
if (blocks.length == 0)
|
||||||
|
{
|
||||||
|
Block* new_block = Mallocator.instance.make!Block;
|
||||||
|
blocks.add(new_block);
|
||||||
|
}
|
||||||
|
/*else if(blocks[$-1].allocated + num >= 256)
|
||||||
|
{
|
||||||
|
blocks.add(Block());
|
||||||
|
}*/
|
||||||
|
|
||||||
|
Block* block = blocks[id];
|
||||||
|
if (block.allocated + num >= 256)
|
||||||
|
{
|
||||||
|
id++;
|
||||||
|
if (id == blocks.length)
|
||||||
|
{
|
||||||
|
Block* new_block = Mallocator.instance.make!Block;
|
||||||
|
blocks.add(new_block);
|
||||||
|
}
|
||||||
|
block = blocks[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
CallData[] ret = block.data[block.allocated .. block.allocated + num];
|
||||||
|
block.allocated += num;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
__gshared EntityManager instance = null;
|
__gshared EntityManager instance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,6 @@ module ecs;
|
||||||
public import ecs.manager;
|
public import ecs.manager;
|
||||||
public import ecs.entity;
|
public import ecs.entity;
|
||||||
public import ecs.system;
|
public import ecs.system;
|
||||||
|
public import ecs.core;
|
||||||
import ecs.id_manager;
|
import ecs.id_manager;
|
||||||
import ecs.events;
|
import ecs.events;
|
||||||
|
|
@ -8,6 +8,7 @@ import ecs.manager;
|
||||||
*/
|
*/
|
||||||
struct System
|
struct System
|
||||||
{
|
{
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
*Check if system is enabled.
|
*Check if system is enabled.
|
||||||
*/
|
*/
|
||||||
|
|
@ -22,7 +23,7 @@ struct System
|
||||||
export void enable()
|
export void enable()
|
||||||
{
|
{
|
||||||
if (!m_enabled && m_enable)
|
if (!m_enabled && m_enable)
|
||||||
m_enable(m_system_pointer);
|
(cast(void function(void*))m_enable)(m_system_pointer);
|
||||||
m_enabled = true;
|
m_enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,7 +33,7 @@ struct System
|
||||||
export void disable()
|
export void disable()
|
||||||
{
|
{
|
||||||
if (m_enabled && m_disable)
|
if (m_enabled && m_disable)
|
||||||
m_disable(m_system_pointer);
|
(cast(void function(void*))m_disable)(m_system_pointer);
|
||||||
m_enabled = false;
|
m_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,17 +64,28 @@ package:
|
||||||
///optional components
|
///optional components
|
||||||
ushort[] m_optional_components;
|
ushort[] m_optional_components;
|
||||||
|
|
||||||
|
EntityManager.Job[] jobs;
|
||||||
|
|
||||||
//void function(ref EntityManager.CallData data) m_update;
|
//void function(ref EntityManager.CallData data) m_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_create;
|
||||||
void function(void* system_pointer) m_destroy;
|
void function(void* system_pointer) m_destroy;
|
||||||
|
|
||||||
void function(void* system_pointer) m_begin;
|
void function(void* system_pointer) m_begin;
|
||||||
void function(void* system_pointer) m_end;
|
void function(void* system_pointer) m_end;*/
|
||||||
|
|
||||||
|
void* m_enable;
|
||||||
|
void* m_disable;
|
||||||
|
|
||||||
|
void* m_create;
|
||||||
|
void* m_destroy;
|
||||||
|
|
||||||
|
void* m_begin;
|
||||||
|
void* m_end;
|
||||||
|
|
||||||
//void function(ref EntityManager.CallData data) m_initialize;
|
//void function(ref EntityManager.CallData data) m_initialize;
|
||||||
//void function(ref EntityManager.CallData data) m_deinitilize;
|
//void function(ref EntityManager.CallData data) m_deinitilize;
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,9 @@ public:
|
||||||
|
|
||||||
export void removeAll() {
|
export void removeAll() {
|
||||||
if (array !is null) {
|
if (array !is null) {
|
||||||
foreach (ref el; array[0 .. used]) {
|
/*foreach (ref el; array[0 .. used]) {
|
||||||
destroy(el);
|
destroy(el);
|
||||||
}
|
}*/
|
||||||
freeData(cast(void[]) array);
|
freeData(cast(void[]) array);
|
||||||
gVectorsDestroyed++;
|
gVectorsDestroyed++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import ecs.events;
|
||||||
import ecs.manager;
|
import ecs.manager;
|
||||||
import ecs.system;
|
import ecs.system;
|
||||||
import ecs.attributes;
|
import ecs.attributes;
|
||||||
|
import ecs.core;
|
||||||
|
|
||||||
import core.time;
|
import core.time;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
|
|
@ -14,19 +15,19 @@ int main()
|
||||||
|
|
||||||
struct TestEvent
|
struct TestEvent
|
||||||
{
|
{
|
||||||
__gshared ushort event_id;
|
mixin ECS.Event;//__gshared ushort event_id;
|
||||||
int a;
|
int a;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestEvent2
|
struct TestEvent2
|
||||||
{
|
{
|
||||||
__gshared ushort event_id;
|
mixin ECS.Event;//__gshared ushort event_id;
|
||||||
float a;
|
float a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct TestComp
|
static struct TestComp
|
||||||
{
|
{
|
||||||
__gshared ushort component_id;
|
mixin ECS.Component;//__gshared ushort component_id;
|
||||||
int a = 1;
|
int a = 1;
|
||||||
ulong b = 2;
|
ulong b = 2;
|
||||||
|
|
||||||
|
|
@ -43,7 +44,7 @@ int main()
|
||||||
|
|
||||||
static struct TestComp2
|
static struct TestComp2
|
||||||
{
|
{
|
||||||
__gshared ushort component_id;
|
mixin ECS.Component;//__gshared ushort component_id;
|
||||||
int b = 3;
|
int b = 3;
|
||||||
int a = 4;
|
int a = 4;
|
||||||
|
|
||||||
|
|
@ -60,7 +61,7 @@ int main()
|
||||||
|
|
||||||
static struct TestComp3
|
static struct TestComp3
|
||||||
{
|
{
|
||||||
__gshared ushort component_id;
|
mixin ECS.Component;//__gshared ushort component_id;
|
||||||
uint gg = 5; //good game
|
uint gg = 5; //good game
|
||||||
uint bg = 6; //bad game
|
uint bg = 6; //bad game
|
||||||
|
|
||||||
|
|
@ -77,7 +78,7 @@ int main()
|
||||||
|
|
||||||
static struct TestComp4
|
static struct TestComp4
|
||||||
{
|
{
|
||||||
__gshared ushort component_id;
|
mixin ECS.Component;//__gshared ushort component_id;
|
||||||
uint gg = 7; //good game
|
uint gg = 7; //good game
|
||||||
uint bg = 8; //bad game
|
uint bg = 8; //bad game
|
||||||
ulong a = 9;
|
ulong a = 9;
|
||||||
|
|
@ -98,7 +99,7 @@ int main()
|
||||||
|
|
||||||
struct TestSystem
|
struct TestSystem
|
||||||
{
|
{
|
||||||
__gshared ushort system_id;
|
mixin ECS.System!16;//__gshared ushort system_id;
|
||||||
|
|
||||||
void onCreate()
|
void onCreate()
|
||||||
{
|
{
|
||||||
|
|
@ -146,7 +147,7 @@ int main()
|
||||||
test2.a = 8;
|
test2.a = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(ref EntitiesData data)
|
void update(EntitiesData data)
|
||||||
{
|
{
|
||||||
foreach(i;0..data.length)
|
foreach(i;0..data.length)
|
||||||
{
|
{
|
||||||
|
|
@ -165,7 +166,7 @@ int main()
|
||||||
|
|
||||||
struct TestSystemWithHighPriority
|
struct TestSystemWithHighPriority
|
||||||
{
|
{
|
||||||
__gshared ushort system_id;
|
mixin ECS.System!16;//__gshared ushort system_id;
|
||||||
|
|
||||||
static struct EntitiesData
|
static struct EntitiesData
|
||||||
{
|
{
|
||||||
|
|
@ -177,7 +178,7 @@ int main()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(ref EntitiesData data)
|
void update(EntitiesData data)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -192,7 +193,7 @@ import std.meta;
|
||||||
|
|
||||||
struct TestSystem2
|
struct TestSystem2
|
||||||
{
|
{
|
||||||
__gshared ushort system_id;
|
mixin ECS.System!16;//__gshared ushort system_id;
|
||||||
|
|
||||||
enum AbsentComponents0
|
enum AbsentComponents0
|
||||||
{
|
{
|
||||||
|
|
@ -255,6 +256,15 @@ import std.meta;
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dispatch(EntityManager.Job[] jobs)
|
||||||
|
{
|
||||||
|
foreach(job;jobs)
|
||||||
|
{
|
||||||
|
//writeln(job);
|
||||||
|
job.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void writeEntityComponents(Entity* entity)
|
void writeEntityComponents(Entity* entity)
|
||||||
{
|
{
|
||||||
write(entity.id);
|
write(entity.id);
|
||||||
|
|
@ -270,7 +280,8 @@ import std.meta;
|
||||||
//writeln((cast(uint*) pp)[0 .. 14], " ", pp);
|
//writeln((cast(uint*) pp)[0 .. 14], " ", pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityManager.initialize();
|
EntityManager.initialize(1);
|
||||||
|
gEM.setJobDispachFunc(&dispatch);
|
||||||
assert(gEM !is null);
|
assert(gEM !is null);
|
||||||
|
|
||||||
MonoTime time = MonoTime.currTime;
|
MonoTime time = MonoTime.currTime;
|
||||||
|
|
@ -358,40 +369,49 @@ import std.meta;
|
||||||
//assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+24)) == EntityID(1,1));
|
//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));
|
//assert(*(cast(EntityID*)(cast(void*)tmpl.info.first_block+48)) == EntityID(1,1));
|
||||||
|
|
||||||
|
Entity entity2;
|
||||||
|
|
||||||
foreach (i; 0 .. 500_000)
|
foreach (i; 0 .. 500_000)
|
||||||
{
|
{
|
||||||
gEM.addEntity(tmpl);
|
entity2 = gEM.addEntity(tmpl);
|
||||||
gEM.addEntity(tmpl2);
|
gEM.addEntity(tmpl2);
|
||||||
}
|
}
|
||||||
|
|
||||||
time = MonoTime.currTime;
|
time = MonoTime.currTime;
|
||||||
|
|
||||||
gEM.begin();
|
gEM.begin();
|
||||||
|
//gEM.updateMT();
|
||||||
gEM.update();
|
gEM.update();
|
||||||
gEM.end();
|
gEM.end();
|
||||||
|
|
||||||
dur = (MonoTime.currTime - time).total!"usecs";
|
dur = (MonoTime.currTime - time).total!"usecs";
|
||||||
writeln("Update: ", dur, " usecs");
|
writeln("Update: ", dur, " usecs");
|
||||||
|
|
||||||
|
writeEntityComponents(gEM.getEntity(entity2.id));
|
||||||
|
|
||||||
time = MonoTime.currTime;
|
time = MonoTime.currTime;
|
||||||
|
|
||||||
gEM.begin();
|
gEM.begin();
|
||||||
gEM.update();
|
gEM.updateMT();
|
||||||
|
//gEM.update();
|
||||||
gEM.end();
|
gEM.end();
|
||||||
|
|
||||||
dur = (MonoTime.currTime - time).total!"usecs";
|
dur = (MonoTime.currTime - time).total!"usecs";
|
||||||
writeln("Update: ", dur, " usecs");
|
writeln("Update: ", dur, " usecs");
|
||||||
|
|
||||||
|
writeEntityComponents(gEM.getEntity(entity2.id));
|
||||||
|
|
||||||
time = MonoTime.currTime;
|
time = MonoTime.currTime;
|
||||||
|
|
||||||
gEM.begin();
|
gEM.begin();
|
||||||
gEM.update();
|
gEM.updateMT();
|
||||||
|
//gEM.update();
|
||||||
gEM.end();
|
gEM.end();
|
||||||
|
|
||||||
dur = (MonoTime.currTime - time).total!"usecs";
|
dur = (MonoTime.currTime - time).total!"usecs";
|
||||||
writeln("Update: ", dur, " usecs");
|
writeln("Update: ", dur, " usecs");
|
||||||
|
|
||||||
writeEntityComponents(gEM.getEntity(entity.id));
|
writeEntityComponents(gEM.getEntity(entity2.id));
|
||||||
|
|
||||||
entity = gEM.addEntity(tmpl);
|
entity = gEM.addEntity(tmpl);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue