diff --git a/.gitignore b/.gitignore index e0e6fff..f2e30a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,9 @@ * +!*/ !source/** !tests/** !README.md -!dub.json +!./dub.json !.gitignore !codecov.yml !skeleton.html @@ -10,6 +11,4 @@ !**/*.wrap !meson_options.txt !compile_wasm.py -!compile_android.py -!.gitlab-ci.yml -!LICENSE \ No newline at end of file +!compile_android.py \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f1d8ecc..8fa868a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,7 +23,7 @@ build_code: test_dmd_debug: stage: test - image: debian:buster-slim + image: frolvlad/alpine-glibc script: - binaries/dmd_debug_unittest artifacts: @@ -31,7 +31,7 @@ test_dmd_debug: junit: test_report.xml test_dmd: stage: test - image: debian:buster-slim + image: frolvlad/alpine-glibc script: - binaries/dmd_release_unittest artifacts: @@ -39,7 +39,7 @@ test_dmd: junit: test_report.xml test_dmd_betterC: stage: test - image: debian:buster-slim + image: frolvlad/alpine-glibc script: - binaries/dmd_debug_unittest_bc artifacts: @@ -56,7 +56,7 @@ coverage_test_dmd: - mkdir reports - binaries/dmd_unittest_cov 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: stage: build_wasm diff --git a/README.md b/README.md index 14e6d75..3f52b93 100644 --- a/README.md +++ b/README.md @@ -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.** -Package is available on [DUB package repository](https://code.dlang.org/packages/bubel-ecs). Usage: -``` - "dependencies": { - "bubel-ecs": "~>0.1.1" - } -``` - ## Design For core information about Entity-Component-System architectural pattern please read definition described at [Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system). diff --git a/compile_wasm.py b/compile_wasm.py index 7214801..3bd1afd 100644 --- a/compile_wasm.py +++ b/compile_wasm.py @@ -13,7 +13,7 @@ def compile(sources, output): if file_extension == '.d' and filename != 'package': 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: ldc_cmd += '-I' + path + ' ' @@ -33,7 +33,7 @@ def compile(sources, output): shared_flags = '' clean = 0 emc_flags = '' -ldc_flags = '' +ldc_flags = '--d-version=ECSEmscripten ' import_paths = ['source','tests'] build_tests = 0 diff --git a/demos/compile_wasm.py b/demos/compile_wasm.py index b178260..06d31ac 100644 --- a/demos/compile_wasm.py +++ b/demos/compile_wasm.py @@ -1,6 +1,7 @@ import os import ntpath import sys +import imp def compile(sources, output): files = [] @@ -13,7 +14,7 @@ def compile(sources, output): if file_extension == '.d' and filename != 'package': 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: ldc_cmd += '-I' + path + ' ' @@ -40,7 +41,7 @@ only_bc = 0 multi = 0 sources = ['tests', 'source'] 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'] for arg in sys.argv[1:]: @@ -120,9 +121,8 @@ emcc_cmd += 'demo.bc ' os.system("mkdir build") -# 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 = os.path.expandvars('$EMSDK/upstream/emscripten') + '/tools/file_packager.py build/assets.data --preload assets --js-output=build/assets.js' +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' print('Packafing files: ' + pack_cmd) os.system(pack_cmd) diff --git a/demos/meson.build b/demos/meson.build index 8a3642d..20df64c 100644 --- a/demos/meson.build +++ b/demos/meson.build @@ -19,7 +19,7 @@ sdl2_image_dep = dependency('SDL2_image') subdir('utils') # Utils library -executable('BubelECSDemos', [demos_src, external_src], +executable('decs-demos', [demos_src, external_src], include_directories : [demos_inc, external_inc], d_module_versions : versions, link_with : [ecs_lib, ecs_utils_lib], @@ -27,7 +27,7 @@ executable('BubelECSDemos', [demos_src, external_src], bindbc_loader_dep, bindbc_sdl_dep, cimgui_dep, - bubel_ecs_dep, + decs_dep, ecs_utils_dep, sdl2_dep, sdl2_image_dep, diff --git a/demos/utils/meson.build b/demos/utils/meson.build index 708fc85..de9e958 100644 --- a/demos/utils/meson.build +++ b/demos/utils/meson.build @@ -5,12 +5,12 @@ subdir('source/ecs_utils') utils_inc = include_directories('source/') # Dependencies -ecs_utils_lib = library('ECSUtils', utils_src, +ecs_utils_lib = library('ecs_utils', utils_src, include_directories : [demos_inc, external_inc, utils_inc], link_args : link_args, d_module_versions : versions, dependencies : [ - bubel_ecs_dep, + decs_dep, bindbc_loader_dep, bindbc_sdl_dep, ] diff --git a/dub.json b/dub.json index 602117d..8e2a1b3 100755 --- a/dub.json +++ b/dub.json @@ -1,11 +1,11 @@ { - "name": "bubel-ecs", - "targetName" : "BubelECS", + "name": "bubel_ecs", + "targetName" : "bubel_ecs", "authors": [ "Michał Masiukiewicz", "Dawid Masiukiewicz" ], "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", "sourcePaths" : ["source\/"], "excludedSourceFiles":[ @@ -63,7 +63,7 @@ ], "dflags": [ "-unittest", - "-cov=ctfe" + "-cov" ] }, { diff --git a/meson.build b/meson.build index 141cb25..0aff444 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('bubel-ecs', 'd', version : '0.5.0') +project('decs', 'd', version : '0.5.0') # Options betterC_opt = get_option('betterC') @@ -43,42 +43,29 @@ if betterC_opt if comp_id == 'gcc' args += ['-fno-druntime'] link_args += ['-fno-druntime'] - else + else args += '-betterC' link_args += '-betterC' endif endif -add_project_arguments(args, language : 'd') -add_project_link_arguments(link_args, language : 'd') +add_global_arguments(args, language : 'd') +add_global_link_arguments(link_args, language : 'd') # Dependencies threads_dep = dependency('threads') -d_versions = [] -deps = [] -if host_machine.cpu_family() == 'wasm32' - -else - # meson incorectly adds "-s USE_PTHREADS=1" to ldc2 invocation whe pthreads is added as dependency - # add it for non wasm builds - deps += threads_dep -endif - -ecs_lib = library('BubelECS', +ecs_lib = library('decs', src, - d_module_versions : d_versions, include_directories : [inc], ) -bubel_ecs_dep = declare_dependency( +decs_dep = declare_dependency( include_directories : [inc], link_with : ecs_lib, - dependencies : deps, + dependencies : threads_dep, ) -meson.override_dependency('bubel-ecs', bubel_ecs_dep) - # Tests if BuildTests_opt subdir('tests') diff --git a/source/bubel/ecs/atomic.d b/source/bubel/ecs/atomic.d index d8995ae..8ea43df 100644 --- a/source/bubel/ecs/atomic.d +++ b/source/bubel/ecs/atomic.d @@ -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. 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. */ 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; +} diff --git a/source/bubel/ecs/attributes.d b/source/bubel/ecs/attributes.d index 1a041d4..d094aad 100644 --- a/source/bubel/ecs/attributes.d +++ b/source/bubel/ecs/attributes.d @@ -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. */ module bubel.ecs.attributes; diff --git a/source/bubel/ecs/block_allocator.d b/source/bubel/ecs/block_allocator.d index 0ab735e..6894a17 100644 --- a/source/bubel/ecs/block_allocator.d +++ b/source/bubel/ecs/block_allocator.d @@ -3,7 +3,7 @@ It's internal code. 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. */ module bubel.ecs.block_allocator; diff --git a/source/bubel/ecs/core.d b/source/bubel/ecs/core.d index c796423..1a5e711 100644 --- a/source/bubel/ecs/core.d +++ b/source/bubel/ecs/core.d @@ -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. */ module bubel.ecs.core; @@ -94,7 +94,7 @@ static struct ECS */ mixin template Component() { - deprecated ComponentRef ref_() @nogc nothrow return + ComponentRef ref_() @nogc nothrow return { return ComponentRef(&this, becsID!(typeof(this))); } diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index 76a8a2f..cb3f752 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -1,7 +1,7 @@ /************************************************************************************************************************ 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. */ module bubel.ecs.entity; @@ -44,7 +44,7 @@ struct Entity 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.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); } - export bool hasComponent(ushort component_id) const + bool hasComponent(ushort component_id) const { EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; @@ -62,7 +62,7 @@ struct Entity return true; } - export EntityMeta getMeta() const + EntityMeta getMeta() const { EntityMeta meta; meta.block = gEntityManager.getMetaData(&this); @@ -85,7 +85,7 @@ struct EntityMeta 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; @@ -95,7 +95,7 @@ struct EntityMeta 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; 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. */ - 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; return cast(void*)(entity_data.ptr + info.tmpl_deltas[component_id]); diff --git a/source/bubel/ecs/events.d b/source/bubel/ecs/events.d index 11816a1..7cb0d0c 100644 --- a/source/bubel/ecs/events.d +++ b/source/bubel/ecs/events.d @@ -1,7 +1,3 @@ -/************************************************************************************************************************ -Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz -License: BSD 3-clause, see LICENSE file in project root folder. -*/ module bubel.ecs.events; import bubel.ecs.block_allocator; diff --git a/source/bubel/ecs/hash_map.d b/source/bubel/ecs/hash_map.d index 7ba6137..764374c 100755 --- a/source/bubel/ecs/hash_map.d +++ b/source/bubel/ecs/hash_map.d @@ -1,8 +1,4 @@ -/************************************************************************************************************************ -Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz -License: BSD 3-clause, see LICENSE file in project root folder. -*/ -module bubel.ecs.hash_map; +module bubel.ecs.hash_map; import std.traits; @@ -28,7 +24,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; @@ -336,36 +332,36 @@ nothrow: return result; } - export int byKey(scope int delegate(ref Key k) dg) + export int byKey(scope int delegate(Key k) nothrow dg) { int result; foreach (ref Key k; this) { - result = (cast(int delegate(ref Key k) nothrow @nogc)dg)(k); + result = dg(k); if (result) break; } return result; } - export int byValue(scope int delegate(ref Value v) dg) + export int byValue(scope int delegate(ref Value k) nothrow dg) { int result; foreach (ref Value v; this) { - result = (cast(int delegate(ref Value v) nothrow @nogc)dg)(v); + result = dg(v); if (result) break; } return result; } - export int byKeyValue(scope int delegate(ref Key k, ref Value v) dg) + export int byKeyValue(scope int delegate(ref Key k, ref Value v) nothrow dg) { int result; foreach (ref Key k, ref Value v; this) { - result = (cast(int delegate(ref Key k, ref Value v) nothrow @nogc)dg)(k, v); + result = dg(k, v); if (result) break; } diff --git a/source/bubel/ecs/id_manager.d b/source/bubel/ecs/id_manager.d index 2054cbb..86a611e 100644 --- a/source/bubel/ecs/id_manager.d +++ b/source/bubel/ecs/id_manager.d @@ -1,7 +1,3 @@ -/************************************************************************************************************************ -Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz -License: BSD 3-clause, see LICENSE file in project root folder. -*/ module bubel.ecs.id_manager; import bubel.ecs.entity; diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index b5220f4..e3ad7bc 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -1,7 +1,7 @@ /************************************************************************************************************************ Most important module. Almost every function is called from EntityManager. -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. */ module bubel.ecs.manager; @@ -10,6 +10,10 @@ import std.algorithm : max; import std.conv : to; import std.traits; +//import core.atomic; +//import core.stdc.stdlib : qsort; +//import core.stdc.string; + import bubel.ecs.system; //not ordered as forward reference bug workaround import bubel.ecs.block_allocator; import bubel.ecs.entity; @@ -27,8 +31,6 @@ alias SerializeVector = bubel.ecs.vector.Vector!ubyte; ///Global EntityManager used for everything. export __gshared EntityManager* gEntityManager = null; -version(D_BetterC) version = NoDRuntime; - /************************************************************************************************************************ Entity manager is responsible for everything. @@ -67,18 +69,21 @@ export struct EntityManager Initialize ECS. */ export static void initialize(uint threads_count = 1, uint page_size = 32768, - uint block_pages_count = 128) + uint block_pages_count = 128) { if (gEntityManager is null) { + //gEntityManager = Mallocator.make!EntityManager(threads_count); gEntityManager = Mallocator.make!EntityManager(threads_count, page_size, block_pages_count); with (gEntityManager) { UpdatePass* pass = Mallocator.make!UpdatePass; pass.name = Mallocator.makeArray(cast(char[]) "update"); + //pass.name = Mallocator.makeArray!char("update".length); + //pass.name[0..$] = "update"; passes.add(pass); - passes_map.add(cast(const(char)[]) pass.name, cast(ushort)(passes.length - 1)); + passes_map.add(cast(string) pass.name, cast(ushort)(passes.length - 1)); } } } @@ -86,7 +91,7 @@ export struct EntityManager /************************************************************************************************************************ Deinitialize and destroy ECS. This function release whole memory. */ - export static void destroy() nothrow @nogc + export static void destroy() { if (gEntityManager is null) return; @@ -169,8 +174,6 @@ export struct EntityManager foreach (ref system; systems) { - if (system.isAlive() == false) - continue; if (system.m_empty) { if (system.m_update) @@ -180,7 +183,7 @@ export struct EntityManager if (system.m_update is null) { if (system.m_add_entity || system.m_remove_entity - || system.m_change_entity || system.m_event_callers.length) + || system.m_change_entity || system.m_event_callers.length) { foreach (info; &entities_infos.byValue) { @@ -235,8 +238,6 @@ export struct EntityManager foreach (ref system; systems) { - if (system.isAlive() == false) - continue; foreach (caller; system.m_event_callers) { event_callers[caller.id]++; @@ -253,8 +254,6 @@ export struct EntityManager foreach (ref system; systems) { - if (system.isAlive() == false) - continue; foreach (caller; system.m_event_callers) { events[caller.id].callers[event_callers[caller.id]].callback = caller.callback; @@ -278,7 +277,7 @@ export struct EntityManager foreach (ref event; events) { qsort(event.callers.ptr, event.callers.length, - EventCaller.sizeof, &comapreEventCaller); + EventCaller.sizeof, &comapreEventCaller); } //qsort(event_callers.ptr, event_callers.length, EventInfo.sizeof, &compareUShorts); @@ -298,6 +297,7 @@ export struct EntityManager if (threads_count == 0) threads_count = 1; threads = Mallocator.makeArray!ThreadData(threads_count); + //foreach(ref thread;threads)thread = ThreadData().init; m_page_size = page_size; m_pages_in_block = block_pages_count; @@ -331,37 +331,13 @@ export struct EntityManager allocator.freeMemory(); } - /************************************************************************************************************************ - Unregister given system form EntityManager. - */ - void unregisterSystem(Sys)() - { - ushort system_id = becsID!Sys; - System* system = getSystem(system_id); - - unregisterSystem(system); - } - - /************************************************************************************************************************ - Unregister given system form EntityManager. - */ - export void unregisterSystem(System* system) nothrow @nogc - { - assert(register_state, "unregisterSystem must be called between beginRegister() and endRegister()."); - assert(system !is null, "System was not registered"); - assert(system.isAlive, "System already unregistered"); - - //disable, destroy and dispose user created system but keep name and other data - system.destroySystemData(); - } - /************************************************************************************************************************ Same as "void registerSystem(Sys)(int priority, int pass = 0)" but use pass name instead of id. */ void registerSystem(Sys)(int priority, const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); - version (NoDRuntime) + version (D_BetterC) assert(pass != ushort.max, "Update pass doesn't exist."); else assert(pass != ushort.max, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); @@ -382,8 +358,8 @@ export struct EntityManager //alias STC = ParameterStorageClass; assert(register_state, - "registerSystem must be called between beginRegister() and endRegister()."); - version (NoDRuntime) + "registerSystem must be called between beginRegister() and endRegister()."); + version (D_BetterC) assert(pass < passes.length, "Update pass doesn't exist."); else assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); @@ -392,7 +368,7 @@ export struct EntityManager enum SystemName = fullName!Sys; //enum SystemName = Sys.stringof; - System system = System(); + System system; system.m_pass = pass; // static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) @@ -432,7 +408,7 @@ export struct EntityManager // enum EventName = fullyQualifiedName!(Unqual!(EventParamType));//.stringof; ushort evt = events_map.get(cast(char[]) EventName, ushort.max); assert(evt != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing event \"" ~ EventName ~ "\"."); callers[i].callback = cast(void*)&callEventHandler!(EventParamType); @@ -475,14 +451,14 @@ export struct EntityManager bool checkExcludedComponentsSomething(Sys)() { return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, - typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); + typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); } foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); if (member == "length" || member == "thread_id" || member == "job_id" - || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { //continue; } @@ -492,7 +468,7 @@ export struct EntityManager static if (isArray!MemberType) { // Workaround. This code is never called with: not an array type, but compiler prints an error // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));//.stringof; - name = fullName!(Unqual!(typeof(MemberType.init[0]))); + name = fullName!(Unqual!(ForeachType!MemberType)); } bool is_optional; @@ -665,7 +641,7 @@ export struct EntityManager } static void allocateSystemComponents(ComponentsIndices!component_counts components_info)( - ref System system) + ref System system) { size_t req = components_info.req.length; size_t opt = components_info.optional.length; @@ -699,14 +675,14 @@ export struct EntityManager bool checkExcludedComponentsSomething(Sys)() { return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, - typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); + typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); } foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); if (member == "length" || member == "thread_id" || member == "job_id" - || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) components_info.entites_array = member; @@ -718,7 +694,7 @@ export struct EntityManager static if (isArray!MemberType) { // Workaround. This code is never called with: not an array type, but compiler prints an error // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType)); - name = fullName!(Unqual!(typeof(MemberType.init[0]))); + name = fullName!(Unqual!(ForeachType!MemberType)); //name = Unqual!(ForeachType!MemberType).stringof; } @@ -814,23 +790,23 @@ export struct EntityManager else static if (member == "length") { static assert(isIntegral!(MemberType), - "EntitiesData 'length' member must be integral type."); + "EntitiesData 'length' member must be integral type."); static assert(MemberType.sizeof > 1, - "EntitiesData 'length' member can't be byte or ubyte."); + "EntitiesData 'length' member can't be byte or ubyte."); } else static if (member == "thread_id") { static assert(isIntegral!(MemberType), - "EntitiesData 'thread_id' member must be integral type."); + "EntitiesData 'thread_id' member must be integral type."); static assert(MemberType.sizeof > 1, - "EntitiesData 'thread_id' member can't be byte or ubyte."); + "EntitiesData 'thread_id' member can't be byte or ubyte."); } else static if (member == "job_id") { static assert(isIntegral!(MemberType), - "EntitiesData 'job_id' member must be integral type."); + "EntitiesData 'job_id' member must be integral type."); static assert(MemberType.sizeof > 1, - "EntitiesData 'job_id' member can't be byte or ubyte."); + "EntitiesData 'job_id' member can't be byte or ubyte."); } else static if (!(isArray!(MemberType))) static assert(0, "EntitiesData members should be arrays of elements!"); @@ -842,9 +818,9 @@ export struct EntityManager foreach (iii, comp_info; components_info.req) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (NoDRuntime) + version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -854,9 +830,9 @@ export struct EntityManager foreach (iii, comp_info; components_info.excluded) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (NoDRuntime) + version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -866,9 +842,9 @@ export struct EntityManager foreach (iii, comp_info; components_info.optional) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (NoDRuntime) + version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -878,9 +854,9 @@ export struct EntityManager foreach (iii, comp_info; components_info.readonly) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (NoDRuntime) + version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -890,9 +866,9 @@ export struct EntityManager foreach (iii, comp_info; components_info.mutable) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (NoDRuntime) + version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -902,14 +878,14 @@ export struct EntityManager } static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, - EntitiesBlock* block, uint offset, uint entities_count, System* system) + EntitiesBlock* block, uint offset, uint entities_count, System* system) { //enum ComponentsIndices components_info = getComponentsInfo(); static if (components_info.entites_array) { __traits(getMember, input_data, components_info.entites_array) = ( - cast(Entity*) block.dataBegin())[offset .. entities_count]; + cast(Entity*) block.dataBegin())[offset .. entities_count]; } static if (hasMember!(Sys.EntitiesData, "length")) @@ -926,18 +902,17 @@ export struct EntityManager static foreach (iii, comp_info; components_info.m_req[0 .. components_info.m_req_counter]) { - __traits(getMember, input_data, comp_info.name) = ( - cast(typeof( - (typeof(__traits(getMember, Sys.EntitiesData, comp_info.name))).init[0] - )*)(cast(void*) block + info.deltas[system.m_components[iii]]) - )[offset .. entities_count]; + __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, + Sys.EntitiesData, comp_info.name)))*)( + cast(void*) block + info.deltas[system.m_components[iii]]))[offset + .. entities_count]; } static foreach (iii, comp_info; components_info.m_optional[0 .. components_info.m_optional_counter]) { if (system.m_optional_components[iii] < info.deltas.length - && info.deltas[system.m_optional_components[iii]] != 0) + && info.deltas[system.m_optional_components[iii]] != 0) { __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, Sys.EntitiesData, comp_info.name)))*)(cast( @@ -1036,7 +1011,7 @@ export struct EntityManager static if (hasMember!(Sys.EntitiesData, "thread_id")) { input_data.thread_id = cast( - typeof(input_data.thread_id)) data.thread_id; + typeof(input_data.thread_id)) data.thread_id; } static if (hasMember!(Sys.EntitiesData, "job_id")) @@ -1047,7 +1022,7 @@ export struct EntityManager //s.onUpdate(input_data); (cast(typeof(&__traits(getOverloads, s, "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)( - input_data); + input_data); } block = block.next_block; offset = 0; @@ -1117,15 +1092,15 @@ export struct EntityManager foreach (func; __traits(getOverloads, Sys, func_name)) { static if ((Parameters!(func)).length == 1 - && is(Parameters!(func)[0] == Sys.EntitiesData) - && is(ReturnType!(func) == RetType)) + && is(Parameters!(func)[0] == Sys.EntitiesData) + && is(ReturnType!(func) == RetType)) { static RetType callFunc(ref ListenerCallData data) { Sys* s = cast(Sys*) data.system.m_system_pointer; Sys.EntitiesData input_data; fillInputData(input_data, data.block.type_info, - data.block, data.begin, data.end, data.system); + data.block, data.begin, data.end, data.system); static if (is(RetTyp == void)) mixin("s." ~ func_name ~ "(input_data)"); else @@ -1146,8 +1121,8 @@ export struct EntityManager foreach (func; __traits(getOverloads, Sys, func_name)) { static if ((Parameters!(func)).length == 1 - && is(Parameters!(func)[0] == EntityInfo*) - && is(ReturnType!(func) == RetType)) + && is(Parameters!(func)[0] == EntityInfo*) + && is(ReturnType!(func) == RetType)) { static RetType callFunc(void* system_pointer, EntityInfo* info) { @@ -1182,16 +1157,14 @@ export struct EntityManager system.m_priority = priority; //(cast(Sys*) system.m_system_pointer).__ecsInitialize(); //system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; - static if (__traits(hasMember, Sys, "__becs_jobs_count")) - system.jobs = Mallocator.makeArray!(Job)(Sys.__becs_jobs_count); - else - system.jobs = Mallocator.makeArray!(Job)(32); + static if(__traits(hasMember, Sys ,"__becs_jobs_count"))system.jobs = Mallocator.makeArray!(Job)(Sys.__becs_jobs_count); + else system.jobs = Mallocator.makeArray!(Job)(32); static if (OnUpdateOverloadNum != -1) { Sys* s = cast(Sys*) system.m_system_pointer; system.m_update_delegate = cast(void delegate())&__traits(getOverloads, - s, "onUpdate")[OnUpdateOverloadNum]; + s, "onUpdate")[OnUpdateOverloadNum]; } genCompList(system, components_map); @@ -1199,10 +1172,10 @@ export struct EntityManager foreach (iii, comp_info; components_info.readonlyDeps) { ushort comp = external_dependencies_map.get(cast(const(char)[]) comp_info.type, - ushort.max); - version (NoDRuntime) + ushort.max); + version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -1213,9 +1186,9 @@ export struct EntityManager foreach (iii, comp_info; components_info.writableDeps) { ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max); - version (NoDRuntime) + version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -1257,8 +1230,7 @@ export struct EntityManager } /************************************************************************************************************************ - Return system ECS api by id. - System pointer might become invalid after registration process. It should be get once again after new systems are registered. + Return system ECS api by id */ export System* getSystem(ushort id) nothrow @nogc { @@ -1281,6 +1253,8 @@ export struct EntityManager { UpdatePass* pass = Mallocator.make!UpdatePass; pass.name = Mallocator.makeArray(cast(char[]) name); + /*pass.name = Mallocator.makeArray!char(name.length); + pass.name[0..$] = name[0..$];*/ passes.add(pass); passes_map.add(name, cast(ushort)(passes.length - 1)); return cast(ushort)(passes.length - 1); @@ -1308,8 +1282,8 @@ export struct EntityManager // } static if (hasMember!(Comp, "onDestroy") && isFunction!(Comp.onDestroy) - && is(ReturnType!(Comp.onDestroy) == void) - && Parameters!(Comp.onDestroy).length == 0) + && is(ReturnType!(Comp.onDestroy) == void) + && Parameters!(Comp.onDestroy).length == 0) { static void callDestroy(void* pointer) nothrow @nogc { @@ -1320,7 +1294,7 @@ export struct EntityManager } static if (hasMember!(Comp, "onCreate") && isFunction!(Comp.onCreate) - && is(ReturnType!(Comp.onCreate) == void) && Parameters!(Comp.onCreate).length == 0) + && is(ReturnType!(Comp.onCreate) == void) && Parameters!(Comp.onCreate).length == 0) { static void callCreate(void* pointer) nothrow @nogc { @@ -1336,8 +1310,7 @@ export struct EntityManager info.size = Comp.sizeof; info.alignment = Comp.alignof; //8; info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof); - __gshared Comp init_memory; - memcpy(info.init_data.ptr, &init_memory, Comp.sizeof); + *cast(Comp*) info.init_data.ptr = Comp.init; // = Comp(); ushort comp_id = components_map.get(cast(char[]) ComponentName, ushort.max); if (comp_id < components.length) @@ -1366,7 +1339,7 @@ export struct EntityManager // } static if (hasMember!(Ev, "onDestroy") && isFunction!(Ev.onDestroy) - && is(ReturnType!(Ev.onDestroy) == void) && Parameters!(Ev.onDestroy).length == 0) + && is(ReturnType!(Ev.onDestroy) == void) && Parameters!(Ev.onDestroy).length == 0) { static void callDestroy(void* pointer) { @@ -1400,10 +1373,10 @@ export struct EntityManager Sys* s; static assert(isDelegate!func, "Function must be delegate."); static assert(__traits(hasMember, Sys, "EntitiesData"), - "Can't call function with system which hasn't EntitesData structure."); + "Can't call function with system which hasn't EntitesData structure."); ///TODO: make possibly to call function to group without system with onUpdate function 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."); FIXME: It's lead to crash on android build @@ -1411,9 +1384,7 @@ export struct EntityManager System* system = getSystem(becsID!Sys); assert(system != null, - "System must be registered in EntityManager before any funcion can be called."); - assert(system.isAlive(), "System must be alive (registered) in order to call entities function on its entities"); - + "System must be registered in EntityManager before any funcion can be called."); if (!system.m_any_system_caller) return; @@ -1455,7 +1426,7 @@ export struct EntityManager foreach (info; caller.infos) { CallData data = CallData(caller.system_id, sys, info, - sys.m_update_delegate); + sys.m_update_delegate); data.update(); } } @@ -1477,7 +1448,7 @@ export struct EntityManager assert(!register_state); assert(pass < passes.length); assert(m_dispatch_jobs, - "Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc()."); + "Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc()."); Vector!CallData tmp_datas; tmp_datas.reserve(8); @@ -1490,7 +1461,7 @@ export struct EntityManager void nextJob() { CallData[] callers = m_call_data_allocator.getCallData( - cast(uint) tmp_datas.length); + cast(uint) tmp_datas.length); //callers[0 .. $] = tmp_datas[0 .. $]; memcpy(callers.ptr, &tmp_datas[0], CallData.sizeof * tmp_datas.length); tmp_datas.clear(); @@ -1545,7 +1516,7 @@ export struct EntityManager //if this info will fill job if ((blocks_count - 1) * info.max_entities + entities_count - + info.last_block.entities_count - first_elem >= entities_per_job) + + info.last_block.entities_count - first_elem >= entities_per_job) { int reamaining_entities = (entities_per_job - entities_count - ( first_block.entities_count - first_elem)); @@ -1566,9 +1537,9 @@ export struct EntityManager assert(entities_per_job == full_blocks_count * info.max_entities + entities_count + ( first_block.entities_count - first_elem)); CallData data = CallData(caller.system_id, sys, - info, sys.m_update_delegate, first_block, - cast(ushort)(full_blocks_count + 1), - cast(ushort) first_elem, 0); + info, sys.m_update_delegate, first_block, + cast(ushort)(full_blocks_count + 1), + cast(ushort) first_elem, 0); tmp_datas.add(data); first_elem = 0; blocks_count -= full_blocks_count + 1; @@ -1577,14 +1548,14 @@ export struct EntityManager else { entities_count += full_blocks_count * info.max_entities + ( - first_block.entities_count - first_elem); // - first_elem; + first_block.entities_count - first_elem); // - first_elem; uint last_elem = entities_per_job - entities_count; // + first_elem - 1; assert(last_elem > 0); assert(last_elem <= block.entities_count); CallData data = CallData(caller.system_id, sys, - info, sys.m_update_delegate, first_block, - cast(ushort)(full_blocks_count + 2), - cast(ushort) first_elem, cast(ushort) last_elem); + info, sys.m_update_delegate, first_block, + cast(ushort)(full_blocks_count + 2), + cast(ushort) first_elem, cast(ushort) last_elem); tmp_datas.add(data); first_elem = last_elem; blocks_count -= full_blocks_count + 1; @@ -1601,8 +1572,8 @@ export struct EntityManager uint last_elem = entities_per_job - entities_count; assert(last_elem > 0); CallData data = CallData(caller.system_id, sys, - info, sys.m_update_delegate, first_block, 1, - cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); + info, sys.m_update_delegate, first_block, 1, + cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); tmp_datas.add(data); first_elem += last_elem; assert(first_elem <= first_block.entities_count); @@ -1622,7 +1593,7 @@ export struct EntityManager { //take whole info blocks CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate, - first_block, cast(ushort) blocks_count, cast(ushort) first_elem); + first_block, cast(ushort) blocks_count, cast(ushort) first_elem); tmp_datas.add(data); entities_count += (blocks_count - 1) * info.max_entities + info.last_block.entities_count - first_elem; @@ -1637,7 +1608,7 @@ export struct EntityManager } export void setMultithreadingCallbacks(void delegate(JobGroup) dispatch_callback, - uint delegate() get_id_callback) + uint delegate() get_id_callback) { m_dispatch_jobs = cast(void delegate(JobGroup jobs) nothrow @nogc) dispatch_callback; m_thread_id_func = cast(uint delegate() nothrow @nogc) get_id_callback; @@ -1702,7 +1673,7 @@ export struct EntityManager if (components[comp].size == 0) continue; 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); } } else @@ -1713,8 +1684,8 @@ export struct EntityManager if (components[comp].size == 0) continue; memcpy(cast(void*) temp.entity_data.ptr + info.tmpl_deltas[comp], - cast(void*) block + info.deltas[comp] + components[comp].size * index, - components[comp].size); + cast(void*) block + info.deltas[comp] + components[comp].size * index, + components[comp].size); } } @@ -1763,7 +1734,7 @@ export struct EntityManager if (components[comp].size == 0) continue; 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); } return temp; @@ -1779,18 +1750,18 @@ export struct EntityManager remove_components_ids = array of components to remove from base template */ export EntityTemplate* allocateTemplate(EntityTemplate* base_tmpl, - ushort[] components_ids, ushort[] remove_components_ids = null) + ushort[] components_ids, ushort[] remove_components_ids = null) { size_t len = base_tmpl.info.components.length + components_ids.length; ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * len))[0 .. len]; memcpy(ids.ptr, base_tmpl.info.components.ptr, - ushort.sizeof * base_tmpl.info.components.length); + ushort.sizeof * base_tmpl.info.components.length); memcpy(ids.ptr + base_tmpl.info.components.length, components_ids.ptr, - ushort.sizeof * components_ids.length); + ushort.sizeof * components_ids.length); qsort(ids.ptr, ids.length, ushort.sizeof, &compareUShorts); qsort(remove_components_ids.ptr, remove_components_ids.length, - ushort.sizeof, &compareUShorts); + ushort.sizeof, &compareUShorts); { uint k = 0; uint j = 1; @@ -1830,20 +1801,20 @@ export struct EntityManager foreach (comp; info.components) { if (comp < base_tmpl.info.tmpl_deltas.length - && base_tmpl.info.tmpl_deltas[comp] != ushort.max) //copy data from base component - { + && 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], - base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp], - components[comp].size); + base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp], + components[comp].size); } else //fill with default data { if (components[comp].size == 0) continue; 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); } } @@ -1858,7 +1829,6 @@ export struct EntityManager */ export EntityTemplate* allocateTemplate(EntityTemplate* copy_tmpl) { - assert(copy_tmpl, "copy_tmpl can't be null"); EntityTemplate* tmpl = Mallocator.make!EntityTemplate; tmpl.info = copy_tmpl.info; tmpl.entity_data = Mallocator.makeArray(copy_tmpl.entity_data); @@ -1873,86 +1843,76 @@ export struct EntityManager */ export EntityInfo* getEntityInfo(ushort[] ids) { - if(ids.length == 0)ids = null; EntityInfo* info = entities_infos.get(ids, null); if (info is null) { info = Mallocator.make!EntityInfo; + info.components = Mallocator.makeArray(ids); + /*info.components = Mallocator.makeArray!ushort(ids.length); + info.components[0 .. $] = ids[0 .. $];*/ + info.deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1); + info.size = EntityID.sizeof; info.alignment = EntityID.alignof; - if(ids is null) + info.tmpl_deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1, ushort.max); + uint components_size = EntityID.sizeof; + + foreach (i, id; ids) { - uint block_memory = cast(uint)( - m_page_size - EntitiesBlock.sizeof - info.size); - uint entites_in_block = block_memory / info.size; - info.max_entities = cast(ushort) entites_in_block; + info.alignment = max(info.alignment, components[id].alignment); + alignNum(info.size, components[id].alignment); + info.tmpl_deltas[id] = info.size; + info.size += components[id].size; + components_size += components[id].size; } - else - { - uint components_size = EntityID.sizeof; + alignNum(info.size, info.alignment); - info.components = Mallocator.makeArray(ids); - info.deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1); - info.tmpl_deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1, ushort.max); - - foreach (i, id; ids) - { - info.alignment = max(info.alignment, components[id].alignment); - alignNum(info.size, components[id].alignment); - info.tmpl_deltas[id] = info.size; - info.size += components[id].size; - components_size += components[id].size; - } - alignNum(info.size, info.alignment); - - uint block_memory = cast(uint)( + uint block_memory = cast(uint)( m_page_size - EntitiesBlock.sizeof - (info.size - components_size)); - //uint entity_comps_size = EntityID.sizeof; - uint mem_begin = EntitiesBlock.sizeof; + //uint entity_comps_size = EntityID.sizeof; + uint mem_begin = EntitiesBlock.sizeof; - uint entites_in_block = block_memory / info.size; //entity_comps_size; - info.max_entities = cast(ushort) entites_in_block; - ushort current_delta = cast(ushort)(mem_begin + entites_in_block * EntityID.sizeof); + uint entites_in_block = block_memory / info.size; //entity_comps_size; + info.max_entities = cast(ushort) entites_in_block; + ushort current_delta = cast(ushort)(mem_begin + entites_in_block * EntityID.sizeof); - foreach (i, id; ids) - { - if (current_delta == 0) - current_delta = ushort.max; - alignNum(current_delta, components[id].alignment); - info.deltas[id] = cast(ushort) current_delta; - current_delta += entites_in_block * components[id].size; - } - - info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); - info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); - - foreach (comp; info.components) - { - info.comp_add_info[comp] = info; - info.comp_rem_info[comp] = null; - } + foreach (i, id; ids) + { + if (current_delta == 0) + current_delta = ushort.max; + alignNum(current_delta, components[id].alignment); + info.deltas[id] = cast(ushort) current_delta; + current_delta += entites_in_block * components[id].size; } info.systems = Mallocator.makeArray!bool(systems.length); foreach (i, ref system; systems) { - if (system.isAlive() == false) - continue; if (system.m_empty) continue; if (system.m_update is null) { if (system.m_add_entity || system.m_remove_entity - || system.m_change_entity || system.m_event_callers.length) + || system.m_change_entity || system.m_event_callers.length) connectListenerToEntityInfo(*info, cast(uint) i); continue; } addSystemCaller(*info, cast(uint) i); } + info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(gEntityManager.components.length); + //info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(gEntityManager.components.length); + info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); + + foreach (comp; info.components) + { + info.comp_add_info[comp] = info; + info.comp_rem_info[comp] = null; + } + entities_infos.add(info.components, info); generateListeners(info); @@ -2103,9 +2063,7 @@ export struct EntityManager } ///call Custom Entity Filter test if function exists - if (system.m_filter_entity && !(cast(bool function(void* system_pointer, EntityInfo* info) @nogc nothrow) system - .m_filter_entity)(system, &entity)) - return; + if(system.m_filter_entity && !(cast(bool function(void* system_pointer, EntityInfo* info) @nogc nothrow)system.m_filter_entity)(system, &entity))return; entity.systems[system_id] = true; } @@ -2150,8 +2108,7 @@ export struct EntityManager System* system = &systems[system_id]; connectListenerToEntityInfo(info, system_id); - if (!info.systems[system_id]) - return; + if(!info.systems[system_id])return; uint index = 0; for (; index < passes[system.m_pass].system_callers.length; index++) @@ -2260,7 +2217,7 @@ export struct EntityManager if (comp_size == 0) continue; 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); } new_block.entities_count++; @@ -2274,7 +2231,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count); + new_block.entities_count - 1, new_block.entities_count); } } } @@ -2286,7 +2243,7 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count, del_ids); + new_block.entities_count - 1, new_block.entities_count, del_ids); } } } @@ -2437,7 +2394,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count); + new_block.entities_count - 1, new_block.entities_count); } } } @@ -2449,7 +2406,7 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count, new_ids); + new_block.entities_count - 1, new_block.entities_count, new_ids); } } } @@ -2467,11 +2424,29 @@ export struct EntityManager void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc { const uint num = Components.length; + /*ushort[num] new_ids; + + static foreach (i, comp; Components) + { + new_ids[i] = comp.component_id; + } + + ThreadData* data = &threads[threadID]; + data.changeEntitiesList.add(cast(ubyte) 1u); + data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]); + data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]); + data.changeEntitiesList.add(cast(ubyte[]) new_ids); + static foreach (i, comp; comps) + { + data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); + }*/ + + //__addComponents(entity_id, new_ids, pointers); ComponentRef[num] _comps; static foreach (i, comp; comps) { - _comps[i] = ComponentRef(&comp, becsID!(typeof(comp))); + _comps[i] = comp.ref_; } addComponents(entity_id, _comps); @@ -2492,8 +2467,13 @@ export struct EntityManager { if (components[ref_.component_id].size != 0) data.changeEntitiesList.add( - (cast(ubyte*) ref_.ptr)[0 .. components[ref_.component_id].size]); + (cast(ubyte*) ref_.ptr)[0 .. components[ref_.component_id].size]); } + /*data.changeEntitiesList.add(cast(ubyte[]) new_ids); + static foreach (i, comp; comps) + { + data.changeEntitiesList.add((cast(ubyte*)&comp)[0 .. comp.sizeof]); + }*/ } /************************************************************************************************************************ @@ -2542,12 +2522,12 @@ export struct EntityManager ushort size = components[comp].size; if (size != 0) memcpy(cast(void*) new_block + info.deltas[comp] + new_id * size, - cast(void*) block + info.deltas[comp] + size * index, size); + cast(void*) block + info.deltas[comp] + size * index, size); if (components[comp].create_callback) { components[comp].create_callback( - cast(void*) new_block + info.deltas[comp] + new_id * size); + cast(void*) new_block + info.deltas[comp] + new_id * size); } } @@ -2566,7 +2546,7 @@ export struct EntityManager use you should save ID instead of pointer. Params: - tmpl = pointer entity template allocated by EntityManager. Can be null in which case empty entity would be added (entity without components) + tmpl = pointer entity template allocated by EntityManager. */ export Entity* addEntity(EntityTemplate* tmpl) { @@ -2578,14 +2558,12 @@ export struct EntityManager use you should save ID instead of pointer. Params: - tmpl = pointer entity template allocated by EntityManager. Can be null in which case empty entity would be added (entity without components) + tmpl = pointer entity template allocated by EntityManager. replacement = list of components references to used. Memory form list replace data from template inside new entity. Should be used only for data which vary between most entities (like 3D position etc.) */ export Entity* addEntity(EntityTemplate* tmpl, ComponentRef[] replacement) { - EntityInfo* info = void; - if(tmpl)info = tmpl.info; - else info = getEntityInfo(null); + EntityInfo* info = tmpl.info; ushort index = 0; EntitiesBlock* block; @@ -2606,7 +2584,7 @@ export struct EntityManager uint size = components[comp].size; if (size != 0) 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); } foreach (comp; replacement) @@ -2628,7 +2606,7 @@ export struct EntityManager if (components[comp].create_callback) { components[comp].create_callback( - cast(void*) block + info.deltas[comp] + id * components[comp].size); + cast(void*) block + info.deltas[comp] + id * components[comp].size); } } @@ -2763,7 +2741,7 @@ export struct EntityManager } private void removeEntityNoID(Entity* entity, EntitiesBlock* block, - bool call_destructors = false) nothrow @nogc + bool call_destructors = false) nothrow @nogc { EntityInfo* info = block.type_info; @@ -2895,7 +2873,7 @@ export struct EntityManager } private static void callAddEntityListener(System* system, EntityInfo* info, - EntitiesBlock* block, int begin, int end) @nogc nothrow + EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; data.system = system; @@ -2906,7 +2884,7 @@ export struct EntityManager } private void callRemoveEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, - int end) @nogc nothrow + int end) @nogc nothrow { foreach (listener; info.remove_listeners) { @@ -2916,7 +2894,7 @@ export struct EntityManager } private static void callRemoveEntityListener(System* system, - EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow + EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; data.system = system; @@ -2927,7 +2905,7 @@ export struct EntityManager } private void callChangeEntityListener(System* system, EntityInfo* info, - EntitiesBlock* block, int begin, int end, ushort[] ch_ids) @nogc nothrow + EntitiesBlock* block, int begin, int end, ushort[] ch_ids) @nogc nothrow { int i = 0; int j = 0; @@ -3081,7 +3059,7 @@ export struct EntityManager foreach (caller; events[i].callers) { if (call_data.block.type_info.systems[caller.system.m_id] == false - || !caller.system.enabled || !caller.system.willExecute) + || !caller.system.enabled || !caller.system.willExecute) continue; call_data.system_pointer = caller.system.m_system_pointer; (cast(void function(ref EventCallData) nothrow @nogc) caller @@ -3144,11 +3122,9 @@ export struct EntityManager foreach (ref system; systems) { - if (system.isAlive() == false) - continue; if (system.enabled && system.m_begin) system.m_execute = (cast(bool function(void*)) system.m_begin)( - system.m_system_pointer); + system.m_system_pointer); } } @@ -3160,9 +3136,6 @@ export struct EntityManager foreach (ref system; systems) { - if (system.isAlive() == false) - continue; - if (system.enabled && system.m_end) (cast(void function(void*)) system.m_end)(system.m_system_pointer); } @@ -3276,6 +3249,8 @@ export struct EntityManager if (index > 0) { caller.exclusion = Mallocator.makeArray(exclusion[0 .. index]); + /*caller.exclusion = Mallocator.makeArray!(SystemCaller*)(index); + caller.exclusion[0..$] = exclusion[0 .. index];*/ } else caller.exclusion = null; @@ -3301,7 +3276,7 @@ export struct EntityManager } qsort(pass.system_callers.array.ptr, pass.system_callers.length, - (SystemCaller*).sizeof, &compareSystems); + (SystemCaller*).sizeof, &compareSystems); foreach (i, caller; pass.system_callers) caller.job_group.id = cast(uint) i; @@ -3323,6 +3298,8 @@ export struct EntityManager if (index > 0) { caller.dependencies = Mallocator.makeArray(exclusion[0 .. index]); + /*caller.dependencies = Mallocator.makeArray!(SystemCaller*)(index); + caller.dependencies[0..$] = exclusion[0 .. index];*/ caller.job_group.dependencies = Mallocator.makeArray!(JobGroup*)(index); foreach (j, dep; caller.dependencies) @@ -3357,16 +3334,6 @@ export struct EntityManager export ~this() nothrow @nogc { } - - export void opAssign(ComponentInfo c) - { - size = c.size; - alignment = c.alignment; - init_data = c.init_data; - destroy_callback = c.destroy_callback; - create_callback = c.create_callback; - } - ///Component size ushort size; ///Component data alignment @@ -3438,7 +3405,7 @@ export struct EntityManager if (comp_add_info.length <= id) { EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)( - gEntityManager.components.length); + gEntityManager.components.length); if (comp_add_info !is null) { //new_infos[0 .. comp_add_info.length] = comp_add_info[0 .. $]; @@ -3472,7 +3439,7 @@ export struct EntityManager break; } } - if (components.length == 0 || id > components[$ - 1]) + if (id > components[$ - 1]) ids[len++] = id; assert(len == components.length + 1); @@ -3483,7 +3450,7 @@ export struct EntityManager return new_info; } - EntityInfo* getNewInfoRemove(ushort id) return + EntityInfo* getNewInfoRemove(ushort id) return { /*if (comp_rem_info.length <= id) { @@ -3526,8 +3493,7 @@ export struct EntityManager export bool hasComponent(ushort component_id) { - if (component_id >= deltas.length || !deltas[component_id]) - return false; + if(component_id >= deltas.length || !deltas[component_id])return false; return true; } @@ -3596,7 +3562,7 @@ export struct EntityManager struct EntitiesBlock { ///return pointer to first element in block - export void* dataBegin() nothrow @nogc pure return + export void* dataBegin() nothrow @nogc pure return { ushort dif = EntitiesBlock.sizeof; return cast(void*)&this + dif; @@ -3679,6 +3645,7 @@ export struct EntityManager export void execute() nothrow @nogc { + //gEntityManager.getThreadID(); foreach (ref caller; callers) { caller.thread_id = gEntityManager.threadID(); @@ -3723,32 +3690,32 @@ export struct EntityManager struct ThreadData { - ref Vector!EntityID entitesToRemove() @nogc nothrow return + ref Vector!EntityID entitesToRemove() @nogc nothrow return { return entities_to_remove[data_index]; } - ref SimpleVector changeEntitiesList() @nogc nothrow return + ref SimpleVector changeEntitiesList() @nogc nothrow return { return change_entities_list[data_index]; } - ref Vector!(EntityInfo*) infosToUpdate() @nogc nothrow return + ref Vector!(EntityInfo*) infosToUpdate() @nogc nothrow return { return infos_to_update[data_index]; } - ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow return + ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow return { return entities_to_remove[1 - data_index]; } - ref SimpleVector changeEntitiesListPrev() @nogc nothrow return + ref SimpleVector changeEntitiesListPrev() @nogc nothrow return { return change_entities_list[1 - data_index]; } - ref Vector!(EntityInfo*) infosToUpdatePrev() @nogc nothrow return + ref Vector!(EntityInfo*) infosToUpdatePrev() @nogc nothrow return { return infos_to_update[1 - data_index]; } @@ -3884,5 +3851,5 @@ export struct EntityManager return ret; } } - + } diff --git a/source/bubel/ecs/package.d b/source/bubel/ecs/package.d index e2d8893..51da325 100644 --- a/source/bubel/ecs/package.d +++ b/source/bubel/ecs/package.d @@ -1,7 +1,3 @@ -/************************************************************************************************************************ -Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz -License: BSD 3-clause, see LICENSE file in project root folder. -*/ module ecs; public import bubel.ecs.core; diff --git a/source/bubel/ecs/simple_vector.d b/source/bubel/ecs/simple_vector.d index 2fdaf31..acf01ee 100644 --- a/source/bubel/ecs/simple_vector.d +++ b/source/bubel/ecs/simple_vector.d @@ -1,7 +1,3 @@ -/************************************************************************************************************************ -Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz -License: BSD 3-clause, see LICENSE file in project root folder. -*/ module bubel.ecs.simple_vector; import bubel.ecs.std; diff --git a/source/bubel/ecs/std.d b/source/bubel/ecs/std.d index 8a3e207..d99a05c 100644 --- a/source/bubel/ecs/std.d +++ b/source/bubel/ecs/std.d @@ -2,14 +2,16 @@ It's internal code! 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. */ module bubel.ecs.std; +version (Emscripten) version = ECSEmscripten; + import std.traits; -version (Emscripten) +version (ECSEmscripten) { 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) 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* malloc(size_t size) @nogc nothrow @system; @@ -54,7 +60,7 @@ else public import core.stdc.stdlib : qsort; } -version (Emscripten) +version (ECSEmscripten) { } else version (Windows) @@ -83,7 +89,7 @@ else version (Posix) import core.sys.posix.stdlib : posix_memalign; } -version (Emscripten) +version (ECSEmscripten) { private const uint max_alloca = 10000; private __gshared byte[max_alloca] alloca_array; @@ -288,7 +294,7 @@ static struct Mallocator posix_memalign(&ret, alignment, length); //ret = aligned_alloc(alignment, length); else version (Windows) ret = _aligned_malloc(length, alignment); - else version (Emscripten) + else version (ECSEmscripten) posix_memalign(&ret, alignment, length); //malloc(length); else static assert(0, "Unimplemented platform!"); @@ -335,7 +341,7 @@ static struct Mallocator free(cast(void*) object); else version (Windows) _aligned_free(cast(void*) object); - else version (Emscripten) + else version (ECSEmscripten) free(cast(void*) object); else static assert(0, "Unimplemented platform!"); @@ -345,7 +351,7 @@ static struct Mallocator struct Mutex { - version (Emscripten) + version (ECSEmscripten) { void initialize() nothrow @nogc { diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index 310b53a..e571e8b 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -1,7 +1,7 @@ /************************************************************************************************************************ 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. */ module bubel.ecs.system; @@ -13,14 +13,14 @@ import bubel.ecs.manager; System contain data required to proper glue EntityManager with Systems. System callbacks: $(LIST - * void onUpdate(EntitiesData); + * void onUpdate(EntitesData); * void onEnable() - called inside system.enable() function * void onDisable() - called inside system.disable() function * bool onBegin() - called inside manager.begin() * void onEnd() - called inside manager.end() * void onCreate() - called after registration inside registerSystem function * 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 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 @@ -89,100 +89,38 @@ struct System 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: - ///destory system. Dispose all data - 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 + void destroy() { import bubel.ecs.std : Mallocator; disable(); if (m_destroy) - { - (cast(void function(void*) nothrow @nogc) m_destroy)(m_system_pointer); - m_destroy = null; - } + (cast(void function(void*)) m_destroy)(m_system_pointer); + if (m_name) + Mallocator.dispose(m_name); if (m_components) - { Mallocator.dispose(m_components); - m_components = null; - } if (m_excluded_components) - { Mallocator.dispose(m_excluded_components); - m_excluded_components = null; - } if (m_optional_components) - { Mallocator.dispose(m_optional_components); - m_optional_components = null; - } if (jobs) - { Mallocator.dispose(jobs); - jobs = null; - } if (m_read_only_components) - { Mallocator.dispose(m_read_only_components); - m_read_only_components = null; - } if (m_writable_components) - { Mallocator.dispose(m_writable_components); - m_writable_components = null; - } if (m_readonly_dependencies) - { Mallocator.dispose(m_readonly_dependencies); - m_readonly_dependencies = null; - } if (m_writable_dependencies) - { Mallocator.dispose(m_writable_dependencies); - m_writable_dependencies = null; - } if (m_event_callers) - { Mallocator.dispose(m_event_callers); - m_event_callers = null; - } if (m_system_pointer) - { Mallocator.dispose(m_system_pointer); - m_system_pointer = null; - } } struct EventCaller diff --git a/source/bubel/ecs/traits.d b/source/bubel/ecs/traits.d index 79901db..3af4b86 100644 --- a/source/bubel/ecs/traits.d +++ b/source/bubel/ecs/traits.d @@ -1,7 +1,3 @@ -/************************************************************************************************************************ -Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz -License: BSD 3-clause, see LICENSE file in project root folder. -*/ module bubel.ecs.traits; import std.traits; @@ -11,11 +7,8 @@ import std.traits; */ ref ushort becsID(T)() { - /// Embed id in struct so export can be added to variable definition - static struct LocalStruct { - export __gshared ushort id = ushort.max; - } - return LocalStruct.id; + __gshared ushort id = ushort.max; + return id; } /************************************************************************************************************************ @@ -73,7 +66,7 @@ static string attachParentName(alias T, string str)() { return attachParentName!(parent, parent_str[7 .. $] ~ '.' ~ str); } - else return parent_str[7 .. $] ~ '.' ~ str; + else return parent_str[8 .. $] ~ '.' ~ str; } else static if(parent_str[0..8] == "package ") { diff --git a/source/bubel/ecs/vector.d b/source/bubel/ecs/vector.d index 6cf6274..019673b 100644 --- a/source/bubel/ecs/vector.d +++ b/source/bubel/ecs/vector.d @@ -1,7 +1,3 @@ -/************************************************************************************************************************ -Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz -License: BSD 3-clause, see LICENSE file in project root folder. -*/ module bubel.ecs.vector; import core.bitop; diff --git a/tests/basic.d b/tests/basic.d index ea54382..aa730ea 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -16,7 +16,7 @@ else import std.array : staticArray; struct CInt { - // mixin ECS.Component; + mixin ECS.Component; alias value this; @@ -25,7 +25,7 @@ struct CInt struct CFloat { - // mixin ECS.Component; + mixin ECS.Component; alias value this; @@ -34,7 +34,7 @@ struct CFloat struct CDouble { - // mixin ECS.Component; + mixin ECS.Component; alias value this; @@ -43,7 +43,7 @@ struct CDouble struct CLong { - // mixin ECS.Component; + mixin ECS.Component; alias value this; @@ -52,7 +52,7 @@ struct CLong struct CShort { - // mixin ECS.Component; + mixin ECS.Component; alias value this; @@ -61,7 +61,7 @@ struct CShort struct CUnregistered { - // mixin ECS.Component; + mixin ECS.Component; alias value this; @@ -70,7 +70,7 @@ struct CUnregistered struct CFlag { - // mixin ECS.Component; + mixin ECS.Component; } struct LongAddSystem @@ -113,31 +113,6 @@ struct EmptySystem 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() { becsID!CUnregistered = ushort.max; @@ -207,18 +182,17 @@ unittest assert(*entity2.getComponent!CInt == 2); assert(*entity2.getComponent!CFloat == 2.0); - CInt int1 = CInt(10); - CLong long1 = CLong(); - CFlag flag1 = CFlag(); - Entity* entity3 = gEntityManager.addEntity(tmpl_, [ComponentRef(&int1, becsID(int1)), ComponentRef(&long1, becsID(long1)), ComponentRef(&flag1, becsID(flag1))].staticArray); + //CInt cint = CInt(10); + //CLong clong; + //Entity* entity3 = gEntityManager.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray); + Entity* entity3 = gEntityManager.addEntity(tmpl_, [CInt(10).ref_, CLong().ref_, CFlag().ref_].staticArray); EntityID id = entity3.id; assert(entity3.hasComponent(becsID!CInt)); assert(entity3.hasComponent(becsID!CFloat)); assert(*entity3.getComponent!CInt == 10); assert(*entity3.getComponent!CFloat == 2.0); - CShort short1 = CShort(2); - gEntityManager.addComponents(entity3.id, [ComponentRef(&flag1, becsID(flag1)),ComponentRef(&short1, becsID(short1))].staticArray); + gEntityManager.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); gEntityManager.commit(); entity3 = gEntityManager.getEntity(id); assert(entity3.getComponent!CInt); @@ -239,7 +213,7 @@ unittest assert(*entity3.getComponent!CInt == 10); assert(*entity3.getComponent!CFloat == 2.0); - gEntityManager.addComponents(entity3.id, [ComponentRef(&flag1, becsID(flag1)),ComponentRef(&short1, becsID(short1))].staticArray); + gEntityManager.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_].staticArray); gEntityManager.removeComponents(entity3.id, [becsID!CUnregistered].staticArray); gEntityManager.commit(); entity3 = gEntityManager.getEntity(id); @@ -257,8 +231,7 @@ unittest gEntityManager.endRegister(); - CUnregistered unregistered1 = CUnregistered(4); - gEntityManager.addComponents(entity3.id, [ComponentRef(&unregistered1, becsID(unregistered1))].staticArray); + gEntityManager.addComponents(entity3.id, [CUnregistered(4).ref_].staticArray); gEntityManager.commit(); entity3 = gEntityManager.getEntity(id); assert(entity3.getComponent!CUnregistered); @@ -268,82 +241,7 @@ unittest gEntityManager.commit(); entity3 = gEntityManager.getEntity(id); 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 diff --git a/tests/bugs.d b/tests/bugs.d index 10a3c62..3c5f426 100644 --- a/tests/bugs.d +++ b/tests/bugs.d @@ -119,12 +119,8 @@ unittest gEntityManager.endRegister(); EntityTemplate* tmpl = gEntityManager.allocateTemplate([becsID!CInt, becsID!CLong].staticArray); - - CLong clong = CLong(10); - CInt cint = CInt(6); - CInt cint2 = CInt(4); - EntityID id = gEntityManager.addEntity(tmpl,[ComponentRef(&clong, becsID(clong)), ComponentRef(&cint, becsID(cint))].staticArray).id; - EntityID id2 = gEntityManager.addEntity(tmpl,[ComponentRef(&cint2, becsID(cint2))].staticArray).id; + EntityID id = gEntityManager.addEntity(tmpl,[CLong(10).ref_, CInt(6).ref_].staticArray).id; + EntityID id2 = gEntityManager.addEntity(tmpl,[CInt(4).ref_].staticArray).id; gEntityManager.freeTemplate(tmpl); gEntityManager.commit(); @@ -142,34 +138,5 @@ unittest gEntityManager.update(); 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(); } \ No newline at end of file diff --git a/tests/meson.build b/tests/meson.build index ff1a3a1..cfccaa7 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -10,7 +10,7 @@ tests_src = files( 'vector.d' ) -exe = executable('BubelECSTests', +exe = executable('decs-tests', tests_src, include_directories : [inc, include_directories('..')], d_args : args,