Merge branch 'master' of https://gitlab.com/Mergul/bubel-ecs.git into Demos

# Conflicts:
#	demos/compile_wasm.py
#	source/ecs/manager.d
This commit is contained in:
Mergul 2020-05-01 21:36:21 +02:00
commit b21e2b0109
24 changed files with 816 additions and 249 deletions

2
.gitignore vendored
View file

@ -5,6 +5,8 @@
!README.md !README.md
!./dub.json !./dub.json
!.gitignore !.gitignore
!codecov.yml
!skeleton.html
!meson.build !meson.build
!meson_options.txt !meson_options.txt
!compile_wasm.py !compile_wasm.py

View file

@ -1,9 +1,91 @@
test_dmd: stages:
stage: test - build
image: mmcomando/ecs_enviroment - test
- testcov
- build_emscripten
- deploy
build_code:
stage: build
image: "registry.gitlab.com/mergul/bubel-ecs:latest"
script: script:
- source $(/script/dlang/install.sh dmd -a) && dmd --version - mkdir build
- source $(/script/dlang/install.sh dmd -a) && dub -c unittest-runner -b unittest - /bin/bash /compile_ecs.sh
- cp artifacts/* build/
- cp -r public build/
artifacts:
expire_in: 1h
paths:
- build
rules:
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
when: always
- when: always
allow_failure: true
test_dmd_debug:
stage: test
image: frolvlad/alpine-glibc
script:
- build/dmd_debug_unittest
artifacts: artifacts:
reports: reports:
junit: test_report.xml junit: test_report.xml
test_dmd:
stage: test
image: frolvlad/alpine-glibc
script:
- build/dmd_release_unittest
artifacts:
reports:
junit: test_report.xml
test_dmd_betterC:
stage: test
image: frolvlad/alpine-glibc
script:
- build/dmd_release_unittest_bc
artifacts:
reports:
junit: test_report.xml
coverage_test_dmd:
stage: testcov
image: "registry.gitlab.com/mergul/bubel-ecs/curl:latest"
needs: ["test_dmd_debug", "build_code"]
dependencies:
- build_code
script:
- mkdir reports
- build/dmd_unittest_cov
after_script:
- bash <(curl -s https://codecov.io/bash) -s reports -t 1a0c0169-a721-4085-8252-fed4755dcd8c
emscripten:
stage: build_emscripten
image: "registry.gitlab.com/mergul/bubel-ecs/emscripten:latest"
dependencies:
- build_code
script:
- /bin/bash /build.sh
rules:
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
when: always
artifacts:
expire_in: 1h
paths:
- wasm
pages:
stage: deploy
image: frolvlad/alpine-glibc
script:
- mkdir public
- cp -r wasm/* public/
- cp -r build/public/* public/
rules:
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
when: always
artifacts:
expire_in: 1h
paths:
- public

29
LICENSE Normal file
View file

@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2020, Dawid Masiukiewicz
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,3 +1,5 @@
# Dynamic Entity Component System # Dynamic Entity Component System
[![pipeline status](https://gitlab.com/Mergul/bubel-ecs/badges/master/pipeline.svg)](https://gitlab.com/Mergul/bubel-ecs/-/commits/master)
[![codecov](https://codecov.io/gl/Mergul/bubel-ecs/branch/master/graph/badge.svg?token=Unm0TJhFoW)](https://codecov.io/gl/Mergul/bubel-ecs)
Entity-Component-System implementation in D language. Entity-Component-System implementation in D language.

3
codecov.yml Normal file
View file

@ -0,0 +1,3 @@
ignore:
- "tests/*"
- "**/traits*"

2
demos/.gitignore vendored
View file

@ -12,4 +12,6 @@
!.gitignore !.gitignore
!compile_wasm.py !compile_wasm.py
!cimgui.bc !cimgui.bc
!emscripten_shell.html
!emscripten_multi_shell.html
.dub .dub

View file

@ -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 = []
@ -36,8 +37,10 @@ compiler = 'ldc2 '
shared_flags = '' shared_flags = ''
clean = 0 clean = 0
demo = 0 demo = 0
only_bc = 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\']" --preload-file assets ' emc_flags = '-s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS="[\'png\']" '
ldc_flags = '--d-version=ECSEmscripten --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']
@ -60,6 +63,8 @@ for arg in sys.argv[1:]:
shared_flags += '-Oz ' shared_flags += '-Oz '
elif(arg == '-g'): elif(arg == '-g'):
shared_flags += '-g ' shared_flags += '-g '
elif(arg == '--multi'):
multi = 1
elif(arg == '-g4'): elif(arg == '-g4'):
ldc_flags += '-g ' ldc_flags += '-g '
emc_flags += '-g4 --source-map-base ./ ' emc_flags += '-g4 --source-map-base ./ '
@ -79,6 +84,8 @@ for arg in sys.argv[1:]:
emc_flags += '-s USE_PTHREADS=1 ' emc_flags += '-s USE_PTHREADS=1 '
elif(arg == '--demo=simple'): elif(arg == '--demo=simple'):
demo = 0 demo = 0
elif(arg == '--only-bc'):
only_bc = 1
else: else:
print('unknown argument: ' + arg) print('unknown argument: ' + arg)
exit() exit()
@ -92,8 +99,17 @@ compile(['source'], 'demo.bc')
if clean or os.path.exists('../ecs.bc') == 0 or os.path.isfile('../ecs.bc') == 0: if clean or os.path.exists('../ecs.bc') == 0 or os.path.isfile('../ecs.bc') == 0:
compile(['../source'], '../ecs.bc') compile(['../source'], '../ecs.bc')
emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s ERROR_ON_UNDEFINED_SYMBOLS=0 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s ALLOW_MEMORY_GROWTH=1 -s MINIFY_HTML=0 -s WASM_MEM_MAX=2048MB -s MALLOC=dlmalloc -s WASM=1 -o ecs_demo.html --shell-file emscripten_shell.html ' if only_bc:
exit()
if multi:
emcc_cmd = 'emcc ' + shared_flags + emc_flags + '--pre-js build/assets.js -s FORCE_FILESYSTEM=1 -s MAX_WEBGL_VERSION=2 --emrun -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s ALLOW_MEMORY_GROWTH=1 -s WASM_MEM_MAX=2048MB -s MALLOC=dlmalloc -s WASM=1 {0} -o {1} --shell-file emscripten_multi_shell.html '
else:
emcc_cmd = 'emcc ' + shared_flags + emc_flags + '--pre-js build/assets.js -s FORCE_FILESYSTEM=1 -s MAX_WEBGL_VERSION=2 --emrun -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s ALLOW_MEMORY_GROWTH=1 -s WASM_MEM_MAX=2048MB -s MALLOC=dlmalloc -s WASM=1 -o build/ecs_demo.html --shell-file emscripten_shell.html '
#emcc_cmd = 'emcc -v ' + shared_flags + emc_flags + '-s MAX_WEBGL_VERSION=2 --emrun -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 -s ALLOW_MEMORY_GROWTH=1 -s WASM_MEM_MAX=2048MB -s MALLOC=dlmalloc -s WASM=1 -o build/ecs_demo.html --shell-file emscripten_shell.html '
#-s ALLOW_MEMORY_GROWTH=1 -s PROXY_TO_PTHREAD=1 -Wl,--no-check-features -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s TOTAL_MEMORY=512MB #-s ALLOW_MEMORY_GROWTH=1 -s PROXY_TO_PTHREAD=1 -Wl,--no-check-features -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s TOTAL_MEMORY=512MB
#-s MAX_WEBGL_VERSION=2
emcc_cmd += '../ecs.bc ' emcc_cmd += '../ecs.bc '
emcc_cmd += 'utils.bc ' emcc_cmd += 'utils.bc '
@ -103,6 +119,24 @@ emcc_cmd += 'cimgui.bc '
emcc_cmd += 'mmutils.bc ' emcc_cmd += 'mmutils.bc '
emcc_cmd += 'demo.bc ' emcc_cmd += 'demo.bc '
print(emcc_cmd) 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'
print('Packafing files: ' + pack_cmd)
os.system(pack_cmd)
if multi:
final_cmd = emcc_cmd.format('','build/ecs_demo.html')
print(final_cmd)
os.system(final_cmd)
final_cmd = emcc_cmd.format('-s USE_PTHREADS=1','build/ecs_demo_mt.js')
print(final_cmd)
os.system(final_cmd)
else:
print(emcc_cmd)
os.system(emcc_cmd) os.system(emcc_cmd)
os.system('rm build/assets.js')

View file

@ -0,0 +1,170 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>ECS Demo</title>
<style>
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
textarea.emscripten { font-family: monospace; width: 80%; }
div.emscripten { text-align: center; }
div.emscripten_border { border: 1px solid black; }
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
canvas.emscripten { position: absolute;top: 0px;left: 0px;margin: 0px; border: 0px none; background-color: black; width: 100%; height: 100%; overflow: hidden;}
.spinner {
height: 50px;
width: 50px;
margin: 0px auto;
-webkit-animation: rotation .8s linear infinite;
-moz-animation: rotation .8s linear infinite;
-o-animation: rotation .8s linear infinite;
animation: rotation 0.8s linear infinite;
border-left: 10px solid rgb(0,150,240);
border-right: 10px solid rgb(0,150,240);
border-bottom: 10px solid rgb(0,150,240);
border-top: 10px solid rgb(100,0,200);
border-radius: 100%;
background-color: rgb(200,100,250);
}
@-webkit-keyframes rotation {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(360deg);}
}
@-moz-keyframes rotation {
from {-moz-transform: rotate(0deg);}
to {-moz-transform: rotate(360deg);}
}
@-o-keyframes rotation {
from {-o-transform: rotate(0deg);}
to {-o-transform: rotate(360deg);}
}
@keyframes rotation {
from {transform: rotate(0deg);}
to {transform: rotate(360deg);}
}
</style>
</head>
<body>
<!--<hr/>-->
<figure style="overflow:visible;" id="spinner"><div class="spinner"></div><center style="margin-top:0.5em"><strong>emscripten</strong></center></figure>
<div class="emscripten" id="status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="progress" hidden=1></progress>
</div>
<div class="emscripten_border">
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
</div>
<!--<hr/>
<div class="emscripten">
<input type="checkbox" id="resize">Resize canvas
<input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
&nbsp;&nbsp;&nbsp;
<input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked,
document.getElementById('resize').checked)">
</div>-->
<hr/>
<textarea class="emscripten" id="output" rows="8"></textarea>
<hr>
<script type='text/javascript'>
var statusElement = document.getElementById('status');
var progressElement = document.getElementById('progress');
var spinnerElement = document.getElementById('spinner');
var canvasElement = document.getElementById('canvas');
canvasElement.style.display = "none";
var Module = {
preRun: [],
postRun: [],
print: (function() {
var element = document.getElementById('output');
if (element) element.value = ''; // clear browser cache
return function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
// These replacements are necessary if you render to raw HTML
//text = text.replace(/&/g, "&amp;");
//text = text.replace(/</g, "&lt;");
//text = text.replace(/>/g, "&gt;");
//text = text.replace('\n', '<br>', 'g');
console.log(text);
if (element) {
element.value += text + "\n";
element.scrollTop = element.scrollHeight; // focus on bottom
}
};
})(),
printErr: function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
},
canvas: (function() {
var canvas = document.getElementById('canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
return canvas;
})(),
setStatus: function(text) {
if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
if (text === Module.setStatus.last.text) return;
var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
var now = Date.now();
if (m && now - Module.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon
Module.setStatus.last.time = now;
Module.setStatus.last.text = text;
if (m) {
text = m[1];
progressElement.value = parseInt(m[2])*100;
progressElement.max = parseInt(m[4])*100;
progressElement.hidden = false;
spinnerElement.hidden = false;
} else {
progressElement.value = null;
progressElement.max = null;
progressElement.hidden = true;
if (!text) spinnerElement.hidden = true;
}
statusElement.innerHTML = text;
},
totalDependencies: 0,
monitorRunDependencies: function(left) {
this.totalDependencies = Math.max(this.totalDependencies, left);
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
if (!left) canvasElement.style.display = "block";
}
};
Module.setStatus('Downloading...');
window.onerror = function() {
canvasElement.style.display = "none";
Module.setStatus('Exception thrown, see JavaScript console');
spinnerElement.style.display = 'none';
Module.setStatus = function(text) {
if (text) Module.printErr('[post-exception status] ' + text);
};
};
(function() {
if(typeof SharedArrayBuffer !== "undefined")
{
memory_test = new WebAssembly.Memory({
"initial": 1,
"maximum": 1,
"shared": true
});
if (!(memory_test.buffer instanceof SharedArrayBuffer))src = "ecs_demo.js";
else src = "ecs_demo_mt.js";
delete memory_test;
}
else src = "ecs_demo.js";
document.write('<script async type="text/javascript" src="' + src + '"><\/script>');
})();
</script>
<!--{{{ SCRIPT }}}-->
</body>
</html>

154
demos/emscripten_shell.html Normal file
View file

@ -0,0 +1,154 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>ECS Demo</title>
<style>
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
textarea.emscripten { font-family: monospace; width: 80%; }
div.emscripten { text-align: center; }
div.emscripten_border { border: 1px solid black; }
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
canvas.emscripten { position: absolute;top: 0px;left: 0px;margin: 0px; border: 0px none; background-color: black; width: 100%; height: 100%; overflow: hidden;}
.spinner {
height: 50px;
width: 50px;
margin: 0px auto;
-webkit-animation: rotation .8s linear infinite;
-moz-animation: rotation .8s linear infinite;
-o-animation: rotation .8s linear infinite;
animation: rotation 0.8s linear infinite;
border-left: 10px solid rgb(0,150,240);
border-right: 10px solid rgb(0,150,240);
border-bottom: 10px solid rgb(0,150,240);
border-top: 10px solid rgb(100,0,200);
border-radius: 100%;
background-color: rgb(200,100,250);
}
@-webkit-keyframes rotation {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(360deg);}
}
@-moz-keyframes rotation {
from {-moz-transform: rotate(0deg);}
to {-moz-transform: rotate(360deg);}
}
@-o-keyframes rotation {
from {-o-transform: rotate(0deg);}
to {-o-transform: rotate(360deg);}
}
@keyframes rotation {
from {transform: rotate(0deg);}
to {transform: rotate(360deg);}
}
</style>
</head>
<body>
<!--<hr/>-->
<figure style="overflow:visible;" id="spinner"><div class="spinner"></div><center style="margin-top:0.5em"><strong>emscripten</strong></center></figure>
<div class="emscripten" id="status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="progress" hidden=1></progress>
</div>
<div class="emscripten_border">
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
</div>
<!--<hr/>
<div class="emscripten">
<input type="checkbox" id="resize">Resize canvas
<input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
&nbsp;&nbsp;&nbsp;
<input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked,
document.getElementById('resize').checked)">
</div>-->
<hr/>
<textarea class="emscripten" id="output" rows="8"></textarea>
<hr>
<script type='text/javascript'>
var statusElement = document.getElementById('status');
var progressElement = document.getElementById('progress');
var spinnerElement = document.getElementById('spinner');
var canvasElement = document.getElementById('canvas');
canvasElement.style.display = "none";
var Module = {
preRun: [],
postRun: [],
print: (function() {
var element = document.getElementById('output');
if (element) element.value = ''; // clear browser cache
return function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
// These replacements are necessary if you render to raw HTML
//text = text.replace(/&/g, "&amp;");
//text = text.replace(/</g, "&lt;");
//text = text.replace(/>/g, "&gt;");
//text = text.replace('\n', '<br>', 'g');
console.log(text);
if (element) {
element.value += text + "\n";
element.scrollTop = element.scrollHeight; // focus on bottom
}
};
})(),
printErr: function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
},
canvas: (function() {
var canvas = document.getElementById('canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
return canvas;
})(),
setStatus: function(text) {
if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
if (text === Module.setStatus.last.text) return;
var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
var now = Date.now();
if (m && now - Module.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon
Module.setStatus.last.time = now;
Module.setStatus.last.text = text;
if (m) {
text = m[1];
progressElement.value = parseInt(m[2])*100;
progressElement.max = parseInt(m[4])*100;
progressElement.hidden = false;
spinnerElement.hidden = false;
} else {
progressElement.value = null;
progressElement.max = null;
progressElement.hidden = true;
if (!text) spinnerElement.hidden = true;
}
statusElement.innerHTML = text;
},
totalDependencies: 0,
monitorRunDependencies: function(left) {
this.totalDependencies = Math.max(this.totalDependencies, left);
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
if (!left) canvasElement.style.display = "block";
}
};
Module.setStatus('Downloading...');
window.onerror = function() {
canvasElement.style.display = "none";
Module.setStatus('Exception thrown, see JavaScript console');
spinnerElement.style.display = 'none';
Module.setStatus = function(text) {
if (text) Module.printErr('[post-exception status] ' + text);
};
};
</script>
{{{ SCRIPT }}}
</body>
</html>

View file

@ -376,7 +376,8 @@ version (MM_USE_POSIX_THREADS)
{ {
threadStart = dg; threadStart = dg;
int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this);
assert(ok == 0); if(!ok)handle = pthread_t();
//assert(ok == 0);
} }
void join() void join()
@ -461,7 +462,8 @@ else version(D_BetterC)
{ {
threadStart = dg; threadStart = dg;
int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this);
assert(ok == 0); if(!ok)handle = pthread_t();
//assert(ok == 0);
} }
void join() void join()
@ -569,7 +571,7 @@ else version(D_BetterC)
threadStart = dg; threadStart = dg;
handle = cast(HANDLE) _beginthreadex( null, 0, &threadRunFunc, cast(void*)&this, 0, null ); handle = cast(HANDLE) _beginthreadex( null, 0, &threadRunFunc, cast(void*)&this, 0, null );
//int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this); //int ok = pthread_create(&handle, null, &threadRunFunc, cast(void*)&this);
assert(handle != null); //assert(handle != null);
} }
void join() void join()

View file

@ -55,6 +55,7 @@ struct Texture
data.data[0..$] = (cast(ubyte*)surf.pixels)[0..data.data.length]; data.data[0..$] = (cast(ubyte*)surf.pixels)[0..data.data.length];
glGenTextures(1, &data.gl_handle); glGenTextures(1, &data.gl_handle);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,data.gl_handle); glBindTexture(GL_TEXTURE_2D,data.gl_handle);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

View file

@ -5,7 +5,7 @@
], ],
"description": "Dynamic Entity Component System", "description": "Dynamic Entity Component System",
"copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz", "copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz",
"license": "BSD", "license": "BSD 3-clause",
"sourcePaths" : ["source\/"], "sourcePaths" : ["source\/"],
"excludedSourceFiles":[ "excludedSourceFiles":[
"source\/ecs\/traits.d" "source\/ecs\/traits.d"

36
skeleton.html Normal file
View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title>BubelECS</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="style.css" />
<script type="text/javascript" src="script.js"></script>
<!-- You should delete this line if you don't want to use
the JS-based search as it exists just to optimize that. -->
<link rel="prefetch" href="search-results.html" />
</head>
<body>
<div id="page-header">
<div id="logotype">
<span>BubelECS</span>
<nav>
<a href="https://gitlab.com/Mergul/bubel-ecs/">Repository</a>
</nav>
</div>
<form id="search" action="search-docs.html">
<input placeholder="Find a symbol name..." type="search" name="searchTerm" />
<input type="submit" value="Go" />
</form>
</div>
<div id="page-body">
<div id="page-content">
</div>
<div id="page-nav">
</div>
</div>
<div id="page-footer">Page generated by <a href="https://github.com/adamdruppe/adrdox">adrdox</a></div>
</body>
</html>

View file

@ -1,8 +1,11 @@
/************************************************************************************************************************ /************************************************************************************************************************
*It's internal code. Can be used for atomics if emscripten backend will be used. 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-2019, Dawid Masiukiewicz, Michał Masiukiewicz
License: BSD 3-clause, see LICENSE file in project root folder.
*/ */
module ecs.atomic; module ecs.atomic;

View file

@ -1,17 +1,24 @@
/************************************************************************************************************************ /************************************************************************************************************************
*This module contain attributes used to mark components. This module contain attributes used to mark components.
*Currently only two attributes are supported: Currently only two attributes are supported:
* - optional: mark component as optional for system update $(LIST
* - readonly: mark component access as read only (used for multithreading) * optional: mark component as optional for system update
* * readonly: mark component access as read only (used for multithreading)
*By default components are required and mutable. "const" attribute can be used insteac od readonly mark. )
*ex.
*Struct EntitiesData By default components are required and mutable. "const" attribute can be used insteac od readonly mark.
*{
* Comp1[] cmp; //mutable required component ---
* @readonly @optional Comp2[] cmp2; //optional read only component Struct EntitiesData
* @optional const (Comp3)[] cmp3; //same as cmp2 {
*} Comp1[] cmp; //mutable required component
@readonly @optional Comp2[] cmp2; //optional read only component
@optional const (Comp3)[] cmp3; //same as cmp2
}
---
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
License: BSD 3-clause, see LICENSE file in project root folder.
*/ */
module ecs.attributes; module ecs.attributes;

View file

@ -1,7 +1,10 @@
/************************************************************************************************************************ /************************************************************************************************************************
*It's internal code. It's internal code.
*
*Module contain memory allocator. Module contain memory allocator.
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
License: BSD 3-clause, see LICENSE file in project root folder.
*/ */
module ecs.block_allocator; module ecs.block_allocator;
@ -9,14 +12,14 @@ import ecs.manager;
import ecs.std; import ecs.std;
/************************************************************************************************************************ /************************************************************************************************************************
*Allocator allocate large blocks and return smaller blocks. When there is no more blocks then next large block is allocated. Allocator allocate large blocks and return smaller blocks. When there is no more blocks then next large block is allocated.
*By default freeing memory only returns it to allocator. To free large memory chunks freeMemory function is used. By default freeing memory only returns it to allocator. To free large memory chunks freeMemory function is used.
*freeMemory function return to system memory even if chunk blocks wasn't freed. freeMemory function return to system memory even if chunk blocks wasn't freed.
*/ */
struct BlockAllocator struct BlockAllocator
{ {
/************************************************************************************************************************ /************************************************************************************************************************
*Get new block. Allocator automatically allocate next memory chunk if needed. Get new block. Allocator automatically allocate next memory chunk if needed.
*/ */
void* getBlock() nothrow @nogc void* getBlock() nothrow @nogc
{ {
@ -28,7 +31,7 @@ struct BlockAllocator
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Return block to allocator for further use. Return block to allocator for further use.
*/ */
void freeBlock(void* block) nothrow @nogc void freeBlock(void* block) nothrow @nogc
{ {
@ -37,7 +40,7 @@ struct BlockAllocator
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Free whole used memory. This function return to system all memory chunks even if not every black was freed. Free whole used memory. This function return to system all memory chunks even if not every black was freed.
*/ */
void freeMemory() nothrow @nogc void freeMemory() nothrow @nogc
{ {

View file

@ -1,34 +1,53 @@
/************************************************************************************************************************ /************************************************************************************************************************
*This module contain main templates for user. This module contain main templates for user.
*There are three structure templates (mixins) which should be added on top of structure: There are three structure templates (mixins) which should be added on top of structure:
* - System: make system structure $(LIST
* - Component: make component structure * System: make system structure
* - Event: make event structure * Component: make component structure
* * Event: make event structure
*ex. )
*Struct System1
*{ ---
* mixin!ECS.System; Struct System1
*} {
* mixin!ECS.System;
*Struct System2 }
*{
* mixin!ECS.System(16);//set number of jobs generated for system by multithreaded update Struct System2
*} {
* mixin!ECS.System(16);//set number of jobs generated for system by multithreaded update
*Struct Component1 }
*{
* mixin!ECS.Component; Struct Component1
*} {
* mixin!ECS.Component;
*Struct Event1 }
*{
* mixin!ECS.Event; Struct Event1
*} {
* mixin!ECS.Event;
*There is also template for generating list of excluded components "ExcludedComponets(T...)". }
*This template takes component structure types and making list of excluded components used in "registerSystem" function. ---
*
There is also template for generating list of excluded components "ExcludedComponets(T...)".
This template takes component structure types and making list of excluded components used in "registerSystem" function.
---
Struct System1
{
mixin!ECS.System;
struct EntitiesData
{
... //used components
}
ExcludedComponets!(Comp1, Comp2);
}
---
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
License: BSD 3-clause, see LICENSE file in project root folder.
*/ */
module ecs.core; module ecs.core;
@ -36,12 +55,12 @@ public import ecs.manager;
public import ecs.entity; public import ecs.entity;
/************************************************************************************************************************ /************************************************************************************************************************
*Main struct used as namespace for templates. Main struct used as namespace for templates.
*/ */
static struct ECS static struct ECS
{ {
/************************************************************************************************************************ /************************************************************************************************************************
*Mark structure as System. Should be added on top of structure (before any data). Mark structure as System. Should be added on top of structure (before any data).
*/ */
mixin template System(uint jobs_count = 32) mixin template System(uint jobs_count = 32)
{ {
@ -50,7 +69,7 @@ static struct ECS
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Mark structure as Component. Should be added on top of structure (before any data). Mark structure as Component. Should be added on top of structure (before any data).
*/ */
mixin template Component() mixin template Component()
{ {
@ -58,7 +77,7 @@ static struct ECS
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Mark structure as Event. Should be added on top of structure (before any data). Mark structure as Event. Should be added on top of structure (before any data).
*/ */
mixin template Event() mixin template Event()
{ {
@ -67,7 +86,7 @@ static struct ECS
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Make list of excluded components. This template get structure types as argument. Should be added inside System structure. Make list of excluded components. This template get structure types as argument. Should be added inside System structure.
*/ */
mixin template ExcludedComponents(T...) mixin template ExcludedComponents(T...)
{ {

View file

@ -1,5 +1,8 @@
/************************************************************************************************************************ /************************************************************************************************************************
*Entity module. Entity module.
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
License: BSD 3-clause, see LICENSE file in project root folder.
*/ */
module ecs.entity; module ecs.entity;
@ -7,7 +10,7 @@ import ecs.system;
import ecs.manager; import ecs.manager;
/************************************************************************************************************************ /************************************************************************************************************************
*Entity ID structure. Used as reference to Entity. Pointer to entity should be ever used to store entity reference! Entity ID structure. Used as reference to Entity. Pointer to entity should be ever used to store entity reference!
*/ */
struct EntityID struct EntityID
{ {
@ -18,7 +21,7 @@ struct EntityID
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Structure of Entity. It's have only ID, but have full konwlege to get to components memory (If pointer to it is proper). Structure of Entity. It's have only ID, but have full konwlege to get to components memory (If pointer to it is proper).
*/ */
struct Entity struct Entity
{ {
@ -26,8 +29,8 @@ struct Entity
EntityID id; EntityID id;
/************************************************************************************************************************ /************************************************************************************************************************
*Get specified component. If component doesn't exist function retun null. Pointer is valid only before next "commit()", "begin()" or "end()" Get specified component. If component doesn't exist function retun null. Pointer is valid only before next "commit()", "begin()" or "end()"
*function is called. Returned pointer shouldn't be used to store reference to entity data. function is called. Returned pointer shouldn't be used to store reference to entity data.
*/ */
T* getComponent(T)() const T* getComponent(T)() const
{ {
@ -45,13 +48,15 @@ struct Entity
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Entity template structure. Entity template structure.
*Entity contain whole information needed to create new entity. Allocating EntityTemplate is considered as more expensive operation
*than adding entity. Whole components memory is stored in EntityTemplate and is copyied to newly added entity. Entity contain whole information needed to create new entity. Allocating EntityTemplate is considered as more expensive operation
*If you want to place several entity with small difference in data then you should take pointer to component and change it before every than adding entity. Whole components memory is stored in EntityTemplate and is copyied to newly added entity.
*entity addition. If you want to place several entity with small difference in data then you should take pointer to component and change it before every
*There is no restriction about number of allocated templates. Single template can be used from multiple threads, but if you entity addition.
*want to changes some components data before add entity (entity position for example) it's better to use multiple templates.
There is no restriction about number of allocated templates. Single template can be used from multiple threads, but if you
want to changes some components data before add entity (entity position for example) it's better to use multiple templates.
*/ */
export struct EntityTemplate export struct EntityTemplate
{ {
@ -61,7 +66,7 @@ export struct EntityTemplate
EntityManager.EntityInfo* info; EntityManager.EntityInfo* info;
/************************************************************************************************************************ /************************************************************************************************************************
*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.
*/ */
T* getComponent(T)() nothrow @nogc T* getComponent(T)() nothrow @nogc
{ {

View file

@ -34,7 +34,7 @@ package struct EventManager
EventData* data = &events[Ev.event_id]; EventData* data = &events[Ev.event_id];
EventBlock* block = data.blocks[block_id]; EventBlock* block = data.blocks[block_id];
//EntityManager.EventInfo* info = &gEM.events[Ev.event_id]; //EntityManager.EventInfo* info = &manager.events[Ev.event_id];
event.entity_id = id; event.entity_id = id;
if(block is null) if(block is null)
@ -119,15 +119,15 @@ package struct EventManager
void allocateData(uint threads_count) nothrow @nogc void allocateData(uint threads_count) nothrow @nogc
{ {
disposeData(); disposeData();
events = Mallocator.makeArray!EventData(gEM.events.length); events = Mallocator.makeArray!EventData(manager.events.length);
foreach(i,ref event;events) foreach(i,ref event;events)
{ {
event.blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2); event.blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2);
event.first_blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2); event.first_blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2);
event.data_offset = EventBlock.sizeof;//gEM.events[i]. event.data_offset = EventBlock.sizeof;//manager.events[i].
gEM.alignNum(event.data_offset, gEM.events[i].alignment); manager.alignNum(event.data_offset, manager.events[i].alignment);
event.max_events = cast(ushort)((events_block_size - event.data_offset) / gEM.events[i].size); event.max_events = cast(ushort)((events_block_size - event.data_offset) / manager.events[i].size);
} }
} }

View file

@ -8,12 +8,12 @@ import ecs.atomic;
import core.stdc.string : memcpy; import core.stdc.string : memcpy;
/************************************************************************************************************************ /************************************************************************************************************************
*IDManager is responsible for assignment and removing IDs. IDs are unique throughtout a whole duration of the program. IDManager is responsible for assignment and removing IDs. IDs are unique throughtout a whole duration of the program.
*/ */
struct IDManager struct IDManager
{ {
/************************************************************************************************************************ /************************************************************************************************************************
*Get new ID. Get new ID.
*/ */
pragma(inline, false) EntityID getNewID() nothrow @nogc pragma(inline, false) EntityID getNewID() nothrow @nogc
{ {
@ -74,7 +74,7 @@ struct IDManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Release ID. Release ID.
*/ */
void releaseID(EntityID id) nothrow @nogc void releaseID(EntityID id) nothrow @nogc
{ {
@ -91,7 +91,7 @@ struct IDManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Update pointer to entity. The purpose of this function is to ensure that pointer to entity is always correct. Update pointer to entity. The purpose of this function is to ensure that pointer to entity is always correct.
*/ */
void update(ref Entity entity) nothrow @nogc void update(ref Entity entity) nothrow @nogc
{ {
@ -107,7 +107,7 @@ struct IDManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Returns pointer to entity. Returns pointer to entity.
*/ */
export Entity* getEntityPointer(EntityID id) nothrow @nogc export Entity* getEntityPointer(EntityID id) nothrow @nogc
{ {
@ -132,7 +132,7 @@ struct IDManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Check if entity with specified ID exist. Check if entity with specified ID exist.
*/ */
export bool isExist(EntityID id) nothrow @nogc export bool isExist(EntityID id) nothrow @nogc
{ {
@ -143,7 +143,7 @@ struct IDManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Initialize manager. Initialize manager.
*/ */
void initialize() nothrow @nogc void initialize() nothrow @nogc
{ {
@ -162,7 +162,7 @@ struct IDManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Free manager memory. Free manager memory.
*/ */
void deinitialize() @trusted @nogc nothrow void deinitialize() @trusted @nogc nothrow
{ {
@ -185,7 +185,7 @@ struct IDManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Optimize memory. Must be called if any ID was added and some ID will be removed. Optimize memory. Must be called if any ID was added and some ID will be removed.
*/ */
void optimize() nothrow @nogc void optimize() nothrow @nogc
{ {

View file

@ -1,5 +1,8 @@
/************************************************************************************************************************ /************************************************************************************************************************
*Most important module. Almost every function is called from EntityManager. Most important module. Almost every function is called from EntityManager.
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
License: BSD 3-clause, see LICENSE file in project root folder.
*/ */
module ecs.manager; module ecs.manager;
@ -28,37 +31,38 @@ export alias gEntityManager = EntityManager.instance;
alias SerializeVector = ecs.vector.Vector!ubyte; alias SerializeVector = ecs.vector.Vector!ubyte;
/************************************************************************************************************************ /************************************************************************************************************************
*Entity manager is responsible for everything. Entity manager is responsible for everything.
*
*Entity manager can be in three states: Entity manager can be in three states:
* - registration: time between beginRegister() and endRegister() calls. - registration: time between beginRegister() and endRegister() calls.
* - update: time between being() and end() calls. - update: time between being() and end() calls.
* - default: when it's not in registration or update time - default: when it's not in registration or update time
*
*Manager can be only in one state simultaneously. Manager can be only in one state simultaneously.
*
*Manager must be initialized before use. There is global instance of EntityManager: EntityManager.instance or gEM as alias. Manager must be initialized before use. There is global instance of EntityManager: EntityManager.instance or gEM as alias.
*
*Registration process consist of registration of passes, systems, entities and events. Registration process consist of registration of passes, systems, entities and events.
*
*Pass is group of system which should be used inside one update() call. Passes are added as name (string) and can be referenced by name or id.<br/> Pass is group of system which should be used inside one update() call. Passes are added as name (string) and can be referenced by name or id.
*System is structure responsible for update of specified group of entities. System consist of EntitiesData structure which contain components used System is structure responsible for update of specified group of entities. System consist of EntitiesData structure which contain components used
*by system and some callback. Main callback is onUpdate() which is called by update() entity manager function. Other callbacks are used as listeners for by system and some callback. Main callback is onUpdate() which is called by update() entity manager function. Other callbacks are used as listeners for
*adding entites, tracking system lifetime and events handling.<br/> adding entites, tracking system lifetime and events handling.
*Component is basicly small fraction of data which is considered to be used as whole. In best scenario every byte of component is used when it's refered to.
*In practice sometimes it's better to join data into one component even if it's can be accessed separetly.<br/> Component is basicly small fraction of data which is considered to be used as whole. In best scenario every byte of component is used when it's refered to.
*Events are structures with data used to handle events. Event can contain for exmaple one floating point number used as damage dealt to entity.<br/> In practice sometimes it's better to join data into one component even if it's can be accessed separetly.
*Entity is group of components. In memory entity is only ID which makes it's possible to take it's components. Components are grouped into chunks, and Events are structures with data used to handle events. Event can contain for exmaple one floating point number used as damage dealt to entity.
*grouped by component type so entity can be fracted in big memory chunk.<br/> Entity is group of components. In memory entity is only ID which makes it's possible to take it's components. Components are grouped into chunks, and
* grouped by component type so entity can be fracted in big memory chunk.
*There is two types of update:
*<br/> - update(): function used to call update pass. There is two types of update:
*<br/> - updateMT(): function used to call update pass multithreaded. This call only generates jobs which must be called by user. - update(): function used to call update pass.
- updateMT(): function used to call update pass multithreaded. This call only generates jobs which must be called by user.
*/ */
export struct EntityManager export struct EntityManager
{ {
/************************************************************************************************************************ /************************************************************************************************************************
*Initialize ECS. Initialize ECS.
*/ */
export static void initialize(uint threads_count, uint page_size = 32768, export static void initialize(uint threads_count, uint page_size = 32768,
uint block_pages_count = 128) uint block_pages_count = 128)
@ -81,7 +85,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Deinitialize and destroy ECS. This function release whole memory. Deinitialize and destroy ECS. This function release whole memory.
*/ */
export static void destroy() export static void destroy()
{ {
@ -154,7 +158,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Begin registering process. Every register function should be called between beginRegister() and endRegister(). Begin registering process. Every register function should be called between beginRegister() and endRegister().
*/ */
export void beginRegister() nothrow @nogc export void beginRegister() nothrow @nogc
{ {
@ -172,7 +176,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*End registering process. Every register function should be called between beginRegister() and endRegister(). End registering process. Every register function should be called between beginRegister() and endRegister().
*/ */
export void endRegister() export void endRegister()
{ {
@ -346,7 +350,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Same as "void registerSystem(Sys)(int priority, int pass = 0)" but use pass name instead of id. 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) void registerSystem(Sys)(int priority, const(char)[] pass_name)
{ {
@ -359,13 +363,13 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Register new System into EntityManager. This funcion generate glue between EntityManager and System. Register new System into EntityManager. This funcion generate glue between EntityManager and System.
*Systems can be registered from external dynamic library, and can be registered after adding entities too. Systems can be registered from external dynamic library, and can be registered after adding entities too.
*System mustn't be registered before components which system want to use, in this case functions call assertion. System mustn't be registered before components which system want to use, in this case functions call assertion.
*
*Params: Params:
*priority = system priority. Priority determines order of execution of systems updates priority = system priority. Priority determines order of execution of systems updates
*pass = index of UpdatePass which sholud call system update pass = index of UpdatePass which sholud call system update
*/ */
void registerSystem(Sys)(int priority, ushort pass = 0) void registerSystem(Sys)(int priority, ushort pass = 0)
{ {
@ -442,11 +446,12 @@ export struct EntityManager
static struct ComponentsCounts static struct ComponentsCounts
{ {
uint readonly; //one more than should be to prevent null arrays (zero length arrays)
uint mutable; uint readonly = 1;
uint excluded; uint mutable = 1;
uint optional; uint excluded = 1;
uint req; uint optional = 1;
uint req = 1;
} }
static ComponentsCounts getComponentsCounts()() static ComponentsCounts getComponentsCounts()()
@ -1083,7 +1088,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Return system ECS api by id Return system ECS api by id
*/ */
export System* getSystem(ushort id) nothrow @nogc export System* getSystem(ushort id) nothrow @nogc
{ {
@ -1093,7 +1098,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Return pointer to system registered in manager Return pointer to system registered in manager
*/ */
Sys* getSystem(Sys)() nothrow @nogc Sys* getSystem(Sys)() nothrow @nogc
{ {
@ -1114,7 +1119,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Register component into EntityManager. Register component into EntityManager.
*/ */
void registerComponent(Comp)() void registerComponent(Comp)()
{ {
@ -1229,7 +1234,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Same as "void update(int pass = 0)" but use pass name instead of id. Same as "void update(int pass = 0)" but use pass name instead of id.
*/ */
export void update(const(char)[] pass_name) nothrow @nogc export void update(const(char)[] pass_name) nothrow @nogc
{ {
@ -1239,7 +1244,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Update systems. Should be called only between begin() and end(). Update systems. Should be called only between begin() and end().
*/ */
export void update(ushort pass = 0) nothrow @nogc export void update(ushort pass = 0) nothrow @nogc
{ {
@ -1267,7 +1272,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Same as "void updateMT(int pass = 0)" but use pass name instead of id. Same as "void updateMT(int pass = 0)" but use pass name instead of id.
*/ */
export void updateMT(const(char)[] pass_name) nothrow @nogc export void updateMT(const(char)[] pass_name) nothrow @nogc
{ {
@ -1430,7 +1435,7 @@ export struct EntityManager
}*/ }*/
/************************************************************************************************************************ /************************************************************************************************************************
*Return size of single page (block). Every entity data block has size of page. Return size of single page (block). Every entity data block has size of page.
*/ */
uint pageSize() uint pageSize()
{ {
@ -1438,8 +1443,8 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Return number of pages in single block allocation. Library allocate defined number of pages at once and assign it's Return number of pages in single block allocation. Library allocate defined number of pages at once and assign it's
*for entities. for entities.
*/ */
uint pagesInBlock() uint pagesInBlock()
{ {
@ -1464,11 +1469,11 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Allocate EntityTemplate with all components from entity witch it's data and returns pointer to it. Allocate EntityTemplate with all components from entity witch it's data and returns pointer to it.
*
*Params: Params:
*entity_id = ID of entity from which should be created template entity_id = ID of entity from which should be created template
*fill_default = if true, components will be filled with default data, instead entity data will be taken fill_default = if true, components will be filled with default data, instead entity data will be taken
*/ */
export EntityTemplate* allocateTemplate(EntityID entity_id, bool fill_default = false) export EntityTemplate* allocateTemplate(EntityID entity_id, bool fill_default = false)
{ {
@ -1504,10 +1509,10 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Allocate EntityTemplate with specifed components and returns pointer to it. Allocate EntityTemplate with specifed components and returns pointer to it.
*
*Params: Params:
*components_ids = array of components allocated with template components_ids = array of components allocated with template
*/ */
export EntityTemplate* allocateTemplate(ushort[] components_ids) export EntityTemplate* allocateTemplate(ushort[] components_ids)
{ {
@ -1550,13 +1555,13 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Allocate EntityTemplate from basic Template with modifications by adding and removing some components and returns pointer to it. Allocate EntityTemplate from basic Template with modifications by adding and removing some components and returns pointer to it.
*Arrays of components needen't to be checked for repeated components, as function itself check if components exist in base template. Arrays of components needen't to be checked for repeated components, as function itself check if components exist in base template.
*
*Params: Params:
*base_tmpl = template from which components sould be copied base_tmpl = template from which components sould be copied
*components_ids = array of new components to add components_ids = array of new components to add
*remove_components_ids = array of components to remove from base template remove_components_ids = array of components to remove from base template
*/ */
export EntityTemplate* allocateTemplate(EntityTemplate* base_tmpl, export EntityTemplate* allocateTemplate(EntityTemplate* base_tmpl,
ushort[] components_ids, ushort[] remove_components_ids = null) ushort[] components_ids, ushort[] remove_components_ids = null)
@ -1626,10 +1631,10 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Returns entity type info. Returns entity type info.
*
*Params: Params:
*ids = array of components ids = array of components
*/ */
export EntityInfo* getEntityInfo(ushort[] ids) export EntityInfo* getEntityInfo(ushort[] ids)
{ {
@ -1932,10 +1937,10 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Returns pointer to entity. Returns pointer to entity.
*
*Params: Params:
*id = ID of entity id = ID of entity
*/ */
export Entity* getEntity(EntityID id) nothrow @nogc export Entity* getEntity(EntityID id) nothrow @nogc
{ {
@ -1943,11 +1948,11 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Remove components from entity by IDs. Components will be removed on end of frame. Remove components from entity by IDs. Components will be removed on end of frame.
*
*Params: Params:
*entity_id = ID of entity entity_id = ID of entity
*del_ids = array of components IDs del_ids = array of components IDs
*/ */
export void removeComponents(EntityID entity_id, ushort[] del_ids) nothrow @nogc export void removeComponents(EntityID entity_id, ushort[] del_ids) nothrow @nogc
{ {
@ -2053,11 +2058,11 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Remove coponents from entity. Remove coponents from entity.
*
*Params: Params:
*Components = components types to remove Components = components types to remove
*entity_id = ID of entity entity_id = ID of entity
*/ */
void removeComponents(Components...)(EntityID entity_id) void removeComponents(Components...)(EntityID entity_id)
{ {
@ -2206,11 +2211,11 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Add components to entity. Components will be added on end of frame. Add components to entity. Components will be added on end of frame.
*
*Params: Params:
*entity_id = ID of entity to remove entity_id = ID of entity to remove
*comps = components to add comps = components to add
*/ */
void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc
{ {
@ -2241,10 +2246,10 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Free template memory. Free template memory.
*
*Params: Params:
*template_ = pointer entity template allocated by EntityManager. template_ = pointer entity template allocated by EntityManager.
*/ */
export void freeTemplate(EntityTemplate* template_) export void freeTemplate(EntityTemplate* template_)
{ {
@ -2253,9 +2258,9 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Add copy of entity to system and returns pointer to it. Added copy has same data as copied entity. Returen pointer is Add copy of entity to system and returns pointer to it. Added copy has same data as copied entity. Returen pointer is
*valid only before one from commit(), begin() or end() will be called. To save entity to further use you should save ID valid only before one from commit(), begin() or end() will be called. To save entity to further use you should save ID
*instead of pointer. instead of pointer.
* *
*Params: *Params:
*id = ID of entity to be copyied. *id = ID of entity to be copyied.
@ -2307,11 +2312,11 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Add entity to system. Returen pointer is valid only before one from commit(), begin() or end() will be called. To save entity to further Add entity to system. Returen pointer is valid only before one from commit(), begin() or end() will be called. To save entity to further
*use you should save ID instead of pointer. use you should save ID instead of pointer.
*
*Params: Params:
*tmpl = pointer entity template allocated by EntityManager. tmpl = pointer entity template allocated by EntityManager.
*/ */
export Entity* addEntity(EntityTemplate* tmpl) export Entity* addEntity(EntityTemplate* tmpl)
{ {
@ -2357,7 +2362,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Return block with free space for selected EntityInfo. Return block with free space for selected EntityInfo.
*/ */
private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info) nothrow @nogc private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info) nothrow @nogc
{ {
@ -2385,7 +2390,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Return block with free space for selected EntityInfo. Additional this function is multithread safe. Return block with free space for selected EntityInfo. Additional this function is multithread safe.
*/ */
private EntitiesBlock* findBlockWithFreeSpaceMT(EntityInfo* info) private EntitiesBlock* findBlockWithFreeSpaceMT(EntityInfo* info)
{ {
@ -2429,10 +2434,10 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Remove entity by ID. Entity will be removed on frame end. Remove entity by ID. Entity will be removed on frame end.
*
*Params: Params:
*id = id of entity to remove id = id of entity to remove
*/ */
export void removeEntity(EntityID id) export void removeEntity(EntityID id)
{ {
@ -2515,10 +2520,10 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*functions return MetaData of page. functions return MetaData of page.
*
*Params: Params:
*pointer = pointer to any data of entity (i.e. component data pointer) pointer = pointer to any data of entity (i.e. component data pointer)
*/ */
export EntitiesBlock* getMetaData(const void* pointer) nothrow @nogc export EntitiesBlock* getMetaData(const void* pointer) nothrow @nogc
{ {
@ -2752,7 +2757,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Begin of update process. Should be called before any update is called. Begin of update process. Should be called before any update is called.
*/ */
export void begin() export void begin()
{ {
@ -2769,7 +2774,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*End of update process. Should be called after every update function. End of update process. Should be called after every update function.
*/ */
export void end() export void end()
{ {
@ -2919,7 +2924,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Component info; Component info;
*/ */
struct ComponentInfo struct ComponentInfo
{ {
@ -2963,7 +2968,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Entity type info. Entity type info.
*/ */
struct EntityInfo struct EntityInfo
{ {
@ -3135,7 +3140,7 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Meta data of every block of entities (contained at the begining of block). Meta data of every block of entities (contained at the begining of block).
*/ */
struct EntitiesBlock struct EntitiesBlock
{ {
@ -3182,10 +3187,10 @@ export struct EntityManager
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Structure with data used to calling System calls. Structure with data used to calling System calls.
*
*<i>first_block</i>, <i>begin</i>, <i>end</i>, <i>blocks</i> parameters are used <i>first_block</i>, <i>begin</i>, <i>end</i>, <i>blocks</i> parameters are used
*to call partial info update to call partial info update
*/ */
struct CallData struct CallData
{ {

View file

@ -1,6 +1,9 @@
/************************************************************************************************************************ /************************************************************************************************************************
*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-2019, Dawid Masiukiewicz, Michał Masiukiewicz
License: BSD 3-clause, see LICENSE file in project root folder.
*/ */
module ecs.std; module ecs.std;

View file

@ -1,5 +1,8 @@
/************************************************************************************************************************ /************************************************************************************************************************
*System module. System module.
Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz
License: BSD 3-clause, see LICENSE file in project root folder.
*/ */
module ecs.system; module ecs.system;
@ -7,25 +10,27 @@ import ecs.entity;
import ecs.manager; import 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:
*<br/>-void onUpdate(EntitesData); $(LIST
*<br/>-void onEnable() * void onUpdate(EntitesData);
*<br/>-void onDisable(); * void onEnable()
*<br/>-bool onBegin(); * void onDisable();
*<br/>-void onEnd(); * bool onBegin();
*<br/>-void onCreate() * void onEnd();
*<br/>-void onDestroy(); * void onCreate()
*<br/>-void onAddEntity(EntitesData); * void onDestroy();
*<br/>-void onRemoveEntity(EntitiesData); * void onAddEntity(EntitesData);
*<br/>-void onChangeEntity(EntitiesData); * void onRemoveEntity(EntitiesData);
*<br/>-void handleEvent(Entity*, Event); * void onChangeEntity(EntitiesData);
* void handleEvent(Entity*, Event);
)
*/ */
struct System struct System
{ {
/************************************************************************************************************************ /************************************************************************************************************************
*Check if system is enabled. Check if system is enabled.
*/ */
export bool enabled() nothrow @nogc export bool enabled() nothrow @nogc
{ {
@ -33,7 +38,7 @@ struct System
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Enable system. If actually it is enabled function do nothing. Enable system. If actually it is enabled function do nothing.
*/ */
export void enable() nothrow @nogc export void enable() nothrow @nogc
{ {
@ -43,7 +48,7 @@ struct System
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Disable system. If actually it is disabled function do nothing. Disable system. If actually it is disabled function do nothing.
*/ */
export void disable() nothrow @nogc export void disable() nothrow @nogc
{ {
@ -53,7 +58,7 @@ struct System
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Get system priority. Get system priority.
*/ */
export int priority() nothrow @nogc export int priority() nothrow @nogc
{ {
@ -61,7 +66,7 @@ struct System
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Get system priority. Get system priority.
*/ */
export bool execute() nothrow @nogc export bool execute() nothrow @nogc
{ {
@ -69,7 +74,7 @@ struct System
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Get system priority. Get system priority.
*/ */
export ushort id() nothrow @nogc export ushort id() nothrow @nogc
{ {
@ -77,7 +82,7 @@ struct System
} }
/************************************************************************************************************************ /************************************************************************************************************************
*Get system name. Get system name.
*/ */
export const(char)[] name() nothrow @nogc export const(char)[] name() nothrow @nogc
{ {

View file

@ -15,7 +15,7 @@ unittest
} }
/************************************************************************************************************************ /************************************************************************************************************************
* Returns index of Component/Entity array in System's EntitiesData struct Returns index of Component/Entity array in System's EntitiesData struct
*/ */
static long getIndexOfTypeInEntitiesData(EntitiesData, Type)() static long getIndexOfTypeInEntitiesData(EntitiesData, Type)()
{ {