Demos #10
16 changed files with 988 additions and 544 deletions
|
|
@ -48,47 +48,82 @@ version(ECSEmscripten)
|
||||||
{
|
{
|
||||||
static if (op == "+=")
|
static if (op == "+=")
|
||||||
{
|
{
|
||||||
static if(is(T == byte) || is(T == ubyte))return cast(Unqual!T)(emscripten_atomic_add_u8(cast(void*)&val, cast(Unqual!T)mod) + 1);
|
static if (is(T == byte) || is(T == ubyte))
|
||||||
else static if(is(T == short) || is(T == ushort))return cast(Unqual!T)(emscripten_atomic_add_u16(cast(void*)&val, cast(Unqual!T)mod) + 1);
|
return cast(Unqual!T)(emscripten_atomic_add_u8(cast(void*)&val,
|
||||||
else static if(is(T == int) || is(T == uint))return cast(Unqual!T)(emscripten_atomic_add_u32(cast(void*)&val, cast(Unqual!T)mod) + 1);
|
cast(Unqual!T) mod) + 1);
|
||||||
else static assert(0);
|
else static if (is(T == short) || is(T == ushort))
|
||||||
|
return cast(Unqual!T)(emscripten_atomic_add_u16(cast(void*)&val,
|
||||||
|
cast(Unqual!T) mod) + 1);
|
||||||
|
else static if (is(T == int) || is(T == uint))
|
||||||
|
return cast(Unqual!T)(emscripten_atomic_add_u32(cast(void*)&val,
|
||||||
|
cast(Unqual!T) mod) + 1);
|
||||||
|
else
|
||||||
|
static assert(0);
|
||||||
}
|
}
|
||||||
else static if (op == "-=")
|
else static if (op == "-=")
|
||||||
{
|
{
|
||||||
static if(is(T == byte) || is(T == ubyte))return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val, cast(Unqual!T)mod) - 1);
|
static if (is(T == byte) || is(T == ubyte))
|
||||||
else static if(is(T == short) || is(T == ushort))return cast(Unqual!T)(emscripten_atomic_sub_u16(cast(void*)&val, cast(Unqual!T)mod) - 1);
|
return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val,
|
||||||
else static if(is(T == int) || is(T == uint))return cast(Unqual!T)(emscripten_atomic_sub_u32(cast(void*)&val, cast(Unqual!T)mod) - 1);
|
cast(Unqual!T) mod) - 1);
|
||||||
else static assert(0);
|
else static if (is(T == short) || is(T == ushort))
|
||||||
|
return cast(Unqual!T)(emscripten_atomic_sub_u16(cast(void*)&val,
|
||||||
|
cast(Unqual!T) mod) - 1);
|
||||||
|
else static if (is(T == int) || is(T == uint))
|
||||||
|
return cast(Unqual!T)(emscripten_atomic_sub_u32(cast(void*)&val,
|
||||||
|
cast(Unqual!T) mod) - 1);
|
||||||
|
else
|
||||||
|
static assert(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, V newval)
|
public pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val,
|
||||||
|
V newval)
|
||||||
{
|
{
|
||||||
alias UT = Unqual!T;
|
alias UT = Unqual!T;
|
||||||
static if(is(UT == bool) || is(UT == byte) || is(UT == ubyte))emscripten_atomic_store_u8(cast(void*)&val, cast(UT)newval);
|
static if (is(UT == bool) || is(UT == byte) || is(UT == ubyte))
|
||||||
else static if(is(UT == short) || is(UT == ushort))emscripten_atomic_store_u16(cast(void*)&val, cast(UT)newval);
|
emscripten_atomic_store_u8(cast(void*)&val, cast(UT) newval);
|
||||||
else static if(is(UT == int) || is(UT == uint))emscripten_atomic_store_u32(cast(void*)&val, cast(UT)newval);
|
else static if (is(UT == short) || is(UT == ushort))
|
||||||
else static assert(0);
|
emscripten_atomic_store_u16(cast(void*)&val, cast(UT) newval);
|
||||||
|
else static if (is(UT == int) || is(UT == uint))
|
||||||
|
emscripten_atomic_store_u32(cast(void*)&val, cast(UT) newval);
|
||||||
|
else
|
||||||
|
static assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(ref const T val)
|
public pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(
|
||||||
|
ref const T val)
|
||||||
{
|
{
|
||||||
alias UT = Unqual!T;
|
alias UT = Unqual!T;
|
||||||
static if(is(UT == bool))return emscripten_atomic_load_u8(cast(const void*)&val) != 0;
|
static if (is(UT == bool))
|
||||||
else static if(is(UT == byte) || is(UT == ubyte))return emscripten_atomic_load_u8(cast(const void*)&val);
|
return emscripten_atomic_load_u8(cast(const void*)&val) != 0;
|
||||||
else static if(is(UT == short) || is(UT == ushort))return emscripten_atomic_load_u16(cast(const void*)&val);
|
else static if (is(UT == byte) || is(UT == ubyte))
|
||||||
else static if(is(UT == int) || is(UT == uint))return emscripten_atomic_load_u32(cast(const void*)&val);
|
return emscripten_atomic_load_u8(cast(const void*)&val);
|
||||||
else static assert(0);
|
else static if (is(UT == short) || is(UT == ushort))
|
||||||
|
return emscripten_atomic_load_u16(cast(const void*)&val);
|
||||||
|
else static if (is(UT == int) || is(UT == uint))
|
||||||
|
return emscripten_atomic_load_u32(cast(const void*)&val);
|
||||||
|
else
|
||||||
|
static assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq, MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis)
|
public pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq,
|
||||||
|
MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis)
|
||||||
{
|
{
|
||||||
alias UT = Unqual!T;
|
alias UT = Unqual!T;
|
||||||
static if(is(UT == bool))return emscripten_atomic_cas_u8(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis;
|
static if (is(UT == bool))
|
||||||
else static if(is(UT == byte) || is(UT == ubyte))return emscripten_atomic_cas_u8(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis;
|
return emscripten_atomic_cas_u8(cast(void*) here,
|
||||||
else static if(is(UT == short) || is(UT == ushort))return emscripten_atomic_cas_u16(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis;
|
cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis;
|
||||||
else static if(is(UT == int) || is(UT == uint))return emscripten_atomic_cas_u32(cast(void*)here, cast(Unqual!T)ifThis, cast(Unqual!T)writeThis) == ifThis;
|
else static if (is(UT == byte) || is(UT == ubyte))
|
||||||
else static assert(0);
|
return emscripten_atomic_cas_u8(cast(void*) here,
|
||||||
|
cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis;
|
||||||
|
else static if (is(UT == short) || is(UT == ushort))
|
||||||
|
return emscripten_atomic_cas_u16(cast(void*) here,
|
||||||
|
cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis;
|
||||||
|
else static if (is(UT == int) || is(UT == uint))
|
||||||
|
return emscripten_atomic_cas_u32(cast(void*) here,
|
||||||
|
cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis;
|
||||||
|
else
|
||||||
|
static assert(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -60,11 +60,13 @@ private:
|
||||||
|
|
||||||
void allocBlock() nothrow @nogc
|
void allocBlock() nothrow @nogc
|
||||||
{
|
{
|
||||||
next_block = cast(void*) Mallocator.alignAlloc(
|
next_block = cast(void*) Mallocator.alignAlloc(block_size * blocks_in_allocation,
|
||||||
block_size * blocks_in_allocation, block_size);
|
block_size);
|
||||||
if(next_block is null)assert(0);
|
if (next_block is null)
|
||||||
|
assert(0);
|
||||||
|
|
||||||
if(pointers is null)pointers = Mallocator.make!BlockPointers;
|
if (pointers is null)
|
||||||
|
pointers = Mallocator.make!BlockPointers;
|
||||||
if (pointers.numberof >= 32)
|
if (pointers.numberof >= 32)
|
||||||
{
|
{
|
||||||
BlockPointers* new_pointers = Mallocator.make!BlockPointers;
|
BlockPointers* new_pointers = Mallocator.make!BlockPointers;
|
||||||
|
|
@ -78,8 +80,7 @@ private:
|
||||||
void** pointer = cast(void**)(next_block + i * block_size);
|
void** pointer = cast(void**)(next_block + i * block_size);
|
||||||
*pointer = next_block + (i + 1) * block_size;
|
*pointer = next_block + (i + 1) * block_size;
|
||||||
}
|
}
|
||||||
void** pointer = cast(void**)(
|
void** pointer = cast(void**)(next_block + (blocks_in_allocation - 1) * block_size);
|
||||||
next_block + (blocks_in_allocation - 1) * block_size);
|
|
||||||
*pointer = null;
|
*pointer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ static struct ECS
|
||||||
{
|
{
|
||||||
__gshared ushort component_id = ushort.max;
|
__gshared ushort component_id = ushort.max;
|
||||||
|
|
||||||
ComponentRef ref_() @nogc nothrow
|
ComponentRef ref_() @nogc nothrow return
|
||||||
{
|
{
|
||||||
return ComponentRef(&this, component_id);
|
return ComponentRef(&this, component_id);
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +87,6 @@ static struct ECS
|
||||||
mixin template Event()
|
mixin template Event()
|
||||||
{
|
{
|
||||||
__gshared ushort event_id = ushort.max;
|
__gshared ushort event_id = ushort.max;
|
||||||
EntityID entity_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,7 @@ struct Entity
|
||||||
if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0)
|
if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
static if (EntityID.sizeof == 8)
|
return cast(T*)(cast(void*)block + info.deltas[T.component_id] + block.entityIndex(&this) * T.sizeof);
|
||||||
uint ind = cast(uint)((cast(void*)&this - block.dataBegin()) >> 3);
|
|
||||||
else
|
|
||||||
uint ind = cast(uint)((cast(void*)&this - block.dataBegin()) / EntityID.sizeof());
|
|
||||||
return cast(T*)(cast(void*)block + info.deltas[T.component_id] + ind * T.sizeof);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasComponent(ushort component_id)
|
bool hasComponent(ushort component_id)
|
||||||
|
|
@ -58,10 +54,7 @@ struct Entity
|
||||||
{
|
{
|
||||||
EntityMeta meta;
|
EntityMeta meta;
|
||||||
meta.block = gEM.getMetaData(&this);
|
meta.block = gEM.getMetaData(&this);
|
||||||
static if (EntityID.sizeof == 8)
|
meta.index = meta.block.entityIndex(&this);
|
||||||
meta.index = cast(ushort)((cast(void*)&this - meta.block.dataBegin()) >> 3);
|
|
||||||
else
|
|
||||||
meta.index = cast(ushort)((cast(void*)&this - meta.block.dataBegin()) / EntityID.sizeof());
|
|
||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ package struct EventManager
|
||||||
EventData* data = &events[Ev.event_id];
|
EventData* data = &events[Ev.event_id];
|
||||||
EventBlock* block = data.blocks[block_id];
|
EventBlock* block = data.blocks[block_id];
|
||||||
//EntityManager.EventInfo* info = &manager.events[Ev.event_id];
|
//EntityManager.EventInfo* info = &manager.events[Ev.event_id];
|
||||||
event.entity_id = id;
|
//event.entity_id = id;
|
||||||
|
|
||||||
if (block is null)
|
if (block is null)
|
||||||
{
|
{
|
||||||
|
|
@ -60,20 +60,27 @@ package struct EventManager
|
||||||
data.blocks[block_id] = block;
|
data.blocks[block_id] = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ev* event_array = cast(Ev*)(cast(void*)block + data.data_offset);
|
uint size = Ev.sizeof + EntityID.sizeof;
|
||||||
event_array[block.count] = event;
|
void* ptr = cast(void*) block + data.data_offset + block.count * size;
|
||||||
|
*cast(EntityID*)ptr = id;
|
||||||
|
*cast(Ev*)(ptr + EntityID.sizeof) = event;
|
||||||
|
//Ev* event_array = cast(Ev*)(cast(void*) block + data.data_offset);
|
||||||
|
//event_array[block.count] = event;
|
||||||
block.count++;
|
block.count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void swapCurrent() nothrow @nogc
|
void swapCurrent() nothrow @nogc
|
||||||
{
|
{
|
||||||
uint threads_count = cast(uint) manager.threads.length;
|
uint threads_count = cast(uint) manager.threads.length;
|
||||||
if(current_index == 0)current_index = threads_count;
|
if (current_index == 0)
|
||||||
else current_index = 0;
|
current_index = threads_count;
|
||||||
|
else
|
||||||
|
current_index = 0;
|
||||||
|
|
||||||
foreach (ref event; events)
|
foreach (ref event; events)
|
||||||
{
|
{
|
||||||
foreach(ref first_block; event.first_blocks[current_index .. current_index + threads_count])
|
foreach (ref first_block; event.first_blocks[current_index
|
||||||
|
.. current_index + threads_count])
|
||||||
{
|
{
|
||||||
EventBlock* block = first_block;
|
EventBlock* block = first_block;
|
||||||
while (block)
|
while (block)
|
||||||
|
|
@ -125,7 +132,9 @@ package struct EventManager
|
||||||
event.data_offset = EventBlock.sizeof; //manager.events[i].
|
event.data_offset = EventBlock.sizeof; //manager.events[i].
|
||||||
manager.alignNum(event.data_offset, manager.events[i].alignment);
|
manager.alignNum(event.data_offset, manager.events[i].alignment);
|
||||||
|
|
||||||
event.max_events = cast(ushort)((events_block_size - event.data_offset) / manager.events[i].size);
|
uint size = manager.events[i].size + EntityID.sizeof;
|
||||||
|
event.max_events = cast(ushort)(
|
||||||
|
(events_block_size - event.data_offset) / size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,23 +11,29 @@ private enum HASH_EMPTY = 0;
|
||||||
private enum HASH_DELETED = 0x1;
|
private enum HASH_DELETED = 0x1;
|
||||||
private enum HASH_FILLED_MARK = ulong(1) << 8 * ulong.sizeof - 1;
|
private enum HASH_FILLED_MARK = ulong(1) << 8 * ulong.sizeof - 1;
|
||||||
|
|
||||||
export ulong defaultHashFunc(T)(auto ref T t) nothrow @nogc {
|
export ulong defaultHashFunc(T)(auto ref T t) nothrow @nogc
|
||||||
static if (isIntegral!(T)) {
|
{
|
||||||
|
static if (isIntegral!(T))
|
||||||
|
{
|
||||||
return hashInt(t);
|
return hashInt(t);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return 0; //hashInt(t.hashOf); // hashOf is not giving proper distribution between H1 and H2 hash parts
|
return 0; //hashInt(t.hashOf); // hashOf is not giving proper distribution between H1 and H2 hash parts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can turn bad hash function to good one
|
// Can turn bad hash function to good one
|
||||||
export ulong hashInt(ulong x) nothrow @nogc @safe {
|
export ulong hashInt(ulong x) nothrow @nogc @safe
|
||||||
|
{
|
||||||
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
|
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
|
||||||
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
|
x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
|
||||||
x = x ^ (x >> 31);
|
x = x ^ (x >> 31);
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc)
|
||||||
|
{
|
||||||
alias Key = KeyPar;
|
alias Key = KeyPar;
|
||||||
alias Value = ValuePar;
|
alias Value = ValuePar;
|
||||||
nothrow:
|
nothrow:
|
||||||
|
|
@ -35,12 +41,14 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||||
enum rehashFactor = 0.75;
|
enum rehashFactor = 0.75;
|
||||||
enum size_t getIndexEmptyValue = size_t.max;
|
enum size_t getIndexEmptyValue = size_t.max;
|
||||||
|
|
||||||
static struct KeyVal {
|
static struct KeyVal
|
||||||
|
{
|
||||||
Key key;
|
Key key;
|
||||||
Value value;
|
Value value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct Bucket {
|
static struct Bucket
|
||||||
|
{
|
||||||
ulong hash;
|
ulong hash;
|
||||||
KeyVal keyValue;
|
KeyVal keyValue;
|
||||||
}
|
}
|
||||||
|
|
@ -49,58 +57,74 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||||
size_t length; // Used to compute loadFactor
|
size_t length; // Used to compute loadFactor
|
||||||
size_t markerdDeleted;
|
size_t markerdDeleted;
|
||||||
|
|
||||||
export void clear() {
|
export void clear()
|
||||||
|
{
|
||||||
elements.clear();
|
elements.clear();
|
||||||
length = 0;
|
length = 0;
|
||||||
markerdDeleted = 0;
|
markerdDeleted = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void reset() {
|
export void reset()
|
||||||
|
{
|
||||||
elements.reset();
|
elements.reset();
|
||||||
length = 0;
|
length = 0;
|
||||||
markerdDeleted = 0;
|
markerdDeleted = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool isIn(ref Key el) {
|
export bool isIn(ref Key el)
|
||||||
|
{
|
||||||
return getIndex(el) != getIndexEmptyValue;
|
return getIndex(el) != getIndexEmptyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool isIn(Key el) {
|
export bool isIn(Key el)
|
||||||
|
{
|
||||||
return getIndex(el) != getIndexEmptyValue;
|
return getIndex(el) != getIndexEmptyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
export Value* getPtr()(auto ref Key k) {
|
export Value* getPtr()(auto ref Key k)
|
||||||
|
{
|
||||||
size_t index = getIndex(k);
|
size_t index = getIndex(k);
|
||||||
if (index == getIndexEmptyValue) {
|
if (index == getIndexEmptyValue)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return &elements[index].keyValue.value;
|
return &elements[index].keyValue.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export ref Value get()(auto ref Key k) {
|
export ref Value get()(auto ref Key k)
|
||||||
|
{
|
||||||
size_t index = getIndex(k);
|
size_t index = getIndex(k);
|
||||||
assert(index != getIndexEmptyValue);
|
assert(index != getIndexEmptyValue);
|
||||||
return elements[index].keyValue.value;
|
return elements[index].keyValue.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
deprecated("Use get with second parameter.") export auto ref Value getDefault()(
|
deprecated("Use get with second parameter.") export auto ref Value getDefault()(
|
||||||
auto ref Key k, auto ref Value defaultValue) {
|
auto ref Key k, auto ref Value defaultValue)
|
||||||
|
{
|
||||||
return get(k, defaultValue);
|
return get(k, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
export auto ref Value get()(auto ref Key k, auto ref Value defaultValue) {
|
export auto ref Value get()(auto ref Key k, auto ref Value defaultValue)
|
||||||
|
{
|
||||||
size_t index = getIndex(k);
|
size_t index = getIndex(k);
|
||||||
if (index == getIndexEmptyValue) {
|
if (index == getIndexEmptyValue)
|
||||||
|
{
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return elements[index].keyValue.value;
|
return elements[index].keyValue.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export ref Value getInsertDefault()(auto ref Key k, auto ref Value defaultValue) {
|
export ref Value getInsertDefault()(auto ref Key k, auto ref Value defaultValue)
|
||||||
|
{
|
||||||
size_t index = getIndex(k);
|
size_t index = getIndex(k);
|
||||||
if (index == getIndexEmptyValue) {
|
if (index == getIndexEmptyValue)
|
||||||
|
{
|
||||||
add(k, defaultValue);
|
add(k, defaultValue);
|
||||||
}
|
}
|
||||||
index = getIndex(k);
|
index = getIndex(k);
|
||||||
|
|
@ -109,9 +133,11 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool tryRemove(Key el) {
|
export bool tryRemove(Key el)
|
||||||
|
{
|
||||||
size_t index = getIndex(el);
|
size_t index = getIndex(el);
|
||||||
if (index == getIndexEmptyValue) {
|
if (index == getIndexEmptyValue)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
length--;
|
length--;
|
||||||
|
|
@ -120,28 +146,34 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void remove(Key el) {
|
export void remove(Key el)
|
||||||
|
{
|
||||||
bool ok = tryRemove(el);
|
bool ok = tryRemove(el);
|
||||||
assert(ok);
|
assert(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
export ref Value opIndex()(auto ref Key key) {
|
export ref Value opIndex()(auto ref Key key)
|
||||||
|
{
|
||||||
return get(key);
|
return get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
export void opIndexAssign()(auto ref Value value, auto ref Key key) {
|
export void opIndexAssign()(auto ref Value value, auto ref Key key)
|
||||||
|
{
|
||||||
add(key, value);
|
add(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export void add()(auto ref Key key, auto ref Value value) {
|
export void add()(auto ref Key key, auto ref Value value)
|
||||||
|
{
|
||||||
size_t index = getIndex(key);
|
size_t index = getIndex(key);
|
||||||
if (index != getIndexEmptyValue) {
|
if (index != getIndexEmptyValue)
|
||||||
|
{
|
||||||
elements[index].keyValue.value = value;
|
elements[index].keyValue.value = value;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getLoadFactor(length + 1) > rehashFactor
|
if (getLoadFactor(length + 1) > rehashFactor
|
||||||
|| getLoadFactor(length + markerdDeleted) > rehashFactor) {
|
|| getLoadFactor(length + markerdDeleted) > rehashFactor)
|
||||||
|
{
|
||||||
rehash();
|
rehash();
|
||||||
}
|
}
|
||||||
length++;
|
length++;
|
||||||
|
|
@ -150,10 +182,13 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||||
immutable size_t rotateMask = elements.length - 1;
|
immutable size_t rotateMask = elements.length - 1;
|
||||||
index = hash & rotateMask; // Starting point
|
index = hash & rotateMask; // Starting point
|
||||||
|
|
||||||
while (true) {
|
while (true)
|
||||||
|
{
|
||||||
Bucket* gr = &elements[index];
|
Bucket* gr = &elements[index];
|
||||||
if ((gr.hash & HASH_FILLED_MARK) == 0) {
|
if ((gr.hash & HASH_FILLED_MARK) == 0)
|
||||||
if (gr.hash == HASH_DELETED) {
|
{
|
||||||
|
if (gr.hash == HASH_DELETED)
|
||||||
|
{
|
||||||
markerdDeleted--;
|
markerdDeleted--;
|
||||||
}
|
}
|
||||||
gr.hash = hash;
|
gr.hash = hash;
|
||||||
|
|
@ -171,15 +206,18 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||||
//int numA;
|
//int numA;
|
||||||
//int numB;
|
//int numB;
|
||||||
|
|
||||||
export size_t getIndex(Key el) {
|
export size_t getIndex(Key el)
|
||||||
|
{
|
||||||
return getIndex(el);
|
return getIndex(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
export size_t getIndex(ref Key el) {
|
export size_t getIndex(ref Key el)
|
||||||
|
{
|
||||||
mixin(doNotInline);
|
mixin(doNotInline);
|
||||||
|
|
||||||
immutable size_t groupsLength = elements.length;
|
immutable size_t groupsLength = elements.length;
|
||||||
if (groupsLength == 0) {
|
if (groupsLength == 0)
|
||||||
|
{
|
||||||
return getIndexEmptyValue;
|
return getIndexEmptyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,13 +226,16 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||||
size_t index = hash & rotateMask; // Starting point
|
size_t index = hash & rotateMask; // Starting point
|
||||||
|
|
||||||
//numA++;
|
//numA++;
|
||||||
while (true) {
|
while (true)
|
||||||
|
{
|
||||||
//numB++;
|
//numB++;
|
||||||
Bucket* gr = &elements[index];
|
Bucket* gr = &elements[index];
|
||||||
if (gr.hash == hash && gr.keyValue.key == el) {
|
if (gr.hash == hash && gr.keyValue.key == el)
|
||||||
|
{
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
if (gr.hash == HASH_EMPTY) {
|
if (gr.hash == HASH_EMPTY)
|
||||||
|
{
|
||||||
return getIndexEmptyValue;
|
return getIndexEmptyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,21 +245,26 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export float getLoadFactor(size_t forElementsNum) {
|
export float getLoadFactor(size_t forElementsNum)
|
||||||
if (elements.length == 0) {
|
{
|
||||||
|
if (elements.length == 0)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return cast(float) forElementsNum / (elements.length);
|
return cast(float) forElementsNum / (elements.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
export void rehash()() {
|
export void rehash()()
|
||||||
|
{
|
||||||
mixin(doNotInline);
|
mixin(doNotInline);
|
||||||
// Get all elements
|
// Get all elements
|
||||||
Vector!KeyVal allElements;
|
Vector!KeyVal allElements;
|
||||||
allElements.reserve(elements.length);
|
allElements.reserve(elements.length);
|
||||||
|
|
||||||
foreach (ref Bucket el; elements) {
|
foreach (ref Bucket el; elements)
|
||||||
if ((el.hash & HASH_FILLED_MARK) == 0) {
|
{
|
||||||
|
if ((el.hash & HASH_FILLED_MARK) == 0)
|
||||||
|
{
|
||||||
el.hash = HASH_EMPTY;
|
el.hash = HASH_EMPTY;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -227,12 +273,14 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getLoadFactor(length + 1) > rehashFactor) { // Reallocate
|
if (getLoadFactor(length + 1) > rehashFactor)
|
||||||
|
{ // Reallocate
|
||||||
elements.length = (elements.length ? elements.length : 4) << 1; // Power of two, initially 8 elements
|
elements.length = (elements.length ? elements.length : 4) << 1; // Power of two, initially 8 elements
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert elements
|
// Insert elements
|
||||||
foreach (i, ref el; allElements) {
|
foreach (i, ref el; allElements)
|
||||||
|
{
|
||||||
add(el.key, el.value);
|
add(el.key, el.value);
|
||||||
}
|
}
|
||||||
length = allElements.length;
|
length = allElements.length;
|
||||||
|
|
@ -240,19 +288,29 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// foreach support
|
// foreach support
|
||||||
export int opApply(DG)(scope DG dg) {
|
export int opApply(DG)(scope DG dg)
|
||||||
|
{
|
||||||
int result;
|
int result;
|
||||||
foreach (ref Bucket gr; elements) {
|
foreach (ref Bucket gr; elements)
|
||||||
if ((gr.hash & HASH_FILLED_MARK) == 0) {
|
{
|
||||||
|
if ((gr.hash & HASH_FILLED_MARK) == 0)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
static if (isForeachDelegateWithTypes!(DG, Key)) {
|
static if (isForeachDelegateWithTypes!(DG, Key))
|
||||||
|
{
|
||||||
result = dg(gr.keyValue.key);
|
result = dg(gr.keyValue.key);
|
||||||
} else static if (isForeachDelegateWithTypes!(DG, Value)) {
|
}
|
||||||
|
else static if (isForeachDelegateWithTypes!(DG, Value))
|
||||||
|
{
|
||||||
result = dg(gr.keyValue.value);
|
result = dg(gr.keyValue.value);
|
||||||
} else static if (isForeachDelegateWithTypes!(DG, Key, Value)) {
|
}
|
||||||
|
else static if (isForeachDelegateWithTypes!(DG, Key, Value))
|
||||||
|
{
|
||||||
result = dg(gr.keyValue.key, gr.keyValue.value);
|
result = dg(gr.keyValue.key, gr.keyValue.value);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
static assert(0);
|
static assert(0);
|
||||||
}
|
}
|
||||||
if (result)
|
if (result)
|
||||||
|
|
@ -263,9 +321,11 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export int byKey(scope int delegate(Key k) nothrow dg) {
|
export int byKey(scope int delegate(Key k) nothrow dg)
|
||||||
|
{
|
||||||
int result;
|
int result;
|
||||||
foreach (ref Key k; this) {
|
foreach (ref Key k; this)
|
||||||
|
{
|
||||||
result = dg(k);
|
result = dg(k);
|
||||||
if (result)
|
if (result)
|
||||||
break;
|
break;
|
||||||
|
|
@ -273,9 +333,11 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export int byValue(scope int delegate(ref Value k) nothrow dg) {
|
export int byValue(scope int delegate(ref Value k) nothrow dg)
|
||||||
|
{
|
||||||
int result;
|
int result;
|
||||||
foreach (ref Value v; this) {
|
foreach (ref Value v; this)
|
||||||
|
{
|
||||||
result = dg(v);
|
result = dg(v);
|
||||||
if (result)
|
if (result)
|
||||||
break;
|
break;
|
||||||
|
|
@ -283,9 +345,11 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export int byKeyValue(scope int delegate(ref Key k, ref Value v) nothrow dg) {
|
export int byKeyValue(scope int delegate(ref Key k, ref Value v) nothrow dg)
|
||||||
|
{
|
||||||
int result;
|
int result;
|
||||||
foreach (ref Key k, ref Value v; this) {
|
foreach (ref Key k, ref Value v; this)
|
||||||
|
{
|
||||||
result = dg(k, v);
|
result = dg(k, v);
|
||||||
if (result)
|
if (result)
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -112,9 +112,11 @@ struct IDManager
|
||||||
*/
|
*/
|
||||||
export bool isExist(EntityID id) nothrow @nogc
|
export bool isExist(EntityID id) nothrow @nogc
|
||||||
{
|
{
|
||||||
if(id.id >= m_ids_array.length)return false;
|
if (id.id >= m_ids_array.length)
|
||||||
|
return false;
|
||||||
Data* data = &m_ids_array[id.id];
|
Data* data = &m_ids_array[id.id];
|
||||||
if(data.entity is null)return false;
|
if (data.entity is null)
|
||||||
|
return false;
|
||||||
return data.counter == id.counter;
|
return data.counter == id.counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,7 +128,8 @@ struct IDManager
|
||||||
m_ids_array = Mallocator.makeArray!Data(65536);
|
m_ids_array = Mallocator.makeArray!Data(65536);
|
||||||
m_free_stack = Mallocator.makeArray!uint(65536);
|
m_free_stack = Mallocator.makeArray!uint(65536);
|
||||||
m_blocks = Mallocator.makeArray!Block(64);
|
m_blocks = Mallocator.makeArray!Block(64);
|
||||||
foreach(ref block;m_blocks)block = Block();
|
foreach (ref block; m_blocks)
|
||||||
|
block = Block();
|
||||||
m_blocks_count = 1;
|
m_blocks_count = 1;
|
||||||
m_blocks[0].alloc();
|
m_blocks[0].alloc();
|
||||||
|
|
||||||
|
|
@ -142,13 +145,16 @@ struct IDManager
|
||||||
*/
|
*/
|
||||||
void deinitialize() @trusted @nogc nothrow
|
void deinitialize() @trusted @nogc nothrow
|
||||||
{
|
{
|
||||||
if(m_ids_array)Mallocator.dispose(m_ids_array);
|
if (m_ids_array)
|
||||||
if(m_free_stack)Mallocator.dispose(m_free_stack);
|
Mallocator.dispose(m_ids_array);
|
||||||
|
if (m_free_stack)
|
||||||
|
Mallocator.dispose(m_free_stack);
|
||||||
if (m_blocks)
|
if (m_blocks)
|
||||||
{
|
{
|
||||||
foreach (ref block; m_blocks)
|
foreach (ref block; m_blocks)
|
||||||
{
|
{
|
||||||
if(block.data)block.free();
|
if (block.data)
|
||||||
|
block.free();
|
||||||
}
|
}
|
||||||
Mallocator.dispose(m_blocks);
|
Mallocator.dispose(m_blocks);
|
||||||
}
|
}
|
||||||
|
|
@ -165,7 +171,8 @@ struct IDManager
|
||||||
*/
|
*/
|
||||||
void optimize() nothrow @nogc
|
void optimize() nothrow @nogc
|
||||||
{
|
{
|
||||||
if(m_stack_top < -1)m_stack_top = -1;
|
if (m_stack_top < -1)
|
||||||
|
m_stack_top = -1;
|
||||||
if (m_last_id > m_ids_array.length)
|
if (m_last_id > m_ids_array.length)
|
||||||
{
|
{
|
||||||
uint begin = cast(uint) m_ids_array.length;
|
uint begin = cast(uint) m_ids_array.length;
|
||||||
|
|
@ -181,11 +188,14 @@ struct IDManager
|
||||||
|
|
||||||
foreach (block; m_blocks[0 .. m_blocks_count - 1])
|
foreach (block; m_blocks[0 .. m_blocks_count - 1])
|
||||||
{
|
{
|
||||||
memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, block.data.ptr, 65536 * Data.sizeof);
|
memcpy(cast(void*) m_ids_array.ptr + begin * Data.sizeof,
|
||||||
|
block.data.ptr, 65536 * Data.sizeof);
|
||||||
begin += 65536;
|
begin += 65536;
|
||||||
}
|
}
|
||||||
memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, m_blocks[m_blocks_count-1].data.ptr, (m_last_id - begin) * Data.sizeof);
|
memcpy(cast(void*) m_ids_array.ptr + begin * Data.sizeof,
|
||||||
foreach(ref block;m_blocks[1..m_blocks_count])block.free();
|
m_blocks[m_blocks_count - 1].data.ptr, (m_last_id - begin) * Data.sizeof);
|
||||||
|
foreach (ref block; m_blocks[1 .. m_blocks_count])
|
||||||
|
block.free();
|
||||||
m_blocks_count = 1;
|
m_blocks_count = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -402,7 +402,7 @@ export struct EntityManager
|
||||||
Sys* data_system = cast(Sys*) data.system_pointer;
|
Sys* data_system = cast(Sys*) data.system_pointer;
|
||||||
|
|
||||||
Type* event = cast(Type*) data.event;
|
Type* event = cast(Type*) data.event;
|
||||||
data_system.handleEvent(gEM.getEntity(event.entity_id), *event);
|
data_system.handleEvent(data.entity, *event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setEventCallers(Sys)(ref System system)
|
void setEventCallers(Sys)(ref System system)
|
||||||
|
|
@ -1018,8 +1018,7 @@ export struct EntityManager
|
||||||
|
|
||||||
static if (hasMember!(Sys.EntitiesData, "job_id"))
|
static if (hasMember!(Sys.EntitiesData, "job_id"))
|
||||||
{
|
{
|
||||||
input_data.job_id = cast(typeof(input_data.job_id)) data
|
input_data.job_id = cast(typeof(input_data.job_id)) data.job_id;
|
||||||
.job_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//s.onUpdate(input_data);
|
//s.onUpdate(input_data);
|
||||||
|
|
@ -1052,8 +1051,7 @@ export struct EntityManager
|
||||||
|
|
||||||
static if (hasMember!(Sys.EntitiesData, "job_id"))
|
static if (hasMember!(Sys.EntitiesData, "job_id"))
|
||||||
{
|
{
|
||||||
input_data.job_id = cast(typeof(input_data.job_id)) data
|
input_data.job_id = cast(typeof(input_data.job_id)) data.job_id;
|
||||||
.job_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(cast(typeof(&__traits(getOverloads, s,
|
(cast(typeof(&__traits(getOverloads, s,
|
||||||
|
|
@ -1146,7 +1144,8 @@ export struct EntityManager
|
||||||
|
|
||||||
foreach (iii, comp_info; components_info.readonlyDeps)
|
foreach (iii, comp_info; components_info.readonlyDeps)
|
||||||
{
|
{
|
||||||
ushort comp = external_dependencies_map.get(cast(const (char)[]) comp_info.type, ushort.max);
|
ushort comp = external_dependencies_map.get(cast(const(char)[]) comp_info.type,
|
||||||
|
ushort.max);
|
||||||
version (D_BetterC)
|
version (D_BetterC)
|
||||||
assert(comp != ushort.max,
|
assert(comp != ushort.max,
|
||||||
"Can't register system \"" ~ Sys.stringof
|
"Can't register system \"" ~ Sys.stringof
|
||||||
|
|
@ -1174,7 +1173,9 @@ export struct EntityManager
|
||||||
if (sys_id < systems.length)
|
if (sys_id < systems.length)
|
||||||
{
|
{
|
||||||
systems[sys_id].disable();
|
systems[sys_id].disable();
|
||||||
if(systems[sys_id].m_destroy)(cast(void function(void*)) systems[sys_id].m_destroy)(systems[sys_id].m_system_pointer);
|
if (systems[sys_id].m_destroy)
|
||||||
|
(cast(void function(void*)) systems[sys_id].m_destroy)(
|
||||||
|
systems[sys_id].m_system_pointer);
|
||||||
|
|
||||||
if (system.m_create)
|
if (system.m_create)
|
||||||
(cast(void function(void*)) system.m_create)(system.m_system_pointer);
|
(cast(void function(void*)) system.m_create)(system.m_system_pointer);
|
||||||
|
|
@ -1274,6 +1275,9 @@ export struct EntityManager
|
||||||
info.create_callback = &callCreate;
|
info.create_callback = &callCreate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static if (Comp.sizeof == 1 && Fields!(Comp).length == 0)
|
||||||
|
info.size = 0;
|
||||||
|
else
|
||||||
info.size = Comp.sizeof;
|
info.size = Comp.sizeof;
|
||||||
info.alignment = Comp.alignof; //8;
|
info.alignment = Comp.alignof; //8;
|
||||||
info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof);
|
info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof);
|
||||||
|
|
@ -1340,7 +1344,9 @@ export struct EntityManager
|
||||||
"Can't call function with system which hasn't EntitesData structure.");
|
"Can't call function with system which hasn't EntitesData structure.");
|
||||||
static assert(__traits(hasMember, Sys, "onUpdate"),
|
static assert(__traits(hasMember, Sys, "onUpdate"),
|
||||||
"Can't call function with system which hasn't onUpdate function callback.");
|
"Can't call function with system which hasn't onUpdate function callback.");
|
||||||
static assert(is(SetFunctionAttributes!(T,functionLinkage!(s.onUpdate), functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)), "Function must match system update function.");
|
static assert(is(SetFunctionAttributes!(T, functionLinkage!(s.onUpdate),
|
||||||
|
functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)),
|
||||||
|
"Function must match system update function.");
|
||||||
static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type.");
|
static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type.");
|
||||||
|
|
||||||
System* system = getSystem(Sys.system_id);
|
System* system = getSystem(Sys.system_id);
|
||||||
|
|
@ -1612,6 +1618,8 @@ export struct EntityManager
|
||||||
//fill components with default data
|
//fill components with default data
|
||||||
foreach (comp; info.components)
|
foreach (comp; info.components)
|
||||||
{
|
{
|
||||||
|
if (components[comp].size == 0)
|
||||||
|
continue;
|
||||||
memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp],
|
memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp],
|
||||||
components[comp].init_data.ptr, components[comp].size);
|
components[comp].init_data.ptr, components[comp].size);
|
||||||
}
|
}
|
||||||
|
|
@ -1621,6 +1629,8 @@ export struct EntityManager
|
||||||
ushort index = block.entityIndex(entity);
|
ushort index = block.entityIndex(entity);
|
||||||
foreach (comp; info.components)
|
foreach (comp; info.components)
|
||||||
{
|
{
|
||||||
|
if (components[comp].size == 0)
|
||||||
|
continue;
|
||||||
memcpy(cast(void*) temp.entity_data.ptr + info.tmpl_deltas[comp],
|
memcpy(cast(void*) temp.entity_data.ptr + info.tmpl_deltas[comp],
|
||||||
cast(void*) block + info.deltas[comp] + components[comp].size * index,
|
cast(void*) block + info.deltas[comp] + components[comp].size * index,
|
||||||
components[comp].size);
|
components[comp].size);
|
||||||
|
|
@ -1669,6 +1679,8 @@ export struct EntityManager
|
||||||
//fill components with default data
|
//fill components with default data
|
||||||
foreach (comp; info.components)
|
foreach (comp; info.components)
|
||||||
{
|
{
|
||||||
|
if (components[comp].size == 0)
|
||||||
|
continue;
|
||||||
memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp],
|
memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp],
|
||||||
components[comp].init_data.ptr, components[comp].size);
|
components[comp].init_data.ptr, components[comp].size);
|
||||||
}
|
}
|
||||||
|
|
@ -1736,14 +1748,19 @@ export struct EntityManager
|
||||||
//fill components with default data and copy from base template
|
//fill components with default data and copy from base template
|
||||||
foreach (comp; info.components)
|
foreach (comp; info.components)
|
||||||
{
|
{
|
||||||
if (comp < base_tmpl.info.deltas.length && base_tmpl.info.deltas[comp] != ushort.max) //copy data from base component
|
if (comp < base_tmpl.info.tmpl_deltas.length
|
||||||
|
&& base_tmpl.info.tmpl_deltas[comp] != ushort.max) //copy data from base component
|
||||||
{
|
{
|
||||||
|
if (components[comp].size == 0)
|
||||||
|
continue;
|
||||||
memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp],
|
memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp],
|
||||||
base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp],
|
base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp],
|
||||||
components[comp].size);
|
components[comp].size);
|
||||||
}
|
}
|
||||||
else //fill with default data
|
else //fill with default data
|
||||||
{
|
{
|
||||||
|
if (components[comp].size == 0)
|
||||||
|
continue;
|
||||||
memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp],
|
memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp],
|
||||||
components[comp].init_data.ptr, components[comp].size);
|
components[comp].init_data.ptr, components[comp].size);
|
||||||
}
|
}
|
||||||
|
|
@ -1833,8 +1850,8 @@ export struct EntityManager
|
||||||
}
|
}
|
||||||
|
|
||||||
info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length);
|
info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length);
|
||||||
info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length,
|
//info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(instance.components.length);
|
||||||
info);
|
info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length);
|
||||||
|
|
||||||
foreach (comp; info.components)
|
foreach (comp; info.components)
|
||||||
{
|
{
|
||||||
|
|
@ -2160,6 +2177,8 @@ export struct EntityManager
|
||||||
foreach (comp; new_info.components)
|
foreach (comp; new_info.components)
|
||||||
{
|
{
|
||||||
uint comp_size = components[comp].size;
|
uint comp_size = components[comp].size;
|
||||||
|
if (comp_size == 0)
|
||||||
|
continue;
|
||||||
memcpy(cast(void*) new_block + new_info.deltas[comp] + new_block.entities_count * comp_size,
|
memcpy(cast(void*) new_block + new_info.deltas[comp] + new_block.entities_count * comp_size,
|
||||||
cast(void*) block + info.deltas[comp] + ind * comp_size, comp_size);
|
cast(void*) block + info.deltas[comp] + ind * comp_size, comp_size);
|
||||||
}
|
}
|
||||||
|
|
@ -2296,23 +2315,28 @@ export struct EntityManager
|
||||||
|
|
||||||
foreach (id; new_info.components) //ids[0 .. len])
|
foreach (id; new_info.components) //ids[0 .. len])
|
||||||
{
|
{
|
||||||
void* dst = cast(void*) new_block + new_info.deltas[id] + (
|
|
||||||
new_block.entities_count) * components[id].size;
|
|
||||||
uint size = components[id].size;
|
uint size = components[id].size;
|
||||||
|
void* dst = void;
|
||||||
|
if (size != 0)
|
||||||
|
dst = cast(void*) new_block + new_info.deltas[id] + (new_block.entities_count)
|
||||||
|
* size;
|
||||||
|
|
||||||
if (k >= new_ids.length)
|
if (k >= new_ids.length)
|
||||||
{
|
{
|
||||||
|
if (size != 0)
|
||||||
memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size);
|
memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size);
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
else if (j >= info.components.length || id == new_ids[k])
|
else if (j >= info.components.length || id == new_ids[k])
|
||||||
{
|
{
|
||||||
|
if (size != 0)
|
||||||
memcpy(dst, data_pointers[k], size);
|
memcpy(dst, data_pointers[k], size);
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(id != new_ids[0]);
|
assert(id != new_ids[0]);
|
||||||
|
if (size != 0)
|
||||||
memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size);
|
memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size);
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
|
@ -2397,7 +2421,9 @@ export struct EntityManager
|
||||||
}
|
}
|
||||||
foreach (ref_; comps)
|
foreach (ref_; comps)
|
||||||
{
|
{
|
||||||
data.changeEntitiesList.add((cast(ubyte*)ref_.ptr)[0 .. components[ref_.component_id].size]);
|
if (components[ref_.component_id].size != 0)
|
||||||
|
data.changeEntitiesList.add(
|
||||||
|
(cast(ubyte*) ref_.ptr)[0 .. components[ref_.component_id].size]);
|
||||||
}
|
}
|
||||||
/*data.changeEntitiesList.add(cast(ubyte[]) new_ids);
|
/*data.changeEntitiesList.add(cast(ubyte[]) new_ids);
|
||||||
static foreach (i, comp; comps)
|
static foreach (i, comp; comps)
|
||||||
|
|
@ -2449,14 +2475,15 @@ export struct EntityManager
|
||||||
|
|
||||||
foreach (i, comp; info.components)
|
foreach (i, comp; info.components)
|
||||||
{
|
{
|
||||||
memcpy(cast(void*) new_block + info.deltas[comp] + components[comp].size * new_id,
|
ushort size = components[comp].size;
|
||||||
cast(void*) block + info.deltas[comp] + components[comp].size * index,
|
if (size != 0)
|
||||||
components[comp].size);
|
memcpy(cast(void*) new_block + info.deltas[comp] + size * new_id,
|
||||||
|
cast(void*) block + info.deltas[comp] + size * index, size);
|
||||||
|
|
||||||
if (components[comp].create_callback)
|
if (components[comp].create_callback)
|
||||||
{
|
{
|
||||||
components[comp].create_callback(cast(
|
components[comp].create_callback(
|
||||||
void*) block + info.deltas[comp] + new_id * components[comp].size);
|
cast(void*) block + info.deltas[comp] + new_id * size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2552,6 +2579,7 @@ export struct EntityManager
|
||||||
foreach (comp; info.components)
|
foreach (comp; info.components)
|
||||||
{
|
{
|
||||||
uint size = components[comp].size;
|
uint size = components[comp].size;
|
||||||
|
if (size != 0)
|
||||||
memcpy(cast(void*) block + info.deltas[comp] + size * id,
|
memcpy(cast(void*) block + info.deltas[comp] + size * id,
|
||||||
tmpl.entity_data.ptr + info.tmpl_deltas[comp], size);
|
tmpl.entity_data.ptr + info.tmpl_deltas[comp], size);
|
||||||
}
|
}
|
||||||
|
|
@ -2564,8 +2592,8 @@ export struct EntityManager
|
||||||
if (delta != ushort.max)
|
if (delta != ushort.max)
|
||||||
{
|
{
|
||||||
uint size = components[comp.component_id].size;
|
uint size = components[comp.component_id].size;
|
||||||
memcpy(cast(void*) block + delta + size * id,
|
if (size != 0)
|
||||||
comp.ptr, size);
|
memcpy(cast(void*) block + delta + size * id, comp.ptr, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2678,8 +2706,10 @@ export struct EntityManager
|
||||||
{
|
{
|
||||||
//get entity and block meta data pointers
|
//get entity and block meta data pointers
|
||||||
Entity* entity = id_manager.getEntityPointer(id);
|
Entity* entity = id_manager.getEntityPointer(id);
|
||||||
|
|
||||||
if (entity is null)
|
if (entity is null)
|
||||||
return; //return if entity doesn't exist
|
return; //return if entity doesn't exist
|
||||||
|
|
||||||
EntitiesBlock* block = getMetaData(entity);
|
EntitiesBlock* block = getMetaData(entity);
|
||||||
|
|
||||||
EntityInfo* info = block.type_info;
|
EntityInfo* info = block.type_info;
|
||||||
|
|
@ -2700,6 +2730,9 @@ export struct EntityManager
|
||||||
{
|
{
|
||||||
EntityInfo* info = block.type_info;
|
EntityInfo* info = block.type_info;
|
||||||
|
|
||||||
|
if (info.last_block.added_count)
|
||||||
|
updateBlock(info.last_block);
|
||||||
|
|
||||||
info.last_block.entities_count--;
|
info.last_block.entities_count--;
|
||||||
|
|
||||||
uint pos = block.entityIndex(entity);
|
uint pos = block.entityIndex(entity);
|
||||||
|
|
@ -2720,9 +2753,11 @@ export struct EntityManager
|
||||||
{
|
{
|
||||||
foreach (comp; info.components)
|
foreach (comp; info.components)
|
||||||
{
|
{
|
||||||
|
uint size = components[comp].size;
|
||||||
|
if (size == 0)
|
||||||
|
continue;
|
||||||
void* src = cast(void*) info.last_block + info.deltas[comp];
|
void* src = cast(void*) info.last_block + info.deltas[comp];
|
||||||
void* dst = cast(void*) block + info.deltas[comp];
|
void* dst = cast(void*) block + info.deltas[comp];
|
||||||
uint size = components[comp].size;
|
|
||||||
memcpy(dst + pos * size, src + info.last_block.entities_count * size, size);
|
memcpy(dst + pos * size, src + info.last_block.entities_count * size, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2768,7 +2803,8 @@ export struct EntityManager
|
||||||
{
|
{
|
||||||
uint index = 0;
|
uint index = 0;
|
||||||
uint len = cast(uint) thread.changeEntitiesListPrev.length;
|
uint len = cast(uint) thread.changeEntitiesListPrev.length;
|
||||||
if(len)has_work = true;
|
if (len)
|
||||||
|
has_work = true;
|
||||||
void*[32] pointers; // = (cast(void**) alloca(num * (void*).sizeof))[0 .. num];
|
void*[32] pointers; // = (cast(void**) alloca(num * (void*).sizeof))[0 .. num];
|
||||||
while (index < len)
|
while (index < len)
|
||||||
{
|
{
|
||||||
|
|
@ -2885,15 +2921,7 @@ export struct EntityManager
|
||||||
(cast(void function(ref ListenerCallData) nothrow @nogc) system.m_change_entity)(data);
|
(cast(void function(ref ListenerCallData) nothrow @nogc) system.m_change_entity)(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool updateBlocks()
|
private void updateBlock(EntitiesBlock* block) @nogc nothrow
|
||||||
{
|
|
||||||
bool has_work = false;
|
|
||||||
//foreach (ref ThreadData thread; threads)thread.swapToUpdate();
|
|
||||||
foreach (ref ThreadData thread; threads)
|
|
||||||
{
|
|
||||||
//thread.swapToUpdate();
|
|
||||||
if(thread.blockToUpdatePrev.length)has_work = true;
|
|
||||||
foreach (block; thread.blockToUpdatePrev)
|
|
||||||
{
|
{
|
||||||
EntityInfo* info = block.type_info;
|
EntityInfo* info = block.type_info;
|
||||||
ushort entities_count = block.entities_count;
|
ushort entities_count = block.entities_count;
|
||||||
|
|
@ -2909,6 +2937,20 @@ export struct EntityManager
|
||||||
callAddEntityListeners(info, block, entities_count, block.entities_count);
|
callAddEntityListeners(info, block, entities_count, block.entities_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool updateBlocks()
|
||||||
|
{
|
||||||
|
bool has_work = false;
|
||||||
|
//foreach (ref ThreadData thread; threads)thread.swapToUpdate();
|
||||||
|
foreach (ref ThreadData thread; threads)
|
||||||
|
{
|
||||||
|
//thread.swapToUpdate();
|
||||||
|
if (thread.blockToUpdatePrev.length)
|
||||||
|
has_work = true;
|
||||||
|
foreach (block; thread.blockToUpdatePrev)
|
||||||
|
{
|
||||||
|
updateBlock(block);
|
||||||
|
}
|
||||||
thread.blockToUpdatePrev.clear();
|
thread.blockToUpdatePrev.clear();
|
||||||
}
|
}
|
||||||
return has_work;
|
return has_work;
|
||||||
|
|
@ -2920,7 +2962,8 @@ export struct EntityManager
|
||||||
//foreach (ref ThreadData thread; threads)thread.swapToRemove();
|
//foreach (ref ThreadData thread; threads)thread.swapToRemove();
|
||||||
foreach (ref ThreadData thread; threads)
|
foreach (ref ThreadData thread; threads)
|
||||||
{
|
{
|
||||||
if(thread.entitiesToRemovePrev.length)has_work = true;
|
if (thread.entitiesToRemovePrev.length)
|
||||||
|
has_work = true;
|
||||||
foreach (id; thread.entitiesToRemovePrev)
|
foreach (id; thread.entitiesToRemovePrev)
|
||||||
{
|
{
|
||||||
__removeEntity(id);
|
__removeEntity(id);
|
||||||
|
|
@ -2944,11 +2987,12 @@ export struct EntityManager
|
||||||
current_index = 0;
|
current_index = 0;
|
||||||
foreach (i, event; event_manager.events)
|
foreach (i, event; event_manager.events)
|
||||||
{
|
{
|
||||||
foreach (first_block; event.first_blocks[current_index
|
foreach (first_block; event.first_blocks[current_index .. current_index + threads
|
||||||
.. current_index + threads.length])
|
.length])
|
||||||
{
|
{
|
||||||
EventManager.EventBlock* block = first_block;
|
EventManager.EventBlock* block = first_block;
|
||||||
if (block)has_work = true;
|
if (block)
|
||||||
|
has_work = true;
|
||||||
// {
|
// {
|
||||||
// has_work = true;
|
// has_work = true;
|
||||||
// //empty = false;
|
// //empty = false;
|
||||||
|
|
@ -2959,28 +3003,28 @@ export struct EntityManager
|
||||||
void* event_pointer = cast(void*) block + event.data_offset;
|
void* event_pointer = cast(void*) block + event.data_offset;
|
||||||
foreach (j; 0 .. block.count)
|
foreach (j; 0 .. block.count)
|
||||||
{
|
{
|
||||||
call_data.event = event_pointer;
|
call_data.event = event_pointer + EntityID.sizeof;
|
||||||
EntityID entity_id = *cast(EntityID*) event_pointer;
|
EntityID entity_id = *cast(EntityID*)(event_pointer);
|
||||||
Entity* entity = id_manager.getEntityPointer(entity_id);
|
Entity* entity = id_manager.getEntityPointer(entity_id);
|
||||||
if (entity)
|
if (entity)
|
||||||
{
|
{
|
||||||
call_data.block = getMetaData(entity);
|
call_data.block = getMetaData(entity);
|
||||||
call_data.id = call_data.block.entityIndex(entity);
|
call_data.id = call_data.block.entityIndex(entity);
|
||||||
|
call_data.entity = entity;
|
||||||
|
|
||||||
foreach (caller; events[i].callers)
|
foreach (caller; events[i].callers)
|
||||||
{
|
{
|
||||||
if (
|
if (call_data.block.type_info.systems[caller.system.m_id] == false
|
||||||
call_data.block.type_info.systems[caller.system.m_id]
|
|| !caller.system.enabled || !caller.system.willExecute)
|
||||||
== false)
|
|
||||||
continue;
|
continue;
|
||||||
call_data.system_pointer = caller.system.m_system_pointer;
|
call_data.system_pointer = caller.system.m_system_pointer;
|
||||||
(cast(void function(
|
(cast(void function(ref EventCallData) nothrow @nogc) caller
|
||||||
ref EventCallData) nothrow @nogc) caller.callback)(
|
.callback)(call_data);
|
||||||
call_data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(events[i].destroy_callback)events[i].destroy_callback(event_pointer);
|
if (events[i].destroy_callback)
|
||||||
event_pointer += events[i].size;
|
events[i].destroy_callback(event_pointer);
|
||||||
|
event_pointer += events[i].size + EntityID.sizeof;
|
||||||
}
|
}
|
||||||
block = block.next;
|
block = block.next;
|
||||||
}
|
}
|
||||||
|
|
@ -3225,7 +3269,8 @@ export struct EntityManager
|
||||||
const(UpdatePass)* getPass(const(char)[] name)
|
const(UpdatePass)* getPass(const(char)[] name)
|
||||||
{
|
{
|
||||||
ushort id = getPassID(name);
|
ushort id = getPassID(name);
|
||||||
if(id == ushort.max)return null;
|
if (id == ushort.max)
|
||||||
|
return null;
|
||||||
return passes[id];
|
return passes[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3267,6 +3312,7 @@ export struct EntityManager
|
||||||
EntitiesBlock* block;
|
EntitiesBlock* block;
|
||||||
void* system_pointer;
|
void* system_pointer;
|
||||||
void* event;
|
void* event;
|
||||||
|
Entity* entity;
|
||||||
ushort id;
|
ushort id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3357,9 +3403,9 @@ export struct EntityManager
|
||||||
return new_info;
|
return new_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityInfo* getNewInfoRemove(ushort id)
|
EntityInfo* getNewInfoRemove(ushort id) return
|
||||||
{
|
{
|
||||||
if (comp_rem_info.length <= id)
|
/*if (comp_rem_info.length <= id)
|
||||||
{
|
{
|
||||||
EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)(
|
EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)(
|
||||||
instance.components.length, &this);
|
instance.components.length, &this);
|
||||||
|
|
@ -3371,7 +3417,7 @@ export struct EntityManager
|
||||||
Mallocator.dispose(comp_rem_info);
|
Mallocator.dispose(comp_rem_info);
|
||||||
}
|
}
|
||||||
comp_rem_info = new_infos;
|
comp_rem_info = new_infos;
|
||||||
}
|
}*/
|
||||||
if (comp_rem_info[id])
|
if (comp_rem_info[id])
|
||||||
return comp_rem_info[id];
|
return comp_rem_info[id];
|
||||||
|
|
||||||
|
|
@ -3386,8 +3432,9 @@ export struct EntityManager
|
||||||
ids[len++] = comp;
|
ids[len++] = comp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (len == components.length)
|
assert(len != components.length);
|
||||||
return &this;
|
//if (len == components.length)
|
||||||
|
// return &this;
|
||||||
|
|
||||||
assert(len == components.length - 1);
|
assert(len == components.length - 1);
|
||||||
|
|
||||||
|
|
@ -3455,23 +3502,14 @@ export struct EntityManager
|
||||||
*/
|
*/
|
||||||
struct EntitiesBlock
|
struct EntitiesBlock
|
||||||
{
|
{
|
||||||
///return distance (in bytes) from begin of block to data
|
|
||||||
///TODO: probably to remove. It's used by old code if I remeber correctly.
|
|
||||||
/*export uint dataDelta() nothrow @nogc pure
|
|
||||||
{
|
|
||||||
ushort dif = EntitiesBlock.sizeof;
|
|
||||||
alignNum(dif, type_info.alignment);
|
|
||||||
return dif;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
///return pointer to first element in block
|
///return pointer to first element in block
|
||||||
export void* dataBegin() nothrow @nogc pure
|
export void* dataBegin() nothrow @nogc pure return
|
||||||
{
|
{
|
||||||
ushort dif = EntitiesBlock.sizeof;
|
ushort dif = EntitiesBlock.sizeof;
|
||||||
return cast(void*)&this + dif;
|
return cast(void*)&this + dif;
|
||||||
}
|
}
|
||||||
|
|
||||||
export ushort entityIndex(Entity* entity) nothrow @nogc pure
|
export ushort entityIndex(const(Entity)* entity) nothrow @nogc pure
|
||||||
{
|
{
|
||||||
static if (EntityID.sizeof == 8)
|
static if (EntityID.sizeof == 8)
|
||||||
return cast(ushort)((cast(void*) entity - dataBegin()) >> 3);
|
return cast(ushort)((cast(void*) entity - dataBegin()) >> 3);
|
||||||
|
|
@ -3593,32 +3631,32 @@ export struct EntityManager
|
||||||
|
|
||||||
struct ThreadData
|
struct ThreadData
|
||||||
{
|
{
|
||||||
ref Vector!EntityID entitesToRemove() @nogc nothrow
|
ref Vector!EntityID entitesToRemove() @nogc nothrow return
|
||||||
{
|
{
|
||||||
return entities_to_remove[data_index];
|
return entities_to_remove[data_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
ref SimpleVector changeEntitiesList() @nogc nothrow
|
ref SimpleVector changeEntitiesList() @nogc nothrow return
|
||||||
{
|
{
|
||||||
return change_entities_list[data_index];
|
return change_entities_list[data_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
ref Vector!(EntitiesBlock*) blockToUpdate() @nogc nothrow
|
ref Vector!(EntitiesBlock*) blockToUpdate() @nogc nothrow return
|
||||||
{
|
{
|
||||||
return blocks_to_update[data_index];
|
return blocks_to_update[data_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow
|
ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow return
|
||||||
{
|
{
|
||||||
return entities_to_remove[1 - data_index];
|
return entities_to_remove[1 - data_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
ref SimpleVector changeEntitiesListPrev() @nogc nothrow
|
ref SimpleVector changeEntitiesListPrev() @nogc nothrow return
|
||||||
{
|
{
|
||||||
return change_entities_list[1 - data_index];
|
return change_entities_list[1 - data_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
ref Vector!(EntitiesBlock*) blockToUpdatePrev() @nogc nothrow
|
ref Vector!(EntitiesBlock*) blockToUpdatePrev() @nogc nothrow return
|
||||||
{
|
{
|
||||||
return blocks_to_update[1 - data_index];
|
return blocks_to_update[1 - data_index];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,10 @@ struct SimpleVector
|
||||||
{
|
{
|
||||||
while (used >= data.length)
|
while (used >= data.length)
|
||||||
{
|
{
|
||||||
if(data is null)data = Mallocator.makeArray!ubyte(1024);
|
if (data is null)
|
||||||
else data = Mallocator.expandArray(data,data.length);
|
data = Mallocator.makeArray!ubyte(1024);
|
||||||
|
else
|
||||||
|
data = Mallocator.expandArray(data, data.length);
|
||||||
}
|
}
|
||||||
data[used++] = el;
|
data[used++] = el;
|
||||||
}
|
}
|
||||||
|
|
@ -29,8 +31,10 @@ struct SimpleVector
|
||||||
{
|
{
|
||||||
while (used + el.length >= data.length)
|
while (used + el.length >= data.length)
|
||||||
{
|
{
|
||||||
if(data is null)data = Mallocator.makeArray!ubyte(1024);
|
if (data is null)
|
||||||
else data = Mallocator.expandArray(data,data.length);
|
data = Mallocator.makeArray!ubyte(1024);
|
||||||
|
else
|
||||||
|
data = Mallocator.expandArray(data, data.length);
|
||||||
}
|
}
|
||||||
memcpy(data.ptr + used, el.ptr, el.length);
|
memcpy(data.ptr + used, el.ptr, el.length);
|
||||||
used += el.length;
|
used += el.length;
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,19 @@ version(ECSEmscripten)
|
||||||
|
|
||||||
extern (C) int memcmp(const void* s1, const void* s2, size_t size);
|
extern (C) int memcmp(const void* s1, const void* s2, size_t size);
|
||||||
extern (C) void exit(int status) nothrow @nogc;
|
extern (C) void exit(int status) nothrow @nogc;
|
||||||
extern(C) void __assert(const(char)* msg, const(char)* file, uint line) { exit(-20);}
|
extern (C) void __assert(const(char)* msg, const(char)* file, uint line)
|
||||||
|
{
|
||||||
|
exit(-20);
|
||||||
|
}
|
||||||
|
|
||||||
extern (C) void free(void*) @nogc nothrow @system;
|
extern (C) void free(void*) @nogc nothrow @system;
|
||||||
extern (C) void* malloc(size_t size) @nogc nothrow @system;
|
extern (C) void* malloc(size_t size) @nogc nothrow @system;
|
||||||
extern (C) void* realloc(void*, size_t size) @nogc nothrow @system;
|
extern (C) void* realloc(void*, size_t size) @nogc nothrow @system;
|
||||||
extern (C) void* memcpy(return void*, scope const void*, size_t size) @nogc nothrow @system;
|
extern (C) void* memcpy(return void*, scope const void*, size_t size) @nogc nothrow @system;
|
||||||
extern (C) void* memset(void*, int val, size_t size) @nogc nothrow @system;
|
extern (C) void* memset(void*, int val, size_t size) @nogc nothrow @system;
|
||||||
extern (C) int posix_memalign(void**, size_t, size_t) @nogc nothrow @system;
|
extern (C) int posix_memalign(void**, size_t, size_t) @nogc nothrow @system;
|
||||||
extern(C) void qsort(void* base, size_t num, size_t size, int function(const void*,const void*) compar) @nogc nothrow @system;
|
extern (C) void qsort(void* base, size_t num, size_t size,
|
||||||
|
int function(const void*, const void*) compar) @nogc nothrow @system;
|
||||||
|
|
||||||
extern (C) int pthread_mutex_lock(pthread_mutex_t* mutex) @nogc nothrow;
|
extern (C) int pthread_mutex_lock(pthread_mutex_t* mutex) @nogc nothrow;
|
||||||
extern (C) int pthread_mutex_trylock(pthread_mutex_t* mutex) @nogc nothrow;
|
extern (C) int pthread_mutex_trylock(pthread_mutex_t* mutex) @nogc nothrow;
|
||||||
|
|
@ -61,6 +66,7 @@ version(ECSEmscripten)
|
||||||
else version (Windows)
|
else version (Windows)
|
||||||
{
|
{
|
||||||
import core.sys.windows.windows;
|
import core.sys.windows.windows;
|
||||||
|
|
||||||
extern (Windows) void* _aligned_malloc(size_t size, size_t alignment) @nogc nothrow @system;
|
extern (Windows) void* _aligned_malloc(size_t size, size_t alignment) @nogc nothrow @system;
|
||||||
extern (Windows) void _aligned_free(void* ptr) @nogc nothrow @system;
|
extern (Windows) void _aligned_free(void* ptr) @nogc nothrow @system;
|
||||||
|
|
||||||
|
|
@ -80,7 +86,7 @@ else version (Windows)
|
||||||
else version (Posix)
|
else version (Posix)
|
||||||
{
|
{
|
||||||
import core.sys.posix.pthread;
|
import core.sys.posix.pthread;
|
||||||
import core.sys.posix.stdlib;
|
import core.sys.posix.stdlib : posix_memalign;
|
||||||
}
|
}
|
||||||
|
|
||||||
version (ECSEmscripten)
|
version (ECSEmscripten)
|
||||||
|
|
@ -90,7 +96,8 @@ version(ECSEmscripten)
|
||||||
private __gshared uint alloca_pos = 0;
|
private __gshared uint alloca_pos = 0;
|
||||||
export extern (C) void* alloca(size_t length) @nogc nothrow
|
export extern (C) void* alloca(size_t length) @nogc nothrow
|
||||||
{
|
{
|
||||||
if(alloca_pos + length > max_alloca)alloca_pos = 0;
|
if (alloca_pos + length > max_alloca)
|
||||||
|
alloca_pos = 0;
|
||||||
void* ret = &alloca_array[alloca_pos];
|
void* ret = &alloca_array[alloca_pos];
|
||||||
alloca_pos += length;
|
alloca_pos += length;
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -106,14 +113,30 @@ else version(D_BetterC)
|
||||||
private const uint max_alloca = 10000;
|
private const uint max_alloca = 10000;
|
||||||
private __gshared byte[max_alloca] alloca_array;
|
private __gshared byte[max_alloca] alloca_array;
|
||||||
private uint alloca_pos = 0;
|
private uint alloca_pos = 0;
|
||||||
export extern(C) void* alloca(size_t length) @nogc nothrow
|
export extern (C) void* __alloca(size_t length) @nogc nothrow
|
||||||
{
|
{
|
||||||
if(alloca_pos + length > max_alloca)alloca_pos = 0;
|
if (alloca_pos + length > max_alloca)
|
||||||
|
alloca_pos = 0;
|
||||||
void* ret = &alloca_array[alloca_pos];
|
void* ret = &alloca_array[alloca_pos];
|
||||||
alloca_pos += length;
|
alloca_pos += length;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alias alloca = __alloca;
|
||||||
|
|
||||||
|
version (DigitalMars)
|
||||||
|
{
|
||||||
|
export extern (C) float* _memsetFloat(float* p, float value, size_t count) @nogc nothrow
|
||||||
|
{
|
||||||
|
float* pstart = p;
|
||||||
|
float* ptop;
|
||||||
|
|
||||||
|
for (ptop = &p[count]; p < ptop; p++)
|
||||||
|
*p = value;
|
||||||
|
return pstart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
version (GNU)
|
version (GNU)
|
||||||
{
|
{
|
||||||
extern (C) void __gdc_personality_v0()
|
extern (C) void __gdc_personality_v0()
|
||||||
|
|
@ -145,6 +168,7 @@ static struct Mallocator
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
static import std.conv;
|
static import std.conv;
|
||||||
|
|
||||||
foreach (i; 0 .. ret.length)
|
foreach (i; 0 .. ret.length)
|
||||||
{
|
{
|
||||||
std.conv.emplace(&ret[i]);
|
std.conv.emplace(&ret[i]);
|
||||||
|
|
@ -156,7 +180,8 @@ static struct Mallocator
|
||||||
static T[] makeArray(T)(size_t length, T initializer) nothrow @nogc
|
static T[] makeArray(T)(size_t length, T initializer) nothrow @nogc
|
||||||
{
|
{
|
||||||
T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length];
|
T[] ret = (cast(T*) malloc(T.sizeof * length))[0 .. length];
|
||||||
foreach(ref v; ret)v = initializer;
|
foreach (ref v; ret)
|
||||||
|
v = initializer;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,7 +194,8 @@ static struct Mallocator
|
||||||
static T[] makeArray(T)(T[] array) nothrow @nogc
|
static T[] makeArray(T)(T[] array) nothrow @nogc
|
||||||
{
|
{
|
||||||
T[] ret = (cast(T*) malloc(T.sizeof * array.length))[0 .. array.length]; //Mallocator.makeArray!(T)(array.length);
|
T[] ret = (cast(T*) malloc(T.sizeof * array.length))[0 .. array.length]; //Mallocator.makeArray!(T)(array.length);
|
||||||
foreach(i, ref v;ret)v = array[i];
|
foreach (i, ref v; ret)
|
||||||
|
v = array[i];
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,40 +203,54 @@ static struct Mallocator
|
||||||
{
|
{
|
||||||
T* ret = cast(T*) malloc(T.sizeof);
|
T* ret = cast(T*) malloc(T.sizeof);
|
||||||
static import std.conv;
|
static import std.conv;
|
||||||
|
|
||||||
static if (__traits(isPOD, T))
|
static if (__traits(isPOD, T))
|
||||||
{
|
{
|
||||||
static immutable T init = T.init;
|
static immutable T init = T.init;
|
||||||
memcpy(ret, &init, T.sizeof);
|
memcpy(ret, &init, T.sizeof);
|
||||||
}
|
}
|
||||||
else static if(is(T == struct))std.conv.emplace(ret, args);
|
else static if (is(T == struct))
|
||||||
|
std.conv.emplace(ret, args);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* alignAlloc(size_t length, size_t alignment) nothrow @nogc
|
static void* alignAlloc(size_t length, size_t alignment) nothrow @nogc
|
||||||
{
|
{
|
||||||
void* ret;
|
void* ret;
|
||||||
version(Posix)posix_memalign(&ret, alignment, length);//ret = aligned_alloc(alignment, length);
|
version (Posix)
|
||||||
else version(Windows)ret = _aligned_malloc(length, alignment);
|
posix_memalign(&ret, alignment, length); //ret = aligned_alloc(alignment, length);
|
||||||
else version(ECSEmscripten)posix_memalign(&ret, alignment, length);//malloc(length);
|
else version (Windows)
|
||||||
else static assert(0, "Unimplemented platform!");
|
ret = _aligned_malloc(length, alignment);
|
||||||
|
else version (ECSEmscripten)
|
||||||
|
posix_memalign(&ret, alignment, length); //malloc(length);
|
||||||
|
else
|
||||||
|
static assert(0, "Unimplemented platform!");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispose(T)(T object) nothrow @nogc
|
static void dispose(T)(T object) nothrow @nogc
|
||||||
{
|
{
|
||||||
static if(__traits(hasMember, T, "__xdtor"))object.__xdtor();
|
static if (__traits(hasMember, T, "__xdtor"))
|
||||||
else static if(__traits(hasMember, T, "__dtor"))object.__dtor();
|
object.__xdtor();
|
||||||
|
else static if (__traits(hasMember, T, "__dtor"))
|
||||||
|
object.__dtor();
|
||||||
free(cast(void*) object);
|
free(cast(void*) object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alignDispose(T)(T object)
|
static void alignDispose(T)(T object)
|
||||||
{
|
{
|
||||||
static if(__traits(hasMember, T, "__xdtor"))object.__xdtor();
|
static if (__traits(hasMember, T, "__xdtor"))
|
||||||
else static if(__traits(hasMember, T, "__dtor"))object.__dtor();
|
object.__xdtor();
|
||||||
version(Posix)free(cast(void*)object);
|
else static if (__traits(hasMember, T, "__dtor"))
|
||||||
else version(Windows)_aligned_free(cast(void*)object);
|
object.__dtor();
|
||||||
else version(ECSEmscripten)free(cast(void*)object);
|
version (Posix)
|
||||||
else static assert(0, "Unimplemented platform!");
|
free(cast(void*) object);
|
||||||
|
else version (Windows)
|
||||||
|
_aligned_free(cast(void*) object);
|
||||||
|
else version (ECSEmscripten)
|
||||||
|
free(cast(void*) object);
|
||||||
|
else
|
||||||
|
static assert(0, "Unimplemented platform!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -318,5 +358,6 @@ struct Mutex
|
||||||
|
|
||||||
private pthread_mutex_t m_handle;
|
private pthread_mutex_t m_handle;
|
||||||
}
|
}
|
||||||
else static assert(0, "unsupported platform!");
|
else
|
||||||
|
static assert(0, "unsupported platform!");
|
||||||
}
|
}
|
||||||
|
|
@ -1,30 +1,36 @@
|
||||||
module bubel.ecs.vector;
|
module bubel.ecs.vector;
|
||||||
|
|
||||||
import core.bitop;
|
import core.bitop;
|
||||||
|
|
||||||
//import core.stdc.stdlib : free, malloc;
|
//import core.stdc.stdlib : free, malloc;
|
||||||
import bubel.ecs.std;
|
import bubel.ecs.std;
|
||||||
|
|
||||||
//import core.stdc.string : memcpy, memset;
|
//import core.stdc.string : memcpy, memset;
|
||||||
//import std.algorithm : swap;
|
//import std.algorithm : swap;
|
||||||
import std.conv : emplace;
|
import std.conv : emplace;
|
||||||
import std.traits : hasMember, isCopyable, TemplateOf, Unqual;
|
import std.traits : hasMember, isCopyable, TemplateOf, Unqual;
|
||||||
|
|
||||||
export @nogc @safe nothrow pure size_t nextPow2(size_t num) {
|
export @nogc @safe nothrow pure size_t nextPow2(size_t num)
|
||||||
|
{
|
||||||
return 1 << bsr(num) + 1;
|
return 1 << bsr(num) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export __gshared size_t gVectorsCreated = 0;
|
export __gshared size_t gVectorsCreated = 0;
|
||||||
export __gshared size_t gVectorsDestroyed = 0;
|
export __gshared size_t gVectorsDestroyed = 0;
|
||||||
|
|
||||||
struct Vector(T) {
|
struct Vector(T)
|
||||||
|
{
|
||||||
T[] array;
|
T[] array;
|
||||||
size_t used;
|
size_t used;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
export this()(T t) {
|
export this()(T t)
|
||||||
|
{
|
||||||
add(t);
|
add(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
export this(X)(X[] t) if (is(Unqual!X == Unqual!T)) {
|
export this(X)(X[] t) if (is(Unqual!X == Unqual!T))
|
||||||
|
{
|
||||||
add(t);
|
add(t);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -42,16 +48,20 @@ public:
|
||||||
|
|
||||||
@disable this(this);
|
@disable this(this);
|
||||||
|
|
||||||
export ~this() {
|
export ~this()
|
||||||
|
{
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
export void clear() {
|
export void clear()
|
||||||
|
{
|
||||||
removeAll();
|
removeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}*/
|
}*/
|
||||||
|
|
@ -63,58 +73,76 @@ public:
|
||||||
used = 0;
|
used = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool empty() const {
|
export bool empty() const
|
||||||
|
{
|
||||||
return (used == 0);
|
return (used == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export size_t length() const {
|
export size_t length() const
|
||||||
|
{
|
||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void length(size_t newLength) {
|
export void length(size_t newLength)
|
||||||
if (newLength > used) {
|
{
|
||||||
|
if (newLength > used)
|
||||||
|
{
|
||||||
reserve(newLength);
|
reserve(newLength);
|
||||||
foreach (ref el; array[used .. newLength]) {
|
foreach (ref el; array[used .. newLength])
|
||||||
|
{
|
||||||
emplace(&el);
|
emplace(&el);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
foreach (ref el; array[newLength .. used]) {
|
else
|
||||||
|
{
|
||||||
|
foreach (ref el; array[newLength .. used])
|
||||||
|
{
|
||||||
//destroy(el);
|
//destroy(el);
|
||||||
static if(__traits(hasMember, T, "__xdtor"))el.__xdtor();
|
static if (__traits(hasMember, T, "__xdtor"))
|
||||||
else static if(__traits(hasMember, T, "__dtor"))el.__dtor();
|
el.__xdtor();
|
||||||
|
else static if (__traits(hasMember, T, "__dtor"))
|
||||||
|
el.__dtor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
used = newLength;
|
used = newLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void reset() {
|
export void reset()
|
||||||
|
{
|
||||||
used = 0;
|
used = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void reserve(size_t numElements) {
|
export void reserve(size_t numElements)
|
||||||
if (numElements > array.length) {
|
{
|
||||||
|
if (numElements > array.length)
|
||||||
|
{
|
||||||
extend(numElements);
|
extend(numElements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export size_t capacity() {
|
export size_t capacity()
|
||||||
|
{
|
||||||
return array.length - used;
|
return array.length - used;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void extend(size_t newNumOfElements) {
|
export void extend(size_t newNumOfElements)
|
||||||
|
{
|
||||||
auto oldArray = manualExtend(array, newNumOfElements);
|
auto oldArray = manualExtend(array, newNumOfElements);
|
||||||
if (oldArray !is null) {
|
if (oldArray !is null)
|
||||||
|
{
|
||||||
freeData(oldArray);
|
freeData(oldArray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export @nogc void freeData(void[] data) {
|
export @nogc void freeData(void[] data)
|
||||||
|
{
|
||||||
// 0x0F probably invalid value for pointers and other types
|
// 0x0F probably invalid value for pointers and other types
|
||||||
memset(data.ptr, 0x0F, data.length); // Makes bugs show up xD
|
memset(data.ptr, 0x0F, data.length); // Makes bugs show up xD
|
||||||
free(data.ptr);
|
free(data.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
export static void[] manualExtend(ref T[] array, size_t newNumOfElements = 0) {
|
export static void[] manualExtend(ref T[] array, size_t newNumOfElements = 0)
|
||||||
|
{
|
||||||
if (newNumOfElements == 0)
|
if (newNumOfElements == 0)
|
||||||
newNumOfElements = 2;
|
newNumOfElements = 2;
|
||||||
if (array.length == 0)
|
if (array.length == 0)
|
||||||
|
|
@ -129,19 +157,23 @@ public:
|
||||||
return (cast(void*) oldArray.ptr)[0 .. oldArray.length * T.sizeof];
|
return (cast(void*) oldArray.ptr)[0 .. oldArray.length * T.sizeof];
|
||||||
}
|
}
|
||||||
|
|
||||||
export Vector!T copy()() {
|
export Vector!T copy()()
|
||||||
|
{
|
||||||
Vector!T duplicate;
|
Vector!T duplicate;
|
||||||
duplicate.reserve(used);
|
duplicate.reserve(used);
|
||||||
duplicate ~= array[0 .. used];
|
duplicate ~= array[0 .. used];
|
||||||
return duplicate;
|
return duplicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool canAddWithoutRealloc(uint elemNum = 1) {
|
export bool canAddWithoutRealloc(uint elemNum = 1)
|
||||||
|
{
|
||||||
return used + elemNum <= array.length;
|
return used + elemNum <= array.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void add()(T t) {
|
export void add()(T t)
|
||||||
if (used >= array.length) {
|
{
|
||||||
|
if (used >= array.length)
|
||||||
|
{
|
||||||
extend(nextPow2(used + 1));
|
extend(nextPow2(used + 1));
|
||||||
}
|
}
|
||||||
emplace(&array[used], t);
|
emplace(&array[used], t);
|
||||||
|
|
@ -149,12 +181,15 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add element at given position moving others
|
/// Add element at given position moving others
|
||||||
export void add()(T t, size_t pos) {
|
export void add()(T t, size_t pos)
|
||||||
|
{
|
||||||
assert(pos <= used);
|
assert(pos <= used);
|
||||||
if (used >= array.length) {
|
if (used >= array.length)
|
||||||
|
{
|
||||||
extend(array.length * 2);
|
extend(array.length * 2);
|
||||||
}
|
}
|
||||||
foreach_reverse (size_t i; pos .. used) {
|
foreach_reverse (size_t i; pos .. used)
|
||||||
|
{
|
||||||
//swap(array[i + 1], array[i]);
|
//swap(array[i + 1], array[i]);
|
||||||
array[i + 1] = array[i];
|
array[i + 1] = array[i];
|
||||||
}
|
}
|
||||||
|
|
@ -162,35 +197,46 @@ public:
|
||||||
used++;
|
used++;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void add(X)(X[] t) if (is(Unqual!X == Unqual!T)) {
|
export void add(X)(X[] t) if (is(Unqual!X == Unqual!T))
|
||||||
if (used + t.length > array.length) {
|
{
|
||||||
|
if (used + t.length > array.length)
|
||||||
|
{
|
||||||
extend(nextPow2(used + t.length));
|
extend(nextPow2(used + t.length));
|
||||||
}
|
}
|
||||||
foreach (i; 0 .. t.length) {
|
foreach (i; 0 .. t.length)
|
||||||
|
{
|
||||||
emplace(&array[used + i], t[i]);
|
emplace(&array[used + i], t[i]);
|
||||||
}
|
}
|
||||||
used += t.length;
|
used += t.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void remove(size_t elemNum) {
|
export void remove(size_t elemNum)
|
||||||
|
{
|
||||||
//destroy(array[elemNum]);
|
//destroy(array[elemNum]);
|
||||||
static if(__traits(hasMember, T, "__xdtor"))array[elemNum].__xdtor();
|
static if (__traits(hasMember, T, "__xdtor"))
|
||||||
else static if(__traits(hasMember, T, "__dtor"))array[elemNum].__dtor();
|
array[elemNum].__xdtor();
|
||||||
|
else static if (__traits(hasMember, T, "__dtor"))
|
||||||
|
array[elemNum].__dtor();
|
||||||
//swap(array[elemNum], array[used - 1]);
|
//swap(array[elemNum], array[used - 1]);
|
||||||
array[elemNum] = array[used - 1];
|
array[elemNum] = array[used - 1];
|
||||||
used--;
|
used--;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void removeStable()(size_t elemNum) {
|
export void removeStable()(size_t elemNum)
|
||||||
|
{
|
||||||
used--;
|
used--;
|
||||||
foreach (i; 0 .. used) {
|
foreach (i; 0 .. used)
|
||||||
|
{
|
||||||
array[i] = array[i + 1];
|
array[i] = array[i + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool tryRemoveElement()(T elem) {
|
export bool tryRemoveElement()(T elem)
|
||||||
foreach (i, ref el; array[0 .. used]) {
|
{
|
||||||
if (el == elem) {
|
foreach (i, ref el; array[0 .. used])
|
||||||
|
{
|
||||||
|
if (el == elem)
|
||||||
|
{
|
||||||
remove(i);
|
remove(i);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -198,55 +244,66 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void removeElement()(T elem) {
|
export void removeElement()(T elem)
|
||||||
|
{
|
||||||
bool ok = tryRemoveElement(elem);
|
bool ok = tryRemoveElement(elem);
|
||||||
assert(ok, "There is no such an element in vector");
|
assert(ok, "There is no such an element in vector");
|
||||||
}
|
}
|
||||||
|
|
||||||
export ref T opIndex(size_t elemNum) const {
|
export ref T opIndex(size_t elemNum) const
|
||||||
|
{
|
||||||
//debug assert(elemNum < used, "Range violation [index]");
|
//debug assert(elemNum < used, "Range violation [index]");
|
||||||
return *cast(T*)&array.ptr[elemNum];
|
return *cast(T*)&array.ptr[elemNum];
|
||||||
}
|
}
|
||||||
|
|
||||||
export auto opSlice() {
|
export auto opSlice()
|
||||||
|
{
|
||||||
return array.ptr[0 .. used];
|
return array.ptr[0 .. used];
|
||||||
}
|
}
|
||||||
|
|
||||||
export T[] opSlice(size_t x, size_t y) {
|
export T[] opSlice(size_t x, size_t y)
|
||||||
|
{
|
||||||
assert(y <= used);
|
assert(y <= used);
|
||||||
return array.ptr[x .. y];
|
return array.ptr[x .. y];
|
||||||
}
|
}
|
||||||
|
|
||||||
export size_t opDollar() {
|
export size_t opDollar()
|
||||||
|
{
|
||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void opAssign(X)(X[] slice) {
|
export void opAssign(X)(X[] slice)
|
||||||
|
{
|
||||||
reset();
|
reset();
|
||||||
this ~= slice;
|
this ~= slice;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void opOpAssign(string op)(T obj) {
|
export void opOpAssign(string op)(T obj)
|
||||||
|
{
|
||||||
//static assert(op == "~");
|
//static assert(op == "~");
|
||||||
add(obj);
|
add(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
export void opOpAssign(string op, X)(X[] obj) {
|
export void opOpAssign(string op, X)(X[] obj)
|
||||||
|
{
|
||||||
//static assert(op == "~");
|
//static assert(op == "~");
|
||||||
add(obj);
|
add(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
export void opIndexAssign()(T obj, size_t elemNum) {
|
export void opIndexAssign()(T obj, size_t elemNum)
|
||||||
|
{
|
||||||
assert(elemNum < used, "Range viloation");
|
assert(elemNum < used, "Range viloation");
|
||||||
array[elemNum] = obj;
|
array[elemNum] = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void opSliceAssign()(T[] obj, size_t a, size_t b) {
|
export void opSliceAssign()(T[] obj, size_t a, size_t b)
|
||||||
|
{
|
||||||
assert(b <= used && a <= b, "Range viloation");
|
assert(b <= used && a <= b, "Range viloation");
|
||||||
array.ptr[a .. b] = obj;
|
array.ptr[a .. b] = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool opEquals()(auto ref const Vector!(T) r) const {
|
export bool opEquals()(auto ref const Vector!(T) r) const
|
||||||
|
{
|
||||||
return used == r.used && array.ptr[0 .. used] == r.array.ptr[0 .. r.used];
|
return used == r.used && array.ptr[0 .. used] == r.array.ptr[0 .. r.used];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
153
tests/basic.d
153
tests/basic.d
|
|
@ -68,6 +68,11 @@ struct CUnregistered
|
||||||
short value = 12;
|
short value = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CFlag
|
||||||
|
{
|
||||||
|
mixin ECS.Component;
|
||||||
|
}
|
||||||
|
|
||||||
struct LongAddSystem
|
struct LongAddSystem
|
||||||
{
|
{
|
||||||
mixin ECS.System;
|
mixin ECS.System;
|
||||||
|
|
@ -110,6 +115,7 @@ struct EmptySystem
|
||||||
|
|
||||||
void beforeEveryTest()
|
void beforeEveryTest()
|
||||||
{
|
{
|
||||||
|
CUnregistered.component_id = ushort.max;
|
||||||
gEM.initialize(0);
|
gEM.initialize(0);
|
||||||
|
|
||||||
gEM.beginRegister();
|
gEM.beginRegister();
|
||||||
|
|
@ -119,6 +125,7 @@ void beforeEveryTest()
|
||||||
gEM.registerComponent!CDouble;
|
gEM.registerComponent!CDouble;
|
||||||
gEM.registerComponent!CLong;
|
gEM.registerComponent!CLong;
|
||||||
gEM.registerComponent!CShort;
|
gEM.registerComponent!CShort;
|
||||||
|
gEM.registerComponent!CFlag;
|
||||||
|
|
||||||
gEM.endRegister();
|
gEM.endRegister();
|
||||||
}
|
}
|
||||||
|
|
@ -131,11 +138,12 @@ void afterEveryTest()
|
||||||
@("AddEntity")
|
@("AddEntity")
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
ushort[2] ids = [CInt.component_id, CFloat.component_id];
|
EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray);
|
||||||
EntityTemplate* tmpl_ = gEM.allocateTemplate(ids);
|
assert(tmpl_.info.components.length == 3);
|
||||||
assert(tmpl_.info.components.length == 2);
|
assert(tmpl_.info.size == (CInt.sizeof + CFloat.sizeof + EntityID.sizeof));
|
||||||
assert(tmpl_.getComponent!CInt);
|
assert(tmpl_.getComponent!CInt);
|
||||||
assert(tmpl_.getComponent!CFloat);
|
assert(tmpl_.getComponent!CFloat);
|
||||||
|
assert(tmpl_.getComponent!CFlag);
|
||||||
assert(!tmpl_.getComponent!CLong);
|
assert(!tmpl_.getComponent!CLong);
|
||||||
assert(!tmpl_.getComponent!CUnregistered);
|
assert(!tmpl_.getComponent!CUnregistered);
|
||||||
assert(*tmpl_.getComponent!CInt == 1);
|
assert(*tmpl_.getComponent!CInt == 1);
|
||||||
|
|
@ -154,13 +162,66 @@ unittest
|
||||||
assert(*entity2.getComponent!CInt == 2);
|
assert(*entity2.getComponent!CInt == 2);
|
||||||
assert(*entity2.getComponent!CFloat == 2.0);
|
assert(*entity2.getComponent!CFloat == 2.0);
|
||||||
|
|
||||||
CInt cint = CInt(10);
|
//CInt cint = CInt(10);
|
||||||
CLong clong;
|
//CLong clong;
|
||||||
Entity* entity3 = gEM.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray);
|
//Entity* entity3 = gEM.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray);
|
||||||
|
Entity* entity3 = gEM.addEntity(tmpl_, [CInt(10).ref_, CLong().ref_, CFlag().ref_].staticArray);
|
||||||
|
EntityID id = entity3.id;
|
||||||
assert(entity3.getComponent!CInt);
|
assert(entity3.getComponent!CInt);
|
||||||
assert(entity3.getComponent!CFloat);
|
assert(entity3.getComponent!CFloat);
|
||||||
assert(*entity3.getComponent!CInt == 10);
|
assert(*entity3.getComponent!CInt == 10);
|
||||||
assert(*entity3.getComponent!CFloat == 2.0);
|
assert(*entity3.getComponent!CFloat == 2.0);
|
||||||
|
|
||||||
|
gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_]);
|
||||||
|
gEM.commit();
|
||||||
|
entity3 = gEM.getEntity(id);
|
||||||
|
assert(entity3.getComponent!CInt);
|
||||||
|
assert(entity3.getComponent!CFloat);
|
||||||
|
assert(entity3.getComponent!CFlag);
|
||||||
|
assert(entity3.getComponent!CShort);
|
||||||
|
assert(*entity3.getComponent!CInt == 10);
|
||||||
|
assert(*entity3.getComponent!CFloat == 2.0);
|
||||||
|
assert(*entity3.getComponent!CShort == 2);
|
||||||
|
|
||||||
|
gEM.removeComponents(entity3.id, [CFlag().component_id,CShort(2).component_id]);
|
||||||
|
gEM.commit();
|
||||||
|
entity3 = gEM.getEntity(id);
|
||||||
|
assert(entity3.getComponent!CInt);
|
||||||
|
assert(entity3.getComponent!CFloat);
|
||||||
|
assert(!entity3.getComponent!CFlag);
|
||||||
|
assert(!entity3.getComponent!CShort);
|
||||||
|
assert(*entity3.getComponent!CInt == 10);
|
||||||
|
assert(*entity3.getComponent!CFloat == 2.0);
|
||||||
|
|
||||||
|
gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_]);
|
||||||
|
gEM.removeComponents(entity3.id, [CUnregistered.component_id]);
|
||||||
|
gEM.commit();
|
||||||
|
entity3 = gEM.getEntity(id);
|
||||||
|
assert(entity3.getComponent!CInt);
|
||||||
|
assert(entity3.getComponent!CFloat);
|
||||||
|
assert(entity3.getComponent!CFlag);
|
||||||
|
assert(entity3.getComponent!CShort);
|
||||||
|
assert(*entity3.getComponent!CInt == 10);
|
||||||
|
assert(*entity3.getComponent!CFloat == 2.0);
|
||||||
|
assert(*entity3.getComponent!CShort == 2);
|
||||||
|
|
||||||
|
gEM.beginRegister();
|
||||||
|
|
||||||
|
gEM.registerComponent!CUnregistered;
|
||||||
|
|
||||||
|
gEM.endRegister();
|
||||||
|
|
||||||
|
gEM.addComponents(entity3.id, [CUnregistered(4).ref_]);
|
||||||
|
gEM.commit();
|
||||||
|
entity3 = gEM.getEntity(id);
|
||||||
|
assert(entity3.getComponent!CUnregistered);
|
||||||
|
assert(*entity3.getComponent!CUnregistered == 4);
|
||||||
|
|
||||||
|
gEM.removeComponents(entity3.id, [CUnregistered.component_id]);
|
||||||
|
gEM.commit();
|
||||||
|
entity3 = gEM.getEntity(id);
|
||||||
|
assert(!entity3.getComponent!CUnregistered);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//allocate templates
|
//allocate templates
|
||||||
|
|
@ -171,32 +232,48 @@ unittest
|
||||||
ushort[2] ids = [CInt.component_id, CFloat.component_id];
|
ushort[2] ids = [CInt.component_id, CFloat.component_id];
|
||||||
EntityTemplate* tmpl_ = gEM.allocateTemplate(ids);
|
EntityTemplate* tmpl_ = gEM.allocateTemplate(ids);
|
||||||
EntityTemplate* tmpl_d = gEM.allocateTemplate([CFloat.component_id, CInt.component_id, CFloat.component_id].staticArray);
|
EntityTemplate* tmpl_d = gEM.allocateTemplate([CFloat.component_id, CInt.component_id, CFloat.component_id].staticArray);
|
||||||
|
EntityTemplate* tmpl_cp = gEM.allocateTemplate(tmpl_);
|
||||||
assert(tmpl_d.info == tmpl_.info);
|
assert(tmpl_d.info == tmpl_.info);
|
||||||
|
assert(tmpl_cp.info == tmpl_cp.info);
|
||||||
assert(tmpl_.info.components.length == 2);
|
assert(tmpl_.info.components.length == 2);
|
||||||
assert(tmpl_.getComponent!CInt);
|
assert(tmpl_.getComponent!CInt);
|
||||||
assert(tmpl_.getComponent!CFloat);
|
assert(tmpl_.getComponent!CFloat);
|
||||||
assert(*tmpl_.getComponent!CInt == 1);
|
assert(*tmpl_.getComponent!CInt == 1);
|
||||||
assert(*tmpl_.getComponent!CFloat == 2.0);
|
assert(*tmpl_.getComponent!CFloat == 2.0);
|
||||||
|
assert(tmpl_cp.getComponent!CFloat);
|
||||||
|
assert(tmpl_cp.getComponent!CInt);
|
||||||
|
assert(tmpl_.getComponent!CInt != tmpl_cp.getComponent!CInt);
|
||||||
|
assert(tmpl_.getComponent!CFloat != tmpl_cp.getComponent!CFloat);
|
||||||
|
assert(*tmpl_.getComponent!CInt == *tmpl_cp.getComponent!CInt);
|
||||||
|
assert(*tmpl_.getComponent!CFloat == *tmpl_cp.getComponent!CFloat);
|
||||||
*tmpl_.getComponent!CInt = 4;
|
*tmpl_.getComponent!CInt = 4;
|
||||||
*tmpl_.getComponent!CFloat = 5.0;
|
*tmpl_.getComponent!CFloat = 5.0;
|
||||||
|
|
||||||
//allocate template from template with additional component
|
//allocate template from template with additional components
|
||||||
ushort[1] ids2 = [CDouble.component_id];
|
ushort[2] ids2 = [CDouble.component_id,CFlag.component_id];
|
||||||
EntityTemplate* tmpl_2 = gEM.allocateTemplate(tmpl_, ids2);
|
EntityTemplate* tmpl_2 = gEM.allocateTemplate(tmpl_, ids2);
|
||||||
assert(tmpl_2.info.components.length == 3);
|
assert(tmpl_2.info.components.length == 4);
|
||||||
assert(tmpl_2.getComponent!CInt);
|
assert(tmpl_2.getComponent!CInt);
|
||||||
assert(tmpl_2.getComponent!CFloat);
|
assert(tmpl_2.getComponent!CFloat);
|
||||||
assert(tmpl_2.getComponent!CDouble);
|
assert(tmpl_2.getComponent!CDouble);
|
||||||
|
assert(tmpl_2.getComponent!CFlag);
|
||||||
assert(*tmpl_2.getComponent!CInt == 4);
|
assert(*tmpl_2.getComponent!CInt == 4);
|
||||||
assert(*tmpl_2.getComponent!CFloat == 5.0);
|
assert(*tmpl_2.getComponent!CFloat == 5.0);
|
||||||
assert(*tmpl_2.getComponent!CDouble == 3.0);
|
assert(*tmpl_2.getComponent!CDouble == 3.0);
|
||||||
|
|
||||||
|
assert(tmpl_.info.blocksCount() == 0);
|
||||||
|
|
||||||
Entity* entity = gEM.addEntity(tmpl_);
|
Entity* entity = gEM.addEntity(tmpl_);
|
||||||
gEM.addComponents(entity.id, CDouble(8.0));
|
gEM.addComponents(entity.id, CFloat(100));
|
||||||
|
gEM.addComponents(entity.id, CDouble(8.0), CFloat(100));
|
||||||
|
|
||||||
|
assert(tmpl_.info.blocksCount() == 1);
|
||||||
|
|
||||||
//apply entity changes
|
//apply entity changes
|
||||||
gEM.commit();
|
gEM.commit();
|
||||||
|
|
||||||
|
assert(tmpl_.info.blocksCount() == 0);
|
||||||
|
|
||||||
//allocate template as entity copy
|
//allocate template as entity copy
|
||||||
EntityTemplate* tmpl_3 = gEM.allocateTemplate(entity.id);
|
EntityTemplate* tmpl_3 = gEM.allocateTemplate(entity.id);
|
||||||
assert(tmpl_3.info.components.length == 3);
|
assert(tmpl_3.info.components.length == 3);
|
||||||
|
|
@ -217,18 +294,20 @@ unittest
|
||||||
assert(*tmpl_4.getComponent!CFloat == 2.0);
|
assert(*tmpl_4.getComponent!CFloat == 2.0);
|
||||||
assert(*tmpl_4.getComponent!CDouble == 3.0);
|
assert(*tmpl_4.getComponent!CDouble == 3.0);
|
||||||
|
|
||||||
//allocate template from template with two additional component
|
//allocate template from template with three additional component
|
||||||
ushort[2] ids3 = [CDouble.component_id, CLong.component_id];
|
ushort[3] ids3 = [CDouble.component_id, CLong.component_id, CShort.component_id];
|
||||||
EntityTemplate* tmpl_5 = gEM.allocateTemplate(tmpl_, ids3);
|
EntityTemplate* tmpl_5 = gEM.allocateTemplate(tmpl_2, ids3);
|
||||||
assert(tmpl_5.info.components.length == 4);
|
assert(tmpl_5.info.components.length == 6);
|
||||||
assert(tmpl_5.getComponent!CInt);
|
assert(tmpl_5.getComponent!CInt);
|
||||||
assert(tmpl_5.getComponent!CFloat);
|
assert(tmpl_5.getComponent!CFloat);
|
||||||
assert(tmpl_5.getComponent!CDouble);
|
assert(tmpl_5.getComponent!CDouble);
|
||||||
assert(tmpl_5.getComponent!CLong);
|
assert(tmpl_5.getComponent!CLong);
|
||||||
|
assert(tmpl_5.getComponent!CShort);
|
||||||
assert(*tmpl_5.getComponent!CInt == 4);
|
assert(*tmpl_5.getComponent!CInt == 4);
|
||||||
assert(*tmpl_5.getComponent!CFloat == 5.0);
|
assert(*tmpl_5.getComponent!CFloat == 5.0);
|
||||||
assert(*tmpl_5.getComponent!CDouble == 3.0);
|
assert(*tmpl_5.getComponent!CDouble == 3.0);
|
||||||
assert(*tmpl_5.getComponent!CLong == 10);
|
assert(*tmpl_5.getComponent!CLong == 10);
|
||||||
|
assert(*tmpl_5.getComponent!CShort == 12);
|
||||||
|
|
||||||
//allocate template from template without one component
|
//allocate template from template without one component
|
||||||
ushort[1] rem_ids = [CFloat.component_id];
|
ushort[1] rem_ids = [CFloat.component_id];
|
||||||
|
|
@ -239,7 +318,7 @@ unittest
|
||||||
|
|
||||||
//allocate template from template without one component and two additional
|
//allocate template from template without one component and two additional
|
||||||
EntityTemplate* tmpl_7 = gEM.allocateTemplate(tmpl_, ids3, rem_ids);
|
EntityTemplate* tmpl_7 = gEM.allocateTemplate(tmpl_, ids3, rem_ids);
|
||||||
assert(tmpl_7.info.components.length == 3);
|
assert(tmpl_7.info.components.length == 4);
|
||||||
assert(tmpl_7.getComponent!CInt);
|
assert(tmpl_7.getComponent!CInt);
|
||||||
assert(tmpl_7.getComponent!CDouble);
|
assert(tmpl_7.getComponent!CDouble);
|
||||||
assert(tmpl_7.getComponent!CLong);
|
assert(tmpl_7.getComponent!CLong);
|
||||||
|
|
@ -496,6 +575,10 @@ unittest
|
||||||
|
|
||||||
gEM.endRegister();
|
gEM.endRegister();
|
||||||
|
|
||||||
|
assert(gEM.getPass("custom"));
|
||||||
|
assert(!gEM.getPass("custommm"));
|
||||||
|
|
||||||
|
|
||||||
LongAddSystem* system = gEM.getSystem!LongAddSystem;
|
LongAddSystem* system = gEM.getSystem!LongAddSystem;
|
||||||
assert(system !is null);
|
assert(system !is null);
|
||||||
assert(system.updates_count == 0);
|
assert(system.updates_count == 0);
|
||||||
|
|
@ -1131,9 +1214,9 @@ unittest
|
||||||
assert(*entity2.getComponent!CShort == 12);
|
assert(*entity2.getComponent!CShort == 12);
|
||||||
|
|
||||||
gEM.sendEvent(id,ETest());
|
gEM.sendEvent(id,ETest());
|
||||||
gEM.sendEvent(id,ETest2(id,10));
|
gEM.sendEvent(id,ETest2(10));
|
||||||
gEM.sendEvent(id2,ETest());
|
gEM.sendEvent(id2,ETest());
|
||||||
gEM.sendEvent(id2,ETest2(id2,12));
|
gEM.sendEvent(id2,ETest2(12));
|
||||||
gEM.commit();
|
gEM.commit();
|
||||||
assert(ETest2.destory == 2);
|
assert(ETest2.destory == 2);
|
||||||
|
|
||||||
|
|
@ -1144,7 +1227,7 @@ unittest
|
||||||
|
|
||||||
gEM.addComponents(id, CInt(2), CShort(1));
|
gEM.addComponents(id, CInt(2), CShort(1));
|
||||||
gEM.sendEvent(id,ETest());
|
gEM.sendEvent(id,ETest());
|
||||||
gEM.sendEvent(id,ETest2(id,2));
|
gEM.sendEvent(id,ETest2(2));
|
||||||
gEM.commit();
|
gEM.commit();
|
||||||
assert(ETest2.destory == 3);
|
assert(ETest2.destory == 3);
|
||||||
|
|
||||||
|
|
@ -1157,7 +1240,7 @@ unittest
|
||||||
foreach(i;0..10000)
|
foreach(i;0..10000)
|
||||||
{
|
{
|
||||||
gEM.sendEvent(id,ETest());
|
gEM.sendEvent(id,ETest());
|
||||||
gEM.sendEvent(id,ETest2(id,4));
|
gEM.sendEvent(id,ETest2(4));
|
||||||
result += 16;
|
result += 16;
|
||||||
result += 8;
|
result += 8;
|
||||||
}
|
}
|
||||||
|
|
@ -1321,22 +1404,6 @@ unittest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void func1(TestSystem.EntitiesData entities)
|
|
||||||
{
|
|
||||||
foreach(i;0 .. entities.length)
|
|
||||||
{
|
|
||||||
entities.int_[i] += entities.int_[i] / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void func2(TestSystem.EntitiesData entities)
|
|
||||||
{
|
|
||||||
foreach(i;0 .. entities.length)
|
|
||||||
{
|
|
||||||
entities.int_[i] += 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gEM.beginRegister();
|
gEM.beginRegister();
|
||||||
|
|
||||||
gEM.registerSystem!TestSystem(0);
|
gEM.registerSystem!TestSystem(0);
|
||||||
|
|
@ -1462,22 +1529,6 @@ unittest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void func1(TestSystem.EntitiesData entities)
|
|
||||||
{
|
|
||||||
foreach(i;0 .. entities.length)
|
|
||||||
{
|
|
||||||
entities.int_[i] += entities.int_[i] / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void func2(TestSystem.EntitiesData entities)
|
|
||||||
{
|
|
||||||
foreach(i;0 .. entities.length)
|
|
||||||
{
|
|
||||||
entities.int_[i] += 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gEM.beginRegister();
|
gEM.beginRegister();
|
||||||
|
|
||||||
gEM.registerDependency(TestDependency);
|
gEM.registerDependency(TestDependency);
|
||||||
|
|
|
||||||
142
tests/bugs.d
Normal file
142
tests/bugs.d
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
module tests.bugs;
|
||||||
|
|
||||||
|
import tests.basic;
|
||||||
|
|
||||||
|
import bubel.ecs.core;
|
||||||
|
import bubel.ecs.manager;
|
||||||
|
import bubel.ecs.system;
|
||||||
|
import bubel.ecs.attributes;
|
||||||
|
|
||||||
|
version(GNU)
|
||||||
|
{
|
||||||
|
pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a)
|
||||||
|
{
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else import std.array : staticArray;
|
||||||
|
|
||||||
|
@("Bug0001")
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
struct Event1
|
||||||
|
{
|
||||||
|
mixin ECS.Event;
|
||||||
|
|
||||||
|
EntityID id;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Event2
|
||||||
|
{
|
||||||
|
mixin ECS.Event;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct System1
|
||||||
|
{
|
||||||
|
mixin ECS.System;
|
||||||
|
|
||||||
|
struct EntitiesData
|
||||||
|
{
|
||||||
|
CInt[] int_;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityTemplate* tmpl;
|
||||||
|
EntityID id;
|
||||||
|
|
||||||
|
void onCreate()
|
||||||
|
{
|
||||||
|
tmpl = gEM.allocateTemplate([CInt.component_id, CLong.component_id].staticArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDestroy()
|
||||||
|
{
|
||||||
|
gEM.freeTemplate(tmpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleEvent(Entity* entity, Event1 event)
|
||||||
|
{
|
||||||
|
gEM.removeEntity(event.id);
|
||||||
|
gEM.sendEvent(entity.id,Event2());
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleEvent(Entity* entity, Event2 event)
|
||||||
|
{
|
||||||
|
id = gEM.addEntity(tmpl,[CInt(2).ref_, CLong(8).ref_].staticArray).id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct System2
|
||||||
|
{
|
||||||
|
mixin ECS.System;
|
||||||
|
|
||||||
|
struct EntitiesData
|
||||||
|
{
|
||||||
|
Entity[] entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
///check if every entity was removed correctly
|
||||||
|
void onUpdate(EntitiesData data)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct System3
|
||||||
|
{
|
||||||
|
mixin ECS.System;
|
||||||
|
|
||||||
|
struct EntitiesData
|
||||||
|
{
|
||||||
|
uint length;
|
||||||
|
Entity[] entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
///remove every entity
|
||||||
|
void onUpdate(EntitiesData data)
|
||||||
|
{
|
||||||
|
foreach(i;0..data.length)gEM.removeEntity(data.entity[i].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gEM.initialize(0);
|
||||||
|
|
||||||
|
gEM.beginRegister();
|
||||||
|
|
||||||
|
gEM.registerComponent!CInt;
|
||||||
|
gEM.registerComponent!CFloat;
|
||||||
|
gEM.registerComponent!CDouble;
|
||||||
|
gEM.registerComponent!CLong;
|
||||||
|
gEM.registerComponent!CShort;
|
||||||
|
gEM.registerComponent!CFlag;
|
||||||
|
|
||||||
|
gEM.registerEvent!Event1;
|
||||||
|
gEM.registerEvent!Event2;
|
||||||
|
|
||||||
|
gEM.registerSystem!System1(0);
|
||||||
|
gEM.registerSystem!System2(-200);
|
||||||
|
gEM.registerSystem!System3(-200);
|
||||||
|
|
||||||
|
gEM.endRegister();
|
||||||
|
|
||||||
|
EntityTemplate* tmpl = gEM.allocateTemplate([CInt.component_id, CLong.component_id].staticArray);
|
||||||
|
EntityID id = gEM.addEntity(tmpl,[CLong(10).ref_, CInt(6).ref_].staticArray).id;
|
||||||
|
EntityID id2 = gEM.addEntity(tmpl,[CInt(4).ref_].staticArray).id;
|
||||||
|
gEM.freeTemplate(tmpl);
|
||||||
|
gEM.commit();
|
||||||
|
|
||||||
|
gEM.sendEvent(id2, Event1(id));
|
||||||
|
|
||||||
|
gEM.getSystem(System2.system_id).disable();
|
||||||
|
|
||||||
|
gEM.begin();
|
||||||
|
gEM.update();
|
||||||
|
gEM.end();
|
||||||
|
|
||||||
|
gEM.getSystem(System2.system_id).enable();
|
||||||
|
|
||||||
|
gEM.begin();
|
||||||
|
gEM.update();
|
||||||
|
gEM.end();
|
||||||
|
|
||||||
|
gEM.destroy();
|
||||||
|
}
|
||||||
|
|
@ -210,7 +210,7 @@ struct TestRunner(Args...)
|
||||||
else
|
else
|
||||||
test.name = attributes[0];
|
test.name = attributes[0];
|
||||||
|
|
||||||
static if (__traits(hasMember, module_, "beforeEveryTest"))
|
static if (__traits(hasMember, module_, "beforeEveryTest") && __traits(compiles, module_.beforeEveryTest()))
|
||||||
module_.beforeEveryTest();
|
module_.beforeEveryTest();
|
||||||
if(before)before();
|
if(before)before();
|
||||||
|
|
||||||
|
|
@ -256,7 +256,7 @@ struct TestRunner(Args...)
|
||||||
else
|
else
|
||||||
suite.failed++;
|
suite.failed++;
|
||||||
suite.tests ~= test;
|
suite.tests ~= test;
|
||||||
static if (__traits(hasMember, module_, "afterEveryTest"))
|
static if (__traits(hasMember, module_, "afterEveryTest") && __traits(compiles, module_.beforeEveryTest()))
|
||||||
module_.afterEveryTest();
|
module_.afterEveryTest();
|
||||||
}
|
}
|
||||||
passed += suite.passed;
|
passed += suite.passed;
|
||||||
|
|
@ -420,7 +420,7 @@ extern (C) int main(int argc, char** args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TestRunner!(tests.id_manager, tests.vector, tests.basic, tests.perf, tests.access_perf) runner;
|
TestRunner!(tests.id_manager, tests.vector, tests.basic, tests.perf, tests.access_perf, tests.bugs) runner;
|
||||||
|
|
||||||
runner.runTests(include[], exclude[]);
|
runner.runTests(include[], exclude[]);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue