Compare commits
1 commit
master
...
test_remov
| Author | SHA1 | Date | |
|---|---|---|---|
| 0281fd5c1d |
25 changed files with 403 additions and 543 deletions
|
|
@ -56,7 +56,7 @@ coverage_test_dmd:
|
||||||
- mkdir reports
|
- mkdir reports
|
||||||
- binaries/dmd_unittest_cov
|
- binaries/dmd_unittest_cov
|
||||||
after_script:
|
after_script:
|
||||||
- bash <(curl -s https://codecov.io/bash) -s reports -t df87b1d8-85f4-4584-96e3-1315d27ec2c5
|
- bash <(curl -s https://codecov.io/bash) -s reports -t 1a0c0169-a721-4085-8252-fed4755dcd8c
|
||||||
|
|
||||||
wasm:
|
wasm:
|
||||||
stage: build_wasm
|
stage: build_wasm
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,6 @@ Bubel ECS was tested on Linux, Windows, Android and WASM.
|
||||||
|
|
||||||
**Currently library is in beta stage so some significant API changes can appear.**
|
**Currently library is in beta stage so some significant API changes can appear.**
|
||||||
|
|
||||||
Package is available on [DUB package repository](https://code.dlang.org/packages/bubel-ecs). Usage:
|
|
||||||
```
|
|
||||||
"dependencies": {
|
|
||||||
"bubel-ecs": "~>0.1.1"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Design
|
## Design
|
||||||
|
|
||||||
For core information about Entity-Component-System architectural pattern please read definition described at [Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system).
|
For core information about Entity-Component-System architectural pattern please read definition described at [Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system).
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ def compile(sources, output):
|
||||||
if file_extension == '.d' and filename != 'package':
|
if file_extension == '.d' and filename != 'package':
|
||||||
files.append(os.path.join(r, file))
|
files.append(os.path.join(r, file))
|
||||||
|
|
||||||
ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-emscripten -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' '
|
ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' '
|
||||||
|
|
||||||
for path in sources:
|
for path in sources:
|
||||||
ldc_cmd += '-I' + path + ' '
|
ldc_cmd += '-I' + path + ' '
|
||||||
|
|
@ -33,7 +33,7 @@ def compile(sources, output):
|
||||||
shared_flags = ''
|
shared_flags = ''
|
||||||
clean = 0
|
clean = 0
|
||||||
emc_flags = ''
|
emc_flags = ''
|
||||||
ldc_flags = ''
|
ldc_flags = '--d-version=ECSEmscripten '
|
||||||
import_paths = ['source','tests']
|
import_paths = ['source','tests']
|
||||||
build_tests = 0
|
build_tests = 0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import ntpath
|
import ntpath
|
||||||
import sys
|
import sys
|
||||||
|
import imp
|
||||||
|
|
||||||
def compile(sources, output):
|
def compile(sources, output):
|
||||||
files = []
|
files = []
|
||||||
|
|
@ -13,7 +14,7 @@ def compile(sources, output):
|
||||||
if file_extension == '.d' and filename != 'package':
|
if file_extension == '.d' and filename != 'package':
|
||||||
files.append(os.path.join(r, file))
|
files.append(os.path.join(r, file))
|
||||||
|
|
||||||
ldc_cmd = compiler + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-emscripten -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' '
|
ldc_cmd = compiler + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' '
|
||||||
|
|
||||||
for path in sources:
|
for path in sources:
|
||||||
ldc_cmd += '-I' + path + ' '
|
ldc_cmd += '-I' + path + ' '
|
||||||
|
|
@ -40,7 +41,7 @@ only_bc = 0
|
||||||
multi = 0
|
multi = 0
|
||||||
sources = ['tests', 'source']
|
sources = ['tests', 'source']
|
||||||
emc_flags = '-s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS="[\'png\']" '
|
emc_flags = '-s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS="[\'png\']" '
|
||||||
ldc_flags = '--d-version=SDL_209 --d-version=BindSDL_Static --d-version=BindSDL_Image --d-version=MM_USE_POSIX_THREADS '
|
ldc_flags = '--d-version=ECSEmscripten --d-version=SDL_209 --d-version=BindSDL_Static --d-version=BindSDL_Image --d-version=MM_USE_POSIX_THREADS '
|
||||||
import_paths = ['external/sources', 'external/imports', 'external/wasm_imports', '../source', 'utils/source', 'simple/source']
|
import_paths = ['external/sources', 'external/imports', 'external/wasm_imports', '../source', 'utils/source', 'simple/source']
|
||||||
|
|
||||||
for arg in sys.argv[1:]:
|
for arg in sys.argv[1:]:
|
||||||
|
|
@ -120,9 +121,8 @@ emcc_cmd += 'demo.bc '
|
||||||
|
|
||||||
os.system("mkdir build")
|
os.system("mkdir build")
|
||||||
|
|
||||||
# emscripten = imp.load_source('', os.path.expanduser("~") + '/.emscripten')
|
emscripten = imp.load_source('', os.path.expanduser("~") + '/.emscripten')
|
||||||
# pack_cmd = emscripten.EMSCRIPTEN_ROOT + '/tools/file_packager.py build/assets.data --preload assets --js-output=build/assets.js'
|
pack_cmd = emscripten.EMSCRIPTEN_ROOT + '/tools/file_packager.py build/assets.data --preload assets --js-output=build/assets.js'
|
||||||
pack_cmd = os.path.expandvars('$EMSDK/upstream/emscripten') + '/tools/file_packager.py build/assets.data --preload assets --js-output=build/assets.js'
|
|
||||||
print('Packafing files: ' + pack_cmd)
|
print('Packafing files: ' + pack_cmd)
|
||||||
|
|
||||||
os.system(pack_cmd)
|
os.system(pack_cmd)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ executable('BubelECSDemos', [demos_src, external_src],
|
||||||
bindbc_loader_dep,
|
bindbc_loader_dep,
|
||||||
bindbc_sdl_dep,
|
bindbc_sdl_dep,
|
||||||
cimgui_dep,
|
cimgui_dep,
|
||||||
bubel_ecs_dep,
|
decs_dep,
|
||||||
ecs_utils_dep,
|
ecs_utils_dep,
|
||||||
sdl2_dep,
|
sdl2_dep,
|
||||||
sdl2_image_dep,
|
sdl2_image_dep,
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ subdir('source/ecs_utils')
|
||||||
utils_inc = include_directories('source/')
|
utils_inc = include_directories('source/')
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
ecs_utils_lib = library('ECSUtils', utils_src,
|
ecs_utils_lib = library('ecs_utils', utils_src,
|
||||||
include_directories : [demos_inc, external_inc, utils_inc],
|
include_directories : [demos_inc, external_inc, utils_inc],
|
||||||
link_args : link_args,
|
link_args : link_args,
|
||||||
d_module_versions : versions,
|
d_module_versions : versions,
|
||||||
dependencies : [
|
dependencies : [
|
||||||
bubel_ecs_dep,
|
decs_dep,
|
||||||
bindbc_loader_dep,
|
bindbc_loader_dep,
|
||||||
bindbc_sdl_dep,
|
bindbc_sdl_dep,
|
||||||
]
|
]
|
||||||
|
|
|
||||||
4
dub.json
4
dub.json
|
|
@ -5,7 +5,7 @@
|
||||||
"Michał Masiukiewicz", "Dawid Masiukiewicz"
|
"Michał Masiukiewicz", "Dawid Masiukiewicz"
|
||||||
],
|
],
|
||||||
"description": "Dynamic Entity Component System",
|
"description": "Dynamic Entity Component System",
|
||||||
"copyright": "Copyright © 2018-2023, Michał Masiukiewicz, Dawid Masiukiewicz",
|
"copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz",
|
||||||
"license": "BSD 3-clause",
|
"license": "BSD 3-clause",
|
||||||
"sourcePaths" : ["source\/"],
|
"sourcePaths" : ["source\/"],
|
||||||
"excludedSourceFiles":[
|
"excludedSourceFiles":[
|
||||||
|
|
@ -63,7 +63,7 @@
|
||||||
],
|
],
|
||||||
"dflags": [
|
"dflags": [
|
||||||
"-unittest",
|
"-unittest",
|
||||||
"-cov=ctfe"
|
"-cov"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ threads_dep = dependency('threads')
|
||||||
d_versions = []
|
d_versions = []
|
||||||
deps = []
|
deps = []
|
||||||
if host_machine.cpu_family() == 'wasm32'
|
if host_machine.cpu_family() == 'wasm32'
|
||||||
|
d_versions += 'ECSEmscripten'
|
||||||
else
|
else
|
||||||
# meson incorectly adds "-s USE_PTHREADS=1" to ldc2 invocation whe pthreads is added as dependency
|
# meson incorectly adds "-s USE_PTHREADS=1" to ldc2 invocation whe pthreads is added as dependency
|
||||||
# add it for non wasm builds
|
# add it for non wasm builds
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,129 @@ It's internal code. Can be used for atomics if emscripten backend will be used.
|
||||||
This module contain atomic operations which include support for emscripten atomics functions.
|
This module contain atomic operations which include support for emscripten atomics functions.
|
||||||
Emscripten functions are contained in API similar to druntime.
|
Emscripten functions are contained in API similar to druntime.
|
||||||
|
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module bubel.ecs.atomic;
|
module bubel.ecs.atomic;
|
||||||
|
|
||||||
public import core.atomic;
|
version (Emscripten) version = ECSEmscripten;
|
||||||
|
|
||||||
|
version (ECSEmscripten)
|
||||||
|
{
|
||||||
|
import std.traits;
|
||||||
|
|
||||||
|
enum MemoryOrder
|
||||||
|
{
|
||||||
|
acq,
|
||||||
|
acq_rel,
|
||||||
|
raw,
|
||||||
|
rel,
|
||||||
|
seq
|
||||||
|
}
|
||||||
|
|
||||||
|
extern (C) ubyte emscripten_atomic_cas_u8(void* addr, ubyte oldVal, ubyte newVal) @nogc nothrow pure;
|
||||||
|
extern (C) ushort emscripten_atomic_cas_u16(void* addr, ushort oldVal, ushort newVal) @nogc nothrow pure;
|
||||||
|
extern (C) uint emscripten_atomic_cas_u32(void* addr, uint oldVal, uint newVal) @nogc nothrow pure;
|
||||||
|
|
||||||
|
extern (C) ubyte emscripten_atomic_load_u8(const void* addr) @nogc nothrow pure;
|
||||||
|
extern (C) ushort emscripten_atomic_load_u16(const void* addr) @nogc nothrow pure;
|
||||||
|
extern (C) uint emscripten_atomic_load_u32(const void* addr) @nogc nothrow pure;
|
||||||
|
|
||||||
|
extern (C) ubyte emscripten_atomic_store_u8(void* addr, ubyte val) @nogc nothrow pure;
|
||||||
|
extern (C) ushort emscripten_atomic_store_u16(void* addr, ushort val) @nogc nothrow pure;
|
||||||
|
extern (C) uint emscripten_atomic_store_u32(void* addr, uint val) @nogc nothrow pure;
|
||||||
|
|
||||||
|
extern (C) ubyte emscripten_atomic_add_u8(void* addr, ubyte val) @nogc nothrow pure;
|
||||||
|
extern (C) ushort emscripten_atomic_add_u16(void* addr, ushort val) @nogc nothrow pure;
|
||||||
|
extern (C) uint emscripten_atomic_add_u32(void* addr, uint val) @nogc nothrow pure;
|
||||||
|
|
||||||
|
extern (C) ubyte emscripten_atomic_sub_u8(void* addr, ubyte val) @nogc nothrow pure;
|
||||||
|
extern (C) ushort emscripten_atomic_sub_u16(void* addr, ushort val) @nogc nothrow pure;
|
||||||
|
extern (C) uint emscripten_atomic_sub_u32(void* addr, uint val) @nogc nothrow pure;
|
||||||
|
|
||||||
|
public pure nothrow @nogc Unqual!T atomicOp(string op, T, V1)(ref shared T val, V1 mod)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
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 == "-=")
|
||||||
|
{
|
||||||
|
static if (is(T == byte) || is(T == ubyte))
|
||||||
|
return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val,
|
||||||
|
cast(Unqual!T) mod) - 1);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
else static if (is(UT == short) || is(UT == ushort))
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
alias UT = Unqual!T;
|
||||||
|
static if (is(UT == bool))
|
||||||
|
return emscripten_atomic_load_u8(cast(const void*)&val) != 0;
|
||||||
|
else static if (is(UT == byte) || is(UT == ubyte))
|
||||||
|
return emscripten_atomic_load_u8(cast(const void*)&val);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
public import core.atomic;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ Struct EntitiesData
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module bubel.ecs.attributes;
|
module bubel.ecs.attributes;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ It's internal code.
|
||||||
|
|
||||||
Module contain memory allocator.
|
Module contain memory allocator.
|
||||||
|
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module bubel.ecs.block_allocator;
|
module bubel.ecs.block_allocator;
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ Struct System1
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module bubel.ecs.core;
|
module bubel.ecs.core;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
Entity module.
|
Entity module.
|
||||||
|
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module bubel.ecs.entity;
|
module bubel.ecs.entity;
|
||||||
|
|
@ -44,7 +44,7 @@ struct Entity
|
||||||
return cast(T*)getComponent(becsID!T);
|
return cast(T*)getComponent(becsID!T);
|
||||||
}
|
}
|
||||||
|
|
||||||
export void* getComponent(ushort component_id) const
|
void* getComponent(ushort component_id) const
|
||||||
{
|
{
|
||||||
EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this);
|
EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this);
|
||||||
EntityManager.EntityInfo* info = block.type_info;
|
EntityManager.EntityInfo* info = block.type_info;
|
||||||
|
|
@ -54,7 +54,7 @@ struct Entity
|
||||||
return (cast(void*)block + info.deltas[component_id] + block.entityIndex(&this) * gEntityManager.components[component_id].size);
|
return (cast(void*)block + info.deltas[component_id] + block.entityIndex(&this) * gEntityManager.components[component_id].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool hasComponent(ushort component_id) const
|
bool hasComponent(ushort component_id) const
|
||||||
{
|
{
|
||||||
EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this);
|
EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this);
|
||||||
EntityManager.EntityInfo* info = block.type_info;
|
EntityManager.EntityInfo* info = block.type_info;
|
||||||
|
|
@ -62,7 +62,7 @@ struct Entity
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export EntityMeta getMeta() const
|
EntityMeta getMeta() const
|
||||||
{
|
{
|
||||||
EntityMeta meta;
|
EntityMeta meta;
|
||||||
meta.block = gEntityManager.getMetaData(&this);
|
meta.block = gEntityManager.getMetaData(&this);
|
||||||
|
|
@ -85,7 +85,7 @@ struct EntityMeta
|
||||||
return cast(T*)getComponent(becsID!T);
|
return cast(T*)getComponent(becsID!T);
|
||||||
}
|
}
|
||||||
|
|
||||||
export void* getComponent(ushort component_id) const
|
void* getComponent(ushort component_id) const
|
||||||
{
|
{
|
||||||
const (EntityManager.EntityInfo)* info = block.type_info;
|
const (EntityManager.EntityInfo)* info = block.type_info;
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ struct EntityMeta
|
||||||
return (cast(void*)block + info.deltas[component_id] + index * gEntityManager.components[component_id].size);
|
return (cast(void*)block + info.deltas[component_id] + index * gEntityManager.components[component_id].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool hasComponent(ushort component_id) const
|
bool hasComponent(ushort component_id) const
|
||||||
{
|
{
|
||||||
const EntityManager.EntityInfo* info = block.type_info;
|
const EntityManager.EntityInfo* info = block.type_info;
|
||||||
if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false;
|
if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false;
|
||||||
|
|
@ -133,7 +133,7 @@ export struct EntityTemplate
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime.
|
Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime.
|
||||||
*/
|
*/
|
||||||
export void* getComponent(ushort component_id) const nothrow @nogc
|
void* getComponent(ushort component_id) const nothrow @nogc
|
||||||
{
|
{
|
||||||
if(component_id >= info.tmpl_deltas.length || info.tmpl_deltas[component_id] == ushort.max)return null;
|
if(component_id >= info.tmpl_deltas.length || info.tmpl_deltas[component_id] == ushort.max)return null;
|
||||||
return cast(void*)(entity_data.ptr + info.tmpl_deltas[component_id]);
|
return cast(void*)(entity_data.ptr + info.tmpl_deltas[component_id]);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module bubel.ecs.events;
|
module bubel.ecs.events;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module bubel.ecs.hash_map;
|
module bubel.ecs.hash_map;
|
||||||
|
|
@ -28,7 +28,7 @@ export ulong defaultHashFunc(T)(auto ref T t) nothrow @nogc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export ulong hash(byte[] array) nothrow @nogc
|
ulong hash(byte[] array) nothrow @nogc
|
||||||
{
|
{
|
||||||
ulong hash = 0;
|
ulong hash = 0;
|
||||||
|
|
||||||
|
|
@ -72,31 +72,31 @@ nothrow:
|
||||||
size_t length; // Used to compute loadFactor
|
size_t length; // Used to compute loadFactor
|
||||||
size_t markerdDeleted;
|
size_t markerdDeleted;
|
||||||
|
|
||||||
export void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
elements.clear();
|
elements.clear();
|
||||||
length = 0;
|
length = 0;
|
||||||
markerdDeleted = 0;
|
markerdDeleted = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void reset()
|
void reset()
|
||||||
{
|
{
|
||||||
elements.reset();
|
elements.reset();
|
||||||
length = 0;
|
length = 0;
|
||||||
markerdDeleted = 0;
|
markerdDeleted = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool isIn(ref Key el)
|
bool isIn(ref Key el)
|
||||||
{
|
{
|
||||||
return getIndex(el) != getIndexEmptyValue;
|
return getIndex(el) != getIndexEmptyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool isIn(Key el)
|
bool isIn(Key el)
|
||||||
{
|
{
|
||||||
return getIndex(el) != getIndexEmptyValue;
|
return getIndex(el) != getIndexEmptyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
export Value* getPtr()(auto ref Key k)
|
Value* getPtr()(auto ref Key k)
|
||||||
{
|
{
|
||||||
size_t index = getIndex(k);
|
size_t index = getIndex(k);
|
||||||
if (index == getIndexEmptyValue)
|
if (index == getIndexEmptyValue)
|
||||||
|
|
@ -109,20 +109,20 @@ nothrow:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export ref Value get()(auto ref Key k)
|
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.") 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)
|
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)
|
||||||
|
|
@ -135,7 +135,7 @@ nothrow:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export ref Value getInsertDefault()(auto ref Key k, auto ref Value defaultValue)
|
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)
|
||||||
|
|
@ -148,7 +148,7 @@ nothrow:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool tryRemove(Key el)
|
bool tryRemove(Key el)
|
||||||
{
|
{
|
||||||
size_t index = getIndex(el);
|
size_t index = getIndex(el);
|
||||||
if (index == getIndexEmptyValue)
|
if (index == getIndexEmptyValue)
|
||||||
|
|
@ -161,23 +161,23 @@ nothrow:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void remove(Key el)
|
void remove(Key el)
|
||||||
{
|
{
|
||||||
bool ok = tryRemove(el);
|
bool ok = tryRemove(el);
|
||||||
assert(ok);
|
assert(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
export ref Value opIndex()(auto ref Key key)
|
ref Value opIndex()(auto ref Key key)
|
||||||
{
|
{
|
||||||
return get(key);
|
return get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
export void opIndexAssign()(auto ref Value value, auto ref Key key)
|
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)
|
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)
|
||||||
|
|
@ -221,12 +221,12 @@ nothrow:
|
||||||
//int numA;
|
//int numA;
|
||||||
//int numB;
|
//int numB;
|
||||||
|
|
||||||
export size_t getIndex(Key el)
|
size_t getIndex(Key el)
|
||||||
{
|
{
|
||||||
return getIndex(el);
|
return getIndex(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
export size_t getIndex(ref Key el)
|
size_t getIndex(ref Key el)
|
||||||
{
|
{
|
||||||
mixin(doNotInline);
|
mixin(doNotInline);
|
||||||
|
|
||||||
|
|
@ -260,7 +260,7 @@ nothrow:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export float getLoadFactor(size_t forElementsNum)
|
float getLoadFactor(size_t forElementsNum)
|
||||||
{
|
{
|
||||||
if (elements.length == 0)
|
if (elements.length == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -269,7 +269,7 @@ nothrow:
|
||||||
return cast(float) forElementsNum / (elements.length);
|
return cast(float) forElementsNum / (elements.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
export void rehash()()
|
void rehash()()
|
||||||
{
|
{
|
||||||
mixin(doNotInline);
|
mixin(doNotInline);
|
||||||
// Get all elements
|
// Get all elements
|
||||||
|
|
@ -303,7 +303,7 @@ nothrow:
|
||||||
}
|
}
|
||||||
|
|
||||||
// foreach support
|
// foreach support
|
||||||
export int opApply(DG)(scope DG dg)
|
int opApply(DG)(scope DG dg)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
foreach (ref Bucket gr; elements)
|
foreach (ref Bucket gr; elements)
|
||||||
|
|
@ -336,36 +336,36 @@ nothrow:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export int byKey(scope int delegate(ref Key k) dg)
|
int byKey(scope int delegate(ref Key k) dg)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
foreach (ref Key k; this)
|
foreach (ref Key k; this)
|
||||||
{
|
{
|
||||||
result = (cast(int delegate(ref Key k) nothrow @nogc)dg)(k);
|
result = (cast(int delegate(ref Key k) nothrow)dg)(k);
|
||||||
if (result)
|
if (result)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export int byValue(scope int delegate(ref Value v) dg)
|
int byValue(scope int delegate(ref Value v) dg)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
foreach (ref Value v; this)
|
foreach (ref Value v; this)
|
||||||
{
|
{
|
||||||
result = (cast(int delegate(ref Value v) nothrow @nogc)dg)(v);
|
result = (cast(int delegate(ref Value v) nothrow)dg)(v);
|
||||||
if (result)
|
if (result)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export int byKeyValue(scope int delegate(ref Key k, ref Value v) dg)
|
int byKeyValue(scope int delegate(ref Key k, ref Value v) dg)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
foreach (ref Key k, ref Value v; this)
|
foreach (ref Key k, ref Value v; this)
|
||||||
{
|
{
|
||||||
result = (cast(int delegate(ref Key k, ref Value v) nothrow @nogc)dg)(k, v);
|
result = (cast(int delegate(ref Key k, ref Value v) nothrow)dg)(k, v);
|
||||||
if (result)
|
if (result)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module bubel.ecs.id_manager;
|
module bubel.ecs.id_manager;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module ecs;
|
module ecs;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module bubel.ecs.simple_vector;
|
module bubel.ecs.simple_vector;
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,16 @@
|
||||||
It's internal code!
|
It's internal code!
|
||||||
This module contain implementation of standard functionality.
|
This module contain implementation of standard functionality.
|
||||||
|
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module bubel.ecs.std;
|
module bubel.ecs.std;
|
||||||
|
|
||||||
|
version (Emscripten) version = ECSEmscripten;
|
||||||
|
|
||||||
import std.traits;
|
import std.traits;
|
||||||
|
|
||||||
version (Emscripten)
|
version (ECSEmscripten)
|
||||||
{
|
{
|
||||||
extern (C) struct pthread_mutex_t
|
extern (C) struct pthread_mutex_t
|
||||||
{
|
{
|
||||||
|
|
@ -27,6 +29,10 @@ version (Emscripten)
|
||||||
|
|
||||||
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 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;
|
||||||
|
|
@ -54,7 +60,7 @@ else
|
||||||
public import core.stdc.stdlib : qsort;
|
public import core.stdc.stdlib : qsort;
|
||||||
}
|
}
|
||||||
|
|
||||||
version (Emscripten)
|
version (ECSEmscripten)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
else version (Windows)
|
else version (Windows)
|
||||||
|
|
@ -83,7 +89,7 @@ else version (Posix)
|
||||||
import core.sys.posix.stdlib : posix_memalign;
|
import core.sys.posix.stdlib : posix_memalign;
|
||||||
}
|
}
|
||||||
|
|
||||||
version (Emscripten)
|
version (ECSEmscripten)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
|
@ -288,7 +294,7 @@ static struct Mallocator
|
||||||
posix_memalign(&ret, alignment, length); //ret = aligned_alloc(alignment, length);
|
posix_memalign(&ret, alignment, length); //ret = aligned_alloc(alignment, length);
|
||||||
else version (Windows)
|
else version (Windows)
|
||||||
ret = _aligned_malloc(length, alignment);
|
ret = _aligned_malloc(length, alignment);
|
||||||
else version (Emscripten)
|
else version (ECSEmscripten)
|
||||||
posix_memalign(&ret, alignment, length); //malloc(length);
|
posix_memalign(&ret, alignment, length); //malloc(length);
|
||||||
else
|
else
|
||||||
static assert(0, "Unimplemented platform!");
|
static assert(0, "Unimplemented platform!");
|
||||||
|
|
@ -335,7 +341,7 @@ static struct Mallocator
|
||||||
free(cast(void*) object);
|
free(cast(void*) object);
|
||||||
else version (Windows)
|
else version (Windows)
|
||||||
_aligned_free(cast(void*) object);
|
_aligned_free(cast(void*) object);
|
||||||
else version (Emscripten)
|
else version (ECSEmscripten)
|
||||||
free(cast(void*) object);
|
free(cast(void*) object);
|
||||||
else
|
else
|
||||||
static assert(0, "Unimplemented platform!");
|
static assert(0, "Unimplemented platform!");
|
||||||
|
|
@ -345,7 +351,7 @@ static struct Mallocator
|
||||||
struct Mutex
|
struct Mutex
|
||||||
{
|
{
|
||||||
|
|
||||||
version (Emscripten)
|
version (ECSEmscripten)
|
||||||
{
|
{
|
||||||
void initialize() nothrow @nogc
|
void initialize() nothrow @nogc
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
System module.
|
System module.
|
||||||
|
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module bubel.ecs.system;
|
module bubel.ecs.system;
|
||||||
|
|
@ -13,14 +13,14 @@ import bubel.ecs.manager;
|
||||||
System contain data required to proper glue EntityManager with Systems.
|
System contain data required to proper glue EntityManager with Systems.
|
||||||
System callbacks:
|
System callbacks:
|
||||||
$(LIST
|
$(LIST
|
||||||
* void onUpdate(EntitiesData);
|
* void onUpdate(EntitesData);
|
||||||
* void onEnable() - called inside system.enable() function
|
* void onEnable() - called inside system.enable() function
|
||||||
* void onDisable() - called inside system.disable() function
|
* void onDisable() - called inside system.disable() function
|
||||||
* bool onBegin() - called inside manager.begin()
|
* bool onBegin() - called inside manager.begin()
|
||||||
* void onEnd() - called inside manager.end()
|
* void onEnd() - called inside manager.end()
|
||||||
* void onCreate() - called after registration inside registerSystem function
|
* void onCreate() - called after registration inside registerSystem function
|
||||||
* void onDestroy() - called during re-registration and inside manager destructor
|
* void onDestroy() - called during re-registration and inside manager destructor
|
||||||
* void onAddEntity(EntitiesData) - called for every entity which are assigned to system (by adding new entity or changing its components)
|
* void onAddEntity(EntitesData) - called for every entity which are assigned to system (by adding new entity or changing its components)
|
||||||
* void onRemoveEntity(EntitiesData) - called for every entity removed from system update process
|
* void onRemoveEntity(EntitiesData) - called for every entity removed from system update process
|
||||||
* void onChangeEntity(EntitiesData) - called for every entity which components are changed but it was previously assigned to system
|
* void onChangeEntity(EntitiesData) - called for every entity which components are changed but it was previously assigned to system
|
||||||
* void handleEvent(Entity*, Event) - called for every event supported by system
|
* void handleEvent(Entity*, Event) - called for every event supported by system
|
||||||
|
|
@ -89,100 +89,38 @@ struct System
|
||||||
return cast(const(char)[]) m_name;
|
return cast(const(char)[]) m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
|
||||||
Return false if system was unregistered, true otherwise.
|
|
||||||
*/
|
|
||||||
export bool isAlive() nothrow @nogc
|
|
||||||
{
|
|
||||||
return m_system_pointer != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/************************************************************************************************************************
|
|
||||||
Return pointer to user side system object
|
|
||||||
*/
|
|
||||||
export void* ptr() nothrow @nogc
|
|
||||||
{
|
|
||||||
return m_system_pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
package:
|
package:
|
||||||
|
|
||||||
///destory system. Dispose all data
|
void destroy()
|
||||||
export void destroy() nothrow @nogc
|
|
||||||
{
|
|
||||||
import bubel.ecs.std : Mallocator;
|
|
||||||
|
|
||||||
destroySystemData();
|
|
||||||
|
|
||||||
if (m_name)
|
|
||||||
{
|
|
||||||
Mallocator.dispose(m_name);
|
|
||||||
m_name = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///destroy all system data but keeps name which is used for case of system re-registration
|
|
||||||
void destroySystemData() nothrow @nogc
|
|
||||||
{
|
{
|
||||||
import bubel.ecs.std : Mallocator;
|
import bubel.ecs.std : Mallocator;
|
||||||
disable();
|
disable();
|
||||||
if (m_destroy)
|
if (m_destroy)
|
||||||
{
|
(cast(void function(void*)) m_destroy)(m_system_pointer);
|
||||||
(cast(void function(void*) nothrow @nogc) m_destroy)(m_system_pointer);
|
|
||||||
m_destroy = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (m_name)
|
||||||
|
Mallocator.dispose(m_name);
|
||||||
if (m_components)
|
if (m_components)
|
||||||
{
|
|
||||||
Mallocator.dispose(m_components);
|
Mallocator.dispose(m_components);
|
||||||
m_components = null;
|
|
||||||
}
|
|
||||||
if (m_excluded_components)
|
if (m_excluded_components)
|
||||||
{
|
|
||||||
Mallocator.dispose(m_excluded_components);
|
Mallocator.dispose(m_excluded_components);
|
||||||
m_excluded_components = null;
|
|
||||||
}
|
|
||||||
if (m_optional_components)
|
if (m_optional_components)
|
||||||
{
|
|
||||||
Mallocator.dispose(m_optional_components);
|
Mallocator.dispose(m_optional_components);
|
||||||
m_optional_components = null;
|
|
||||||
}
|
|
||||||
if (jobs)
|
if (jobs)
|
||||||
{
|
|
||||||
Mallocator.dispose(jobs);
|
Mallocator.dispose(jobs);
|
||||||
jobs = null;
|
|
||||||
}
|
|
||||||
if (m_read_only_components)
|
if (m_read_only_components)
|
||||||
{
|
|
||||||
Mallocator.dispose(m_read_only_components);
|
Mallocator.dispose(m_read_only_components);
|
||||||
m_read_only_components = null;
|
|
||||||
}
|
|
||||||
if (m_writable_components)
|
if (m_writable_components)
|
||||||
{
|
|
||||||
Mallocator.dispose(m_writable_components);
|
Mallocator.dispose(m_writable_components);
|
||||||
m_writable_components = null;
|
|
||||||
}
|
|
||||||
if (m_readonly_dependencies)
|
if (m_readonly_dependencies)
|
||||||
{
|
|
||||||
Mallocator.dispose(m_readonly_dependencies);
|
Mallocator.dispose(m_readonly_dependencies);
|
||||||
m_readonly_dependencies = null;
|
|
||||||
}
|
|
||||||
if (m_writable_dependencies)
|
if (m_writable_dependencies)
|
||||||
{
|
|
||||||
Mallocator.dispose(m_writable_dependencies);
|
Mallocator.dispose(m_writable_dependencies);
|
||||||
m_writable_dependencies = null;
|
|
||||||
}
|
|
||||||
if (m_event_callers)
|
if (m_event_callers)
|
||||||
{
|
|
||||||
Mallocator.dispose(m_event_callers);
|
Mallocator.dispose(m_event_callers);
|
||||||
m_event_callers = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_system_pointer)
|
if (m_system_pointer)
|
||||||
{
|
|
||||||
Mallocator.dispose(m_system_pointer);
|
Mallocator.dispose(m_system_pointer);
|
||||||
m_system_pointer = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EventCaller
|
struct EventCaller
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module bubel.ecs.traits;
|
module bubel.ecs.traits;
|
||||||
|
|
@ -11,11 +11,8 @@ import std.traits;
|
||||||
*/
|
*/
|
||||||
ref ushort becsID(T)()
|
ref ushort becsID(T)()
|
||||||
{
|
{
|
||||||
/// Embed id in struct so export can be added to variable definition
|
__gshared ushort id = ushort.max;
|
||||||
static struct LocalStruct {
|
return id;
|
||||||
export __gshared ushort id = ushort.max;
|
|
||||||
}
|
|
||||||
return LocalStruct.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/************************************************************************************************************************
|
/************************************************************************************************************************
|
||||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||||
*/
|
*/
|
||||||
module bubel.ecs.vector;
|
module bubel.ecs.vector;
|
||||||
|
|
@ -14,13 +14,13 @@ import bubel.ecs.std;
|
||||||
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)
|
@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;
|
__gshared size_t gVectorsCreated = 0;
|
||||||
export __gshared size_t gVectorsDestroyed = 0;
|
__gshared size_t gVectorsDestroyed = 0;
|
||||||
|
|
||||||
struct Vector(T)
|
struct Vector(T)
|
||||||
{
|
{
|
||||||
|
|
@ -28,19 +28,19 @@ struct Vector(T)
|
||||||
size_t used;
|
size_t used;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
export this()(T t)
|
this()(T t)
|
||||||
{
|
{
|
||||||
add(t);
|
add(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
export this(X)(X[] t) if (is(Unqual!X == Unqual!T))
|
this(X)(X[] t) if (is(Unqual!X == Unqual!T))
|
||||||
{
|
{
|
||||||
add(t);
|
add(t);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static if (isCopyable!T) {
|
/*static if (isCopyable!T) {
|
||||||
export this(this) {
|
this(this) {
|
||||||
T[] tmp = array[0 .. used];
|
T[] tmp = array[0 .. used];
|
||||||
array = null;
|
array = null;
|
||||||
used = 0;
|
used = 0;
|
||||||
|
|
@ -52,17 +52,17 @@ public:
|
||||||
|
|
||||||
@disable this(this);
|
@disable this(this);
|
||||||
|
|
||||||
export ~this()
|
~this()
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
export void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
removeAll();
|
removeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
export void removeAll()
|
void removeAll()
|
||||||
{
|
{
|
||||||
if (array !is null)
|
if (array !is null)
|
||||||
{
|
{
|
||||||
|
|
@ -77,17 +77,17 @@ public:
|
||||||
used = 0;
|
used = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool empty() const
|
bool empty() const
|
||||||
{
|
{
|
||||||
return (used == 0);
|
return (used == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export size_t length() const
|
size_t length() const
|
||||||
{
|
{
|
||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void length(size_t newLength)
|
void length(size_t newLength)
|
||||||
{
|
{
|
||||||
if (newLength > used)
|
if (newLength > used)
|
||||||
{
|
{
|
||||||
|
|
@ -111,12 +111,12 @@ public:
|
||||||
used = newLength;
|
used = newLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void reset()
|
void reset()
|
||||||
{
|
{
|
||||||
used = 0;
|
used = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void reserve(size_t numElements)
|
void reserve(size_t numElements)
|
||||||
{
|
{
|
||||||
if (numElements > array.length)
|
if (numElements > array.length)
|
||||||
{
|
{
|
||||||
|
|
@ -124,12 +124,12 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export size_t capacity()
|
size_t capacity()
|
||||||
{
|
{
|
||||||
return array.length - used;
|
return array.length - used;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void extend(size_t newNumOfElements)
|
void extend(size_t newNumOfElements)
|
||||||
{
|
{
|
||||||
auto oldArray = manualExtend(array, newNumOfElements);
|
auto oldArray = manualExtend(array, newNumOfElements);
|
||||||
if (oldArray !is null)
|
if (oldArray !is null)
|
||||||
|
|
@ -138,14 +138,14 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export @nogc void freeData(void[] data)
|
@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)
|
static void[] manualExtend(ref T[] array, size_t newNumOfElements = 0)
|
||||||
{
|
{
|
||||||
if (newNumOfElements == 0)
|
if (newNumOfElements == 0)
|
||||||
newNumOfElements = 2;
|
newNumOfElements = 2;
|
||||||
|
|
@ -161,7 +161,7 @@ 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()()
|
Vector!T copy()()
|
||||||
{
|
{
|
||||||
Vector!T duplicate;
|
Vector!T duplicate;
|
||||||
duplicate.reserve(used);
|
duplicate.reserve(used);
|
||||||
|
|
@ -169,12 +169,12 @@ public:
|
||||||
return duplicate;
|
return duplicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*export bool canAddWithoutRealloc(uint elemNum = 1)
|
/*bool canAddWithoutRealloc(uint elemNum = 1)
|
||||||
{
|
{
|
||||||
return used + elemNum <= array.length;
|
return used + elemNum <= array.length;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
export void add()(T t)
|
void add()(T t)
|
||||||
{
|
{
|
||||||
if (used >= array.length)
|
if (used >= array.length)
|
||||||
{
|
{
|
||||||
|
|
@ -185,7 +185,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add element at given position moving others
|
/// Add element at given position moving others
|
||||||
export void add()(T t, size_t pos)
|
void add()(T t, size_t pos)
|
||||||
{
|
{
|
||||||
assert(pos <= used);
|
assert(pos <= used);
|
||||||
if (used >= array.length)
|
if (used >= array.length)
|
||||||
|
|
@ -201,7 +201,7 @@ public:
|
||||||
used++;
|
used++;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void add(X)(X[] t) if (is(Unqual!X == Unqual!T))
|
void add(X)(X[] t) if (is(Unqual!X == Unqual!T))
|
||||||
{
|
{
|
||||||
if (used + t.length > array.length)
|
if (used + t.length > array.length)
|
||||||
{
|
{
|
||||||
|
|
@ -214,7 +214,7 @@ public:
|
||||||
used += t.length;
|
used += t.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void remove(size_t elemNum)
|
void remove(size_t elemNum)
|
||||||
{
|
{
|
||||||
//destroy(array[elemNum]);
|
//destroy(array[elemNum]);
|
||||||
static if (__traits(hasMember, T, "__xdtor"))
|
static if (__traits(hasMember, T, "__xdtor"))
|
||||||
|
|
@ -226,7 +226,7 @@ public:
|
||||||
used--;
|
used--;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void removeStable()(size_t elemNum)
|
void removeStable()(size_t elemNum)
|
||||||
{
|
{
|
||||||
used--;
|
used--;
|
||||||
foreach (i; 0 .. used)
|
foreach (i; 0 .. used)
|
||||||
|
|
@ -235,7 +235,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export bool tryRemoveElement()(T elem)
|
bool tryRemoveElement()(T elem)
|
||||||
{
|
{
|
||||||
foreach (i, ref el; array[0 .. used])
|
foreach (i, ref el; array[0 .. used])
|
||||||
{
|
{
|
||||||
|
|
@ -248,65 +248,65 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void removeElement()(T elem)
|
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
|
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()
|
auto opSlice()
|
||||||
{
|
{
|
||||||
return array.ptr[0 .. used];
|
return array.ptr[0 .. used];
|
||||||
}
|
}
|
||||||
|
|
||||||
export T[] opSlice(size_t x, size_t y)
|
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()
|
size_t opDollar()
|
||||||
{
|
{
|
||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void opAssign(X)(X[] slice)
|
void opAssign(X)(X[] slice)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
this ~= slice;
|
this ~= slice;
|
||||||
}
|
}
|
||||||
|
|
||||||
export void opOpAssign(string op)(T obj)
|
void opOpAssign(string op)(T obj)
|
||||||
{
|
{
|
||||||
//static assert(op == "~");
|
//static assert(op == "~");
|
||||||
add(obj);
|
add(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
export void opOpAssign(string op, X)(X[] obj)
|
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)
|
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)
|
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
|
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];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
100
tests/basic.d
100
tests/basic.d
|
|
@ -113,31 +113,6 @@ struct EmptySystem
|
||||||
int count = 0;
|
int count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EntityCounterSystem
|
|
||||||
{
|
|
||||||
mixin ECS.System!1;
|
|
||||||
|
|
||||||
struct EntitiesData
|
|
||||||
{
|
|
||||||
int thread_id;
|
|
||||||
uint length;
|
|
||||||
Entity[] entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool onBegin()
|
|
||||||
{
|
|
||||||
count = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onUpdate(EntitiesData data)
|
|
||||||
{
|
|
||||||
count += data.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void beforeEveryTest()
|
void beforeEveryTest()
|
||||||
{
|
{
|
||||||
becsID!CUnregistered = ushort.max;
|
becsID!CUnregistered = ushort.max;
|
||||||
|
|
@ -268,82 +243,7 @@ unittest
|
||||||
gEntityManager.commit();
|
gEntityManager.commit();
|
||||||
entity3 = gEntityManager.getEntity(id);
|
entity3 = gEntityManager.getEntity(id);
|
||||||
assert(!entity3.getComponent!CUnregistered);
|
assert(!entity3.getComponent!CUnregistered);
|
||||||
}
|
|
||||||
|
|
||||||
@("AddEmptyEntity")
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
struct OnAddRemoveChangeCounter
|
|
||||||
{
|
|
||||||
mixin ECS.System!1;
|
|
||||||
|
|
||||||
struct EntitiesData
|
|
||||||
{
|
|
||||||
int thread_id;
|
|
||||||
uint length;
|
|
||||||
Entity[] entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onAddEntity(EntitiesData data)
|
|
||||||
{
|
|
||||||
add += data.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onRemoveEntity(EntitiesData data)
|
|
||||||
{
|
|
||||||
assert(0, "It's impossible to remove entity from being updated by system which accept empty entity");
|
|
||||||
}
|
|
||||||
|
|
||||||
int add = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
gEntityManager.beginRegister();
|
|
||||||
|
|
||||||
gEntityManager.registerSystem!EntityCounterSystem(0);
|
|
||||||
gEntityManager.registerSystem!OnAddRemoveChangeCounter(1);
|
|
||||||
|
|
||||||
gEntityManager.endRegister();
|
|
||||||
|
|
||||||
CLong long_component = CLong(3);
|
|
||||||
|
|
||||||
Entity* entity = null;
|
|
||||||
EntityID entity_id = gEntityManager.addEntity(null).id;
|
|
||||||
|
|
||||||
EntityCounterSystem* system = gEntityManager.getSystem!EntityCounterSystem;
|
|
||||||
assert(system !is null);
|
|
||||||
assert(system.count == 0);
|
|
||||||
|
|
||||||
OnAddRemoveChangeCounter* add_remove_change_system = gEntityManager.getSystem!OnAddRemoveChangeCounter;
|
|
||||||
assert(add_remove_change_system !is null);
|
|
||||||
assert(add_remove_change_system.add == 0);
|
|
||||||
|
|
||||||
gEntityManager.commit();
|
|
||||||
assert(add_remove_change_system.add == 1);
|
|
||||||
|
|
||||||
entity = gEntityManager.getEntity(entity_id);
|
|
||||||
assert(!entity.hasComponent(becsID!CLong));
|
|
||||||
assert(entity.getComponent(becsID!CLong) is null);
|
|
||||||
|
|
||||||
|
|
||||||
gEntityManager.begin();
|
|
||||||
gEntityManager.update();
|
|
||||||
assert(system.count == 1);
|
|
||||||
gEntityManager.end();
|
|
||||||
|
|
||||||
gEntityManager.addEntityCopy(entity_id);
|
|
||||||
gEntityManager.addEntityCopy(entity_id);
|
|
||||||
gEntityManager.addComponents(entity_id, [ComponentRef(&long_component, becsID(long_component))].staticArray);
|
|
||||||
gEntityManager.commit();
|
|
||||||
assert(add_remove_change_system.add == 3, "onAddEntity missed");
|
|
||||||
|
|
||||||
entity = gEntityManager.getEntity(entity_id);
|
|
||||||
assert(entity.hasComponent(becsID!CLong));
|
|
||||||
assert(*entity.getComponent!CLong == 3);
|
|
||||||
|
|
||||||
gEntityManager.begin();
|
|
||||||
gEntityManager.update();
|
|
||||||
assert(system.count == 3);
|
|
||||||
gEntityManager.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//allocate templates
|
//allocate templates
|
||||||
|
|
|
||||||
29
tests/bugs.d
29
tests/bugs.d
|
|
@ -142,34 +142,5 @@ unittest
|
||||||
gEntityManager.update();
|
gEntityManager.update();
|
||||||
gEntityManager.end();
|
gEntityManager.end();
|
||||||
|
|
||||||
gEntityManager.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@("2-empty-entity-crash")
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
|
|
||||||
gEntityManager.initialize(0);
|
|
||||||
|
|
||||||
gEntityManager.beginRegister();
|
|
||||||
|
|
||||||
gEntityManager.registerComponent!CInt;
|
|
||||||
gEntityManager.registerComponent!CFloat;
|
|
||||||
|
|
||||||
gEntityManager.endRegister();
|
|
||||||
|
|
||||||
|
|
||||||
EntityTemplate* tmpl = gEntityManager.allocateTemplate([becsID!CInt, becsID!CFloat].staticArray);
|
|
||||||
scope(exit) gEntityManager.freeTemplate(tmpl);
|
|
||||||
|
|
||||||
EntityID id = gEntityManager.addEntity(tmpl).id;
|
|
||||||
// EntityID id2 = gEntityManager.addEntity().id;
|
|
||||||
|
|
||||||
gEntityManager.commit();
|
|
||||||
|
|
||||||
gEntityManager.removeComponents(id, [becsID!CInt, becsID!CFloat].staticArray);
|
|
||||||
|
|
||||||
gEntityManager.commit();
|
|
||||||
|
|
||||||
gEntityManager.destroy();
|
gEntityManager.destroy();
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue