Compare commits

..

2 commits

Author SHA1 Message Date
1a5452d6cc Improve fullName template
fullName now support multi-pararmeter templates
2023-05-24 22:15:05 +02:00
6a600d22c8 Refactored fullName template
New fullName implementation gives same result as fullyQualifiedName for normal types and templated ones, and still works in BetterC
2023-04-27 23:09:21 +02:00
12 changed files with 260 additions and 78 deletions

View file

@ -13,7 +13,7 @@ def compile(sources, output):
if file_extension == '.d' and filename != 'package': if file_extension == '.d' and filename != 'package':
files.append(os.path.join(r, file)) files.append(os.path.join(r, file))
ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-emscripten -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' '
for path in sources: for path in sources:
ldc_cmd += '-I' + path + ' ' ldc_cmd += '-I' + path + ' '
@ -33,7 +33,7 @@ def compile(sources, output):
shared_flags = '' shared_flags = ''
clean = 0 clean = 0
emc_flags = '' emc_flags = ''
ldc_flags = '' ldc_flags = '--d-version=ECSEmscripten '
import_paths = ['source','tests'] import_paths = ['source','tests']
build_tests = 0 build_tests = 0

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 = []
@ -13,7 +14,7 @@ def compile(sources, output):
if file_extension == '.d' and filename != 'package': if file_extension == '.d' and filename != 'package':
files.append(os.path.join(r, file)) files.append(os.path.join(r, file))
ldc_cmd = compiler + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-emscripten -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' ldc_cmd = compiler + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' '
for path in sources: for path in sources:
ldc_cmd += '-I' + path + ' ' ldc_cmd += '-I' + path + ' '
@ -40,7 +41,7 @@ only_bc = 0
multi = 0 multi = 0
sources = ['tests', 'source'] sources = ['tests', 'source']
emc_flags = '-s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS="[\'png\']" ' emc_flags = '-s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS="[\'png\']" '
ldc_flags = '--d-version=SDL_209 --d-version=BindSDL_Static --d-version=BindSDL_Image --d-version=MM_USE_POSIX_THREADS ' ldc_flags = '--d-version=ECSEmscripten --d-version=SDL_209 --d-version=BindSDL_Static --d-version=BindSDL_Image --d-version=MM_USE_POSIX_THREADS '
import_paths = ['external/sources', 'external/imports', 'external/wasm_imports', '../source', 'utils/source', 'simple/source'] import_paths = ['external/sources', 'external/imports', 'external/wasm_imports', '../source', 'utils/source', 'simple/source']
for arg in sys.argv[1:]: for arg in sys.argv[1:]:
@ -120,9 +121,8 @@ emcc_cmd += 'demo.bc '
os.system("mkdir build") os.system("mkdir build")
# emscripten = imp.load_source('', os.path.expanduser("~") + '/.emscripten') emscripten = imp.load_source('', os.path.expanduser("~") + '/.emscripten')
# pack_cmd = emscripten.EMSCRIPTEN_ROOT + '/tools/file_packager.py build/assets.data --preload assets --js-output=build/assets.js' pack_cmd = emscripten.EMSCRIPTEN_ROOT + '/tools/file_packager.py build/assets.data --preload assets --js-output=build/assets.js'
pack_cmd = os.path.expandvars('$EMSDK/upstream/emscripten') + '/tools/file_packager.py build/assets.data --preload assets --js-output=build/assets.js'
print('Packafing files: ' + pack_cmd) print('Packafing files: ' + pack_cmd)
os.system(pack_cmd) os.system(pack_cmd)

View file

@ -58,7 +58,7 @@ threads_dep = dependency('threads')
d_versions = [] d_versions = []
deps = [] deps = []
if host_machine.cpu_family() == 'wasm32' if host_machine.cpu_family() == 'wasm32'
d_versions += 'ECSEmscripten'
else else
# meson incorectly adds "-s USE_PTHREADS=1" to ldc2 invocation whe pthreads is added as dependency # meson incorectly adds "-s USE_PTHREADS=1" to ldc2 invocation whe pthreads is added as dependency
# add it for non wasm builds # add it for non wasm builds

View file

@ -9,5 +9,124 @@ License: BSD 3-clause, see LICENSE file in project root folder.
*/ */
module bubel.ecs.atomic; module bubel.ecs.atomic;
public import core.atomic; version (Emscripten) version = ECSEmscripten;
version (ECSEmscripten)
{
import std.traits;
enum MemoryOrder
{
acq,
acq_rel,
raw,
rel,
seq
}
extern (C) ubyte emscripten_atomic_cas_u8(void* addr, ubyte oldVal, ubyte newVal) @nogc nothrow pure;
extern (C) ushort emscripten_atomic_cas_u16(void* addr, ushort oldVal, ushort newVal) @nogc nothrow pure;
extern (C) uint emscripten_atomic_cas_u32(void* addr, uint oldVal, uint newVal) @nogc nothrow pure;
extern (C) ubyte emscripten_atomic_load_u8(const void* addr) @nogc nothrow pure;
extern (C) ushort emscripten_atomic_load_u16(const void* addr) @nogc nothrow pure;
extern (C) uint emscripten_atomic_load_u32(const void* addr) @nogc nothrow pure;
extern (C) ubyte emscripten_atomic_store_u8(void* addr, ubyte val) @nogc nothrow pure;
extern (C) ushort emscripten_atomic_store_u16(void* addr, ushort val) @nogc nothrow pure;
extern (C) uint emscripten_atomic_store_u32(void* addr, uint val) @nogc nothrow pure;
extern (C) ubyte emscripten_atomic_add_u8(void* addr, ubyte val) @nogc nothrow pure;
extern (C) ushort emscripten_atomic_add_u16(void* addr, ushort val) @nogc nothrow pure;
extern (C) uint emscripten_atomic_add_u32(void* addr, uint val) @nogc nothrow pure;
extern (C) ubyte emscripten_atomic_sub_u8(void* addr, ubyte val) @nogc nothrow pure;
extern (C) ushort emscripten_atomic_sub_u16(void* addr, ushort val) @nogc nothrow pure;
extern (C) uint emscripten_atomic_sub_u32(void* addr, uint val) @nogc nothrow pure;
public pure nothrow @nogc Unqual!T atomicOp(string op, T, V1)(ref shared T val, V1 mod)
{
static if (op == "+=")
{
static if (is(T == byte) || is(T == ubyte))
return cast(Unqual!T)(emscripten_atomic_add_u8(cast(void*)&val,
cast(Unqual!T) mod) + 1);
else static if (is(T == short) || is(T == ushort))
return cast(Unqual!T)(emscripten_atomic_add_u16(cast(void*)&val,
cast(Unqual!T) mod) + 1);
else static if (is(T == int) || is(T == uint))
return cast(Unqual!T)(emscripten_atomic_add_u32(cast(void*)&val,
cast(Unqual!T) mod) + 1);
else
static assert(0);
}
else static if (op == "-=")
{
static if (is(T == byte) || is(T == ubyte))
return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val,
cast(Unqual!T) mod) - 1);
else static if (is(T == short) || is(T == ushort))
return cast(Unqual!T)(emscripten_atomic_sub_u16(cast(void*)&val,
cast(Unqual!T) mod) - 1);
else static if (is(T == int) || is(T == uint))
return cast(Unqual!T)(emscripten_atomic_sub_u32(cast(void*)&val,
cast(Unqual!T) mod) - 1);
else
static assert(0);
}
}
public pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val,
V newval)
{
alias UT = Unqual!T;
static if (is(UT == bool) || is(UT == byte) || is(UT == ubyte))
emscripten_atomic_store_u8(cast(void*)&val, cast(UT) newval);
else static if (is(UT == short) || is(UT == ushort))
emscripten_atomic_store_u16(cast(void*)&val, cast(UT) newval);
else static if (is(UT == int) || is(UT == uint))
emscripten_atomic_store_u32(cast(void*)&val, cast(UT) newval);
else
static assert(0);
}
public pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(
ref const T val)
{
alias UT = Unqual!T;
static if (is(UT == bool))
return emscripten_atomic_load_u8(cast(const void*)&val) != 0;
else static if (is(UT == byte) || is(UT == ubyte))
return emscripten_atomic_load_u8(cast(const void*)&val);
else static if (is(UT == short) || is(UT == ushort))
return emscripten_atomic_load_u16(cast(const void*)&val);
else static if (is(UT == int) || is(UT == uint))
return emscripten_atomic_load_u32(cast(const void*)&val);
else
static assert(0);
}
public pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq,
MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis)
{
alias UT = Unqual!T;
static if (is(UT == bool))
return emscripten_atomic_cas_u8(cast(void*) here,
cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis;
else static if (is(UT == byte) || is(UT == ubyte))
return emscripten_atomic_cas_u8(cast(void*) here,
cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis;
else static if (is(UT == short) || is(UT == ushort))
return emscripten_atomic_cas_u16(cast(void*) here,
cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis;
else static if (is(UT == int) || is(UT == uint))
return emscripten_atomic_cas_u32(cast(void*) here,
cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis;
else
static assert(0);
}
}
else
{
public import core.atomic;
}

View file

@ -44,7 +44,7 @@ struct Entity
return cast(T*)getComponent(becsID!T); return cast(T*)getComponent(becsID!T);
} }
export void* getComponent(ushort component_id) const void* getComponent(ushort component_id) const
{ {
EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this); EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this);
EntityManager.EntityInfo* info = block.type_info; EntityManager.EntityInfo* info = block.type_info;
@ -54,7 +54,7 @@ struct Entity
return (cast(void*)block + info.deltas[component_id] + block.entityIndex(&this) * gEntityManager.components[component_id].size); return (cast(void*)block + info.deltas[component_id] + block.entityIndex(&this) * gEntityManager.components[component_id].size);
} }
export bool hasComponent(ushort component_id) const bool hasComponent(ushort component_id) const
{ {
EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this); EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this);
EntityManager.EntityInfo* info = block.type_info; EntityManager.EntityInfo* info = block.type_info;
@ -62,7 +62,7 @@ struct Entity
return true; return true;
} }
export EntityMeta getMeta() const EntityMeta getMeta() const
{ {
EntityMeta meta; EntityMeta meta;
meta.block = gEntityManager.getMetaData(&this); meta.block = gEntityManager.getMetaData(&this);
@ -85,7 +85,7 @@ struct EntityMeta
return cast(T*)getComponent(becsID!T); return cast(T*)getComponent(becsID!T);
} }
export void* getComponent(ushort component_id) const void* getComponent(ushort component_id) const
{ {
const (EntityManager.EntityInfo)* info = block.type_info; const (EntityManager.EntityInfo)* info = block.type_info;
@ -95,7 +95,7 @@ struct EntityMeta
return (cast(void*)block + info.deltas[component_id] + index * gEntityManager.components[component_id].size); return (cast(void*)block + info.deltas[component_id] + index * gEntityManager.components[component_id].size);
} }
export bool hasComponent(ushort component_id) const bool hasComponent(ushort component_id) const
{ {
const EntityManager.EntityInfo* info = block.type_info; const EntityManager.EntityInfo* info = block.type_info;
if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false;
@ -133,7 +133,7 @@ export struct EntityTemplate
/************************************************************************************************************************ /************************************************************************************************************************
Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime. Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime.
*/ */
export void* getComponent(ushort component_id) const nothrow @nogc void* getComponent(ushort component_id) const nothrow @nogc
{ {
if(component_id >= info.tmpl_deltas.length || info.tmpl_deltas[component_id] == ushort.max)return null; if(component_id >= info.tmpl_deltas.length || info.tmpl_deltas[component_id] == ushort.max)return null;
return cast(void*)(entity_data.ptr + info.tmpl_deltas[component_id]); return cast(void*)(entity_data.ptr + info.tmpl_deltas[component_id]);

View file

@ -28,7 +28,7 @@ export ulong defaultHashFunc(T)(auto ref T t) nothrow @nogc
} }
} }
export ulong hash(byte[] array) nothrow @nogc ulong hash(byte[] array) nothrow @nogc
{ {
ulong hash = 0; ulong hash = 0;

View file

@ -27,8 +27,6 @@ alias SerializeVector = bubel.ecs.vector.Vector!ubyte;
///Global EntityManager used for everything. ///Global EntityManager used for everything.
export __gshared EntityManager* gEntityManager = null; export __gshared EntityManager* gEntityManager = null;
version(D_BetterC) version = NoDRuntime;
/************************************************************************************************************************ /************************************************************************************************************************
Entity manager is responsible for everything. Entity manager is responsible for everything.
@ -361,7 +359,7 @@ export struct EntityManager
void registerSystem(Sys)(int priority, const(char)[] pass_name) void registerSystem(Sys)(int priority, const(char)[] pass_name)
{ {
ushort pass = passes_map.get(pass_name, ushort.max); ushort pass = passes_map.get(pass_name, ushort.max);
version (NoDRuntime) version (D_BetterC)
assert(pass != ushort.max, "Update pass doesn't exist."); assert(pass != ushort.max, "Update pass doesn't exist.");
else else
assert(pass != ushort.max, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); assert(pass != ushort.max, "Update pass (Name " ~ pass_name ~ ") doesn't exist.");
@ -383,16 +381,17 @@ export struct EntityManager
assert(register_state, assert(register_state,
"registerSystem must be called between beginRegister() and endRegister()."); "registerSystem must be called between beginRegister() and endRegister().");
version (NoDRuntime) version (D_BetterC)
assert(pass < passes.length, "Update pass doesn't exist."); assert(pass < passes.length, "Update pass doesn't exist.");
else else
assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist.");
// enum SystemName = __traits(fullyQualifiedName,Sys);
// enum SystemName = fullyQualifiedName!Sys; // enum SystemName = fullyQualifiedName!Sys;
enum SystemName = fullName!Sys; enum SystemName = fullName!Sys;
//enum SystemName = Sys.stringof; //enum SystemName = Sys.stringof;
System system = System(); System system;
system.m_pass = pass; system.m_pass = pass;
// static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) // static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort))
@ -429,7 +428,8 @@ export struct EntityManager
{ {
alias EventParamType = Params[1]; alias EventParamType = Params[1];
enum EventName = fullName!(Unqual!(EventParamType)); enum EventName = fullName!(Unqual!(EventParamType));
// enum EventName = fullyQualifiedName!(Unqual!(EventParamType));//.stringof; // enum EventName = __traits(fullyQualifiedName,Unqual!(EventParamType));
// enum EventName = fullyQualifiedName!(Unqual!(EventParamType));
ushort evt = events_map.get(cast(char[]) EventName, ushort.max); ushort evt = events_map.get(cast(char[]) EventName, ushort.max);
assert(evt != ushort.max, assert(evt != ushort.max,
"Can't register system \"" ~ SystemName "Can't register system \"" ~ SystemName
@ -491,8 +491,10 @@ export struct EntityManager
string name; string name;
static if (isArray!MemberType) static if (isArray!MemberType)
{ // Workaround. This code is never called with: not an array type, but compiler prints an error { // Workaround. This code is never called with: not an array type, but compiler prints an error
// name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));//.stringof; // name = __traits(fullyQualifiedName,Unqual!(ForeachType!MemberType));
name = fullName!(Unqual!(typeof(MemberType.init[0]))); // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));
// name = fullName!(Unqual!(typeof(MemberType.init[0])));
name = fullName!(Unqual!(Unqual!(ForeachType!MemberType)));
} }
bool is_optional; bool is_optional;
@ -717,8 +719,9 @@ export struct EntityManager
string name; string name;
static if (isArray!MemberType) static if (isArray!MemberType)
{ // Workaround. This code is never called with: not an array type, but compiler prints an error { // Workaround. This code is never called with: not an array type, but compiler prints an error
// name = __traits(fullyQualifiedName,Unqual!(ForeachType!MemberType));
// name = fullyQualifiedName!(Unqual!(ForeachType!MemberType)); // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));
name = fullName!(Unqual!(typeof(MemberType.init[0]))); name = fullName!(Unqual!(ForeachType!MemberType));
//name = Unqual!(ForeachType!MemberType).stringof; //name = Unqual!(ForeachType!MemberType).stringof;
} }
@ -842,7 +845,7 @@ export struct EntityManager
foreach (iii, comp_info; components_info.req) foreach (iii, comp_info; components_info.req)
{ {
ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
version (NoDRuntime) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ SystemName "Can't register system \"" ~ SystemName
~ "\" due to non existing component."); ~ "\" due to non existing component.");
@ -854,7 +857,7 @@ export struct EntityManager
foreach (iii, comp_info; components_info.excluded) foreach (iii, comp_info; components_info.excluded)
{ {
ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
version (NoDRuntime) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ SystemName "Can't register system \"" ~ SystemName
~ "\" due to non existing component."); ~ "\" due to non existing component.");
@ -866,7 +869,7 @@ export struct EntityManager
foreach (iii, comp_info; components_info.optional) foreach (iii, comp_info; components_info.optional)
{ {
ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
version (NoDRuntime) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ SystemName "Can't register system \"" ~ SystemName
~ "\" due to non existing component."); ~ "\" due to non existing component.");
@ -878,7 +881,7 @@ export struct EntityManager
foreach (iii, comp_info; components_info.readonly) foreach (iii, comp_info; components_info.readonly)
{ {
ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
version (NoDRuntime) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ SystemName "Can't register system \"" ~ SystemName
~ "\" due to non existing component."); ~ "\" due to non existing component.");
@ -890,7 +893,7 @@ export struct EntityManager
foreach (iii, comp_info; components_info.mutable) foreach (iii, comp_info; components_info.mutable)
{ {
ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
version (NoDRuntime) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ SystemName "Can't register system \"" ~ SystemName
~ "\" due to non existing component."); ~ "\" due to non existing component.");
@ -1200,7 +1203,7 @@ export struct EntityManager
{ {
ushort comp = external_dependencies_map.get(cast(const(char)[]) comp_info.type, ushort comp = external_dependencies_map.get(cast(const(char)[]) comp_info.type,
ushort.max); ushort.max);
version (NoDRuntime) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ SystemName "Can't register system \"" ~ SystemName
~ "\" due to non existing dependency."); ~ "\" due to non existing dependency.");
@ -1213,7 +1216,7 @@ export struct EntityManager
foreach (iii, comp_info; components_info.writableDeps) foreach (iii, comp_info; components_info.writableDeps)
{ {
ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max); ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max);
version (NoDRuntime) version (D_BetterC)
assert(comp != ushort.max, assert(comp != ushort.max,
"Can't register system \"" ~ SystemName "Can't register system \"" ~ SystemName
~ "\" due to non existing dependency."); ~ "\" due to non existing dependency.");
@ -1298,6 +1301,7 @@ export struct EntityManager
{ {
ComponentInfo info; ComponentInfo info;
// enum ComponentName = __traits(fullyQualifiedName,Comp);
// enum ComponentName = fullyQualifiedName!Comp; // enum ComponentName = fullyQualifiedName!Comp;
enum ComponentName = fullName!Comp; enum ComponentName = fullName!Comp;
// enum ComponentName = Comp.stringof; // enum ComponentName = Comp.stringof;
@ -3357,16 +3361,6 @@ export struct EntityManager
export ~this() nothrow @nogc 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 ///Component size
ushort size; ushort size;
///Component data alignment ///Component data alignment

View file

@ -7,9 +7,11 @@ License: BSD 3-clause, see LICENSE file in project root folder.
*/ */
module bubel.ecs.std; module bubel.ecs.std;
version (Emscripten) version = ECSEmscripten;
import std.traits; import std.traits;
version (Emscripten) version (ECSEmscripten)
{ {
extern (C) struct pthread_mutex_t extern (C) struct pthread_mutex_t
{ {
@ -27,6 +29,10 @@ version (Emscripten)
extern (C) int memcmp(const void* s1, const void* s2, size_t size); extern (C) int memcmp(const void* s1, const void* s2, size_t size);
extern (C) void exit(int status) nothrow @nogc; extern (C) void exit(int status) nothrow @nogc;
extern (C) void __assert(const(char)* msg, const(char)* file, uint line)
{
exit(-20);
}
extern (C) void free(void*) @nogc nothrow @system; extern (C) void free(void*) @nogc nothrow @system;
extern (C) void* malloc(size_t size) @nogc nothrow @system; extern (C) void* malloc(size_t size) @nogc nothrow @system;
@ -54,7 +60,7 @@ else
public import core.stdc.stdlib : qsort; public import core.stdc.stdlib : qsort;
} }
version (Emscripten) version (ECSEmscripten)
{ {
} }
else version (Windows) else version (Windows)
@ -83,7 +89,7 @@ else version (Posix)
import core.sys.posix.stdlib : posix_memalign; import core.sys.posix.stdlib : posix_memalign;
} }
version (Emscripten) version (ECSEmscripten)
{ {
private const uint max_alloca = 10000; private const uint max_alloca = 10000;
private __gshared byte[max_alloca] alloca_array; private __gshared byte[max_alloca] alloca_array;
@ -288,7 +294,7 @@ static struct Mallocator
posix_memalign(&ret, alignment, length); //ret = aligned_alloc(alignment, length); posix_memalign(&ret, alignment, length); //ret = aligned_alloc(alignment, length);
else version (Windows) else version (Windows)
ret = _aligned_malloc(length, alignment); ret = _aligned_malloc(length, alignment);
else version (Emscripten) else version (ECSEmscripten)
posix_memalign(&ret, alignment, length); //malloc(length); posix_memalign(&ret, alignment, length); //malloc(length);
else else
static assert(0, "Unimplemented platform!"); static assert(0, "Unimplemented platform!");
@ -335,7 +341,7 @@ static struct Mallocator
free(cast(void*) object); free(cast(void*) object);
else version (Windows) else version (Windows)
_aligned_free(cast(void*) object); _aligned_free(cast(void*) object);
else version (Emscripten) else version (ECSEmscripten)
free(cast(void*) object); free(cast(void*) object);
else else
static assert(0, "Unimplemented platform!"); static assert(0, "Unimplemented platform!");
@ -345,7 +351,7 @@ static struct Mallocator
struct Mutex struct Mutex
{ {
version (Emscripten) version (ECSEmscripten)
{ {
void initialize() nothrow @nogc void initialize() nothrow @nogc
{ {

View file

@ -13,14 +13,14 @@ import bubel.ecs.manager;
System contain data required to proper glue EntityManager with Systems. System contain data required to proper glue EntityManager with Systems.
System callbacks: System callbacks:
$(LIST $(LIST
* void onUpdate(EntitiesData); * void onUpdate(EntitesData);
* void onEnable() - called inside system.enable() function * void onEnable() - called inside system.enable() function
* void onDisable() - called inside system.disable() function * void onDisable() - called inside system.disable() function
* bool onBegin() - called inside manager.begin() * bool onBegin() - called inside manager.begin()
* void onEnd() - called inside manager.end() * void onEnd() - called inside manager.end()
* void onCreate() - called after registration inside registerSystem function * void onCreate() - called after registration inside registerSystem function
* void onDestroy() - called during re-registration and inside manager destructor * void onDestroy() - called during re-registration and inside manager destructor
* void onAddEntity(EntitiesData) - called for every entity which are assigned to system (by adding new entity or changing its components) * void onAddEntity(EntitesData) - called for every entity which are assigned to system (by adding new entity or changing its components)
* void onRemoveEntity(EntitiesData) - called for every entity removed from system update process * void onRemoveEntity(EntitiesData) - called for every entity removed from system update process
* void onChangeEntity(EntitiesData) - called for every entity which components are changed but it was previously assigned to system * void onChangeEntity(EntitiesData) - called for every entity which components are changed but it was previously assigned to system
* void handleEvent(Entity*, Event) - called for every event supported by system * void handleEvent(Entity*, Event) - called for every event supported by system
@ -108,7 +108,7 @@ struct System
package: package:
///destory system. Dispose all data ///destory system. Dispose all data
export void destroy() nothrow @nogc void destroy() nothrow @nogc
{ {
import bubel.ecs.std : Mallocator; import bubel.ecs.std : Mallocator;

View file

@ -63,34 +63,30 @@ static long getIndexOfTypeInEntitiesData(EntitiesData, Type)()
return index; return index;
} }
static string attachParentName(alias T, string str)() template fullName(alias T : X!A, alias X, A...)
{ {
alias parent = __traits(parent, T); alias parent = __traits(parent, X);
enum parent_str = parent.stringof; enum fullName = fullName!parent ~ '.' ~ __traits(identifier, X) ~ "!(" ~ fullName!A ~ ")";
static if(parent_str[0..7] == "module ")
{
static if(__traits(compiles, __traits(parent, parent)))
{
return attachParentName!(parent, parent_str[7 .. $] ~ '.' ~ str);
}
else return parent_str[7 .. $] ~ '.' ~ str;
}
else static if(parent_str[0..8] == "package ")
{
static if(__traits(compiles, __traits(parent, parent)))
{
return attachParentName!(parent, parent_str[8 .. $] ~ '.' ~ str);
}
else return parent_str[8 .. $] ~ '.' ~ str;
}
else static if(__traits(compiles, __traits(parent, parent)))
{
return attachParentName!(parent, parent_str ~ '.' ~ str);
}
else return parent_str ~ '.' ~ str;
} }
static string fullName(T)() template fullName(T...)
{ {
return attachParentName!(T, T.stringof); static if(__traits(compiles, __traits(parent, T[0])))
{
alias parent = __traits(parent, T[0]);
enum fullName = fullName!parent ~ '.' ~ __traits(identifier, T[0]) ~ ", " ~ fullName!(T[1 .. $]);
}
else static if(__traits(compiles, __traits(identifier, T[0])))enum fullName = __traits(identifier, T[0]) ~ ", " ~ fullName!(T[1 .. $]);
else enum fullName = T[0].stringof ~ ", " ~ fullName!(T[1 .. $]);
}
template fullName(alias T)
{
static if(__traits(compiles, __traits(parent, T)))
{
alias parent = __traits(parent, T);
enum fullName = fullName!parent ~ '.' ~ __traits(identifier, T);
}
else static if(__traits(compiles, __traits(identifier, T)))enum fullName = __traits(identifier, T);
else enum fullName = T.stringof;
} }

View file

@ -160,6 +160,22 @@ void afterEveryTest()
gEntityManager.destroy(); gEntityManager.destroy();
} }
@("RegisteredNames")
unittest
{
import bubel.ecs.traits;
gEntityManager.beginRegister();
gEntityManager.registerSystem!EmptySystem(0);
gEntityManager.registerSystem!EntityCounterSystem(0);
gEntityManager.endRegister();
System* empty_system = gEntityManager.getSystem(becsID!EmptySystem);
System* counter_system = gEntityManager.getSystem(becsID!EntityCounterSystem);
assert(empty_system.name == "tests.basic.EmptySystem", fullName!EmptySystem);
assert(counter_system.name == "tests.basic.EntityCounterSystem", fullName!EntityCounterSystem);
}
@("EntityMeta") @("EntityMeta")
unittest unittest
{ {

View file

@ -173,3 +173,54 @@ unittest
gEntityManager.destroy(); gEntityManager.destroy();
} }
@("3-template-system-compilation-file")
unittest
{
struct TemplateSystem(T)
{
struct EntitiesData
{
uint length;
}
T a;
}
struct TemplateSystem2(T, T2, T3)
{
struct EntitiesData
{
uint length;
}
T a;
T2 b;
T3 c;
}
struct TempalteComponent(T)
{
T parameter;
}
struct TempalteComponent2(T, T2)
{
T parameter;
T2 parameter2;
}
gEntityManager.initialize(0);
gEntityManager.beginRegister();
gEntityManager.registerComponent!CInt;
gEntityManager.registerComponent!(TempalteComponent!uint);
gEntityManager.registerComponent!(TempalteComponent2!(float,int));
gEntityManager.registerSystem!(TemplateSystem!CInt)(0);
gEntityManager.registerSystem!(TemplateSystem2!(CInt, uint, float))(0);
gEntityManager.endRegister();
}