From 0281fd5c1dd11547dfc7e99c8d36ba07a528bf0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Masiukiewicz?= Date: Thu, 27 Oct 2022 22:33:23 +0200 Subject: [PATCH 01/14] Remove unnecessary exports If given type is not used across library interface it's methods can stay private. As of now this is only test as I am not sure if it doesn't cause problems in wasm build. --- source/bubel/ecs/hash_map.d | 44 +++++++++++----------- source/bubel/ecs/vector.d | 74 ++++++++++++++++++------------------- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/source/bubel/ecs/hash_map.d b/source/bubel/ecs/hash_map.d index 1af0fd8..4b4206c 100755 --- a/source/bubel/ecs/hash_map.d +++ b/source/bubel/ecs/hash_map.d @@ -72,31 +72,31 @@ nothrow: size_t length; // Used to compute loadFactor size_t markerdDeleted; - export void clear() + void clear() { elements.clear(); length = 0; markerdDeleted = 0; } - export void reset() + void reset() { elements.reset(); length = 0; markerdDeleted = 0; } - export bool isIn(ref Key el) + bool isIn(ref Key el) { return getIndex(el) != getIndexEmptyValue; } - export bool isIn(Key el) + bool isIn(Key el) { return getIndex(el) != getIndexEmptyValue; } - export Value* getPtr()(auto ref Key k) + Value* getPtr()(auto ref Key k) { size_t index = getIndex(k); if (index == getIndexEmptyValue) @@ -109,20 +109,20 @@ nothrow: } } - export ref Value get()(auto ref Key k) + ref Value get()(auto ref Key k) { size_t index = getIndex(k); assert(index != getIndexEmptyValue); return elements[index].keyValue.value; } - deprecated("Use get with second parameter.") export auto ref Value getDefault()( + deprecated("Use get with second parameter.") auto ref Value getDefault()( auto ref Key k, auto ref Value defaultValue) { return get(k, defaultValue); } - export auto ref Value get()(auto ref Key k, auto ref Value defaultValue) + auto ref Value get()(auto ref Key k, auto ref Value defaultValue) { size_t index = getIndex(k); if (index == getIndexEmptyValue) @@ -135,7 +135,7 @@ nothrow: } } - export ref Value getInsertDefault()(auto ref Key k, auto ref Value defaultValue) + ref Value getInsertDefault()(auto ref Key k, auto ref Value defaultValue) { size_t index = getIndex(k); if (index == getIndexEmptyValue) @@ -148,7 +148,7 @@ nothrow: } - export bool tryRemove(Key el) + bool tryRemove(Key el) { size_t index = getIndex(el); if (index == getIndexEmptyValue) @@ -161,23 +161,23 @@ nothrow: return true; } - export void remove(Key el) + void remove(Key el) { bool ok = tryRemove(el); assert(ok); } - export ref Value opIndex()(auto ref Key key) + ref Value opIndex()(auto ref Key key) { return get(key); } - export void opIndexAssign()(auto ref Value value, auto ref Key key) + void opIndexAssign()(auto ref Value value, auto ref Key key) { add(key, value); } - export void add()(auto ref Key key, auto ref Value value) + void add()(auto ref Key key, auto ref Value value) { size_t index = getIndex(key); if (index != getIndexEmptyValue) @@ -221,12 +221,12 @@ nothrow: //int numA; //int numB; - export size_t getIndex(Key el) + size_t getIndex(Key el) { return getIndex(el); } - export size_t getIndex(ref Key el) + size_t getIndex(ref Key el) { mixin(doNotInline); @@ -260,7 +260,7 @@ nothrow: } - export float getLoadFactor(size_t forElementsNum) + float getLoadFactor(size_t forElementsNum) { if (elements.length == 0) { @@ -269,7 +269,7 @@ nothrow: return cast(float) forElementsNum / (elements.length); } - export void rehash()() + void rehash()() { mixin(doNotInline); // Get all elements @@ -303,7 +303,7 @@ nothrow: } // foreach support - export int opApply(DG)(scope DG dg) + int opApply(DG)(scope DG dg) { int result; foreach (ref Bucket gr; elements) @@ -336,7 +336,7 @@ nothrow: return result; } - export int byKey(scope int delegate(ref Key k) dg) + int byKey(scope int delegate(ref Key k) dg) { int result; foreach (ref Key k; this) @@ -348,7 +348,7 @@ nothrow: return result; } - export int byValue(scope int delegate(ref Value v) dg) + int byValue(scope int delegate(ref Value v) dg) { int result; foreach (ref Value v; this) @@ -360,7 +360,7 @@ nothrow: return result; } - export int byKeyValue(scope int delegate(ref Key k, ref Value v) dg) + int byKeyValue(scope int delegate(ref Key k, ref Value v) dg) { int result; foreach (ref Key k, ref Value v; this) diff --git a/source/bubel/ecs/vector.d b/source/bubel/ecs/vector.d index e9b061d..f1c9d52 100644 --- a/source/bubel/ecs/vector.d +++ b/source/bubel/ecs/vector.d @@ -14,13 +14,13 @@ import bubel.ecs.std; import std.conv : emplace; import std.traits : hasMember, isCopyable, TemplateOf, Unqual; -export @nogc @safe nothrow pure size_t nextPow2(size_t num) +@nogc @safe nothrow pure size_t nextPow2(size_t num) { return 1 << bsr(num) + 1; } -export __gshared size_t gVectorsCreated = 0; -export __gshared size_t gVectorsDestroyed = 0; +__gshared size_t gVectorsCreated = 0; +__gshared size_t gVectorsDestroyed = 0; struct Vector(T) { @@ -28,19 +28,19 @@ struct Vector(T) size_t used; public: - export this()(T t) + this()(T t) { add(t); } - export this(X)(X[] t) if (is(Unqual!X == Unqual!T)) + this(X)(X[] t) if (is(Unqual!X == Unqual!T)) { add(t); } /*static if (isCopyable!T) { - export this(this) { + this(this) { T[] tmp = array[0 .. used]; array = null; used = 0; @@ -52,17 +52,17 @@ public: @disable this(this); - export ~this() + ~this() { clear(); } - export void clear() + void clear() { removeAll(); } - export void removeAll() + void removeAll() { if (array !is null) { @@ -77,17 +77,17 @@ public: used = 0; } - export bool empty() const + bool empty() const { return (used == 0); } - export size_t length() const + size_t length() const { return used; } - export void length(size_t newLength) + void length(size_t newLength) { if (newLength > used) { @@ -111,12 +111,12 @@ public: used = newLength; } - export void reset() + void reset() { used = 0; } - export void reserve(size_t numElements) + void reserve(size_t numElements) { if (numElements > array.length) { @@ -124,12 +124,12 @@ public: } } - export size_t capacity() + size_t capacity() { return array.length - used; } - export void extend(size_t newNumOfElements) + void extend(size_t newNumOfElements) { auto oldArray = manualExtend(array, newNumOfElements); if (oldArray !is null) @@ -138,14 +138,14 @@ public: } } - export @nogc void freeData(void[] data) + @nogc void freeData(void[] data) { // 0x0F probably invalid value for pointers and other types memset(data.ptr, 0x0F, data.length); // Makes bugs show up xD free(data.ptr); } - export static void[] manualExtend(ref T[] array, size_t newNumOfElements = 0) + static void[] manualExtend(ref T[] array, size_t newNumOfElements = 0) { if (newNumOfElements == 0) newNumOfElements = 2; @@ -161,7 +161,7 @@ public: return (cast(void*) oldArray.ptr)[0 .. oldArray.length * T.sizeof]; } - export Vector!T copy()() + Vector!T copy()() { Vector!T duplicate; duplicate.reserve(used); @@ -169,12 +169,12 @@ public: return duplicate; } - /*export bool canAddWithoutRealloc(uint elemNum = 1) + /*bool canAddWithoutRealloc(uint elemNum = 1) { return used + elemNum <= array.length; }*/ - export void add()(T t) + void add()(T t) { if (used >= array.length) { @@ -185,7 +185,7 @@ public: } /// Add element at given position moving others - export void add()(T t, size_t pos) + void add()(T t, size_t pos) { assert(pos <= used); if (used >= array.length) @@ -201,7 +201,7 @@ public: used++; } - export void add(X)(X[] t) if (is(Unqual!X == Unqual!T)) + void add(X)(X[] t) if (is(Unqual!X == Unqual!T)) { if (used + t.length > array.length) { @@ -214,7 +214,7 @@ public: used += t.length; } - export void remove(size_t elemNum) + void remove(size_t elemNum) { //destroy(array[elemNum]); static if (__traits(hasMember, T, "__xdtor")) @@ -226,7 +226,7 @@ public: used--; } - export void removeStable()(size_t elemNum) + void removeStable()(size_t elemNum) { used--; foreach (i; 0 .. used) @@ -235,7 +235,7 @@ public: } } - export bool tryRemoveElement()(T elem) + bool tryRemoveElement()(T elem) { foreach (i, ref el; array[0 .. used]) { @@ -248,65 +248,65 @@ public: return false; } - export void removeElement()(T elem) + void removeElement()(T elem) { bool ok = tryRemoveElement(elem); assert(ok, "There is no such an element in vector"); } - export ref T opIndex(size_t elemNum) const + ref T opIndex(size_t elemNum) const { //debug assert(elemNum < used, "Range violation [index]"); return *cast(T*)&array.ptr[elemNum]; } - export auto opSlice() + auto opSlice() { return array.ptr[0 .. used]; } - export T[] opSlice(size_t x, size_t y) + T[] opSlice(size_t x, size_t y) { assert(y <= used); return array.ptr[x .. y]; } - export size_t opDollar() + size_t opDollar() { return used; } - export void opAssign(X)(X[] slice) + void opAssign(X)(X[] slice) { reset(); this ~= slice; } - export void opOpAssign(string op)(T obj) + void opOpAssign(string op)(T obj) { //static assert(op == "~"); add(obj); } - export void opOpAssign(string op, X)(X[] obj) + void opOpAssign(string op, X)(X[] obj) { //static assert(op == "~"); add(obj); } - export void opIndexAssign()(T obj, size_t elemNum) + void opIndexAssign()(T obj, size_t elemNum) { assert(elemNum < used, "Range viloation"); array[elemNum] = obj; } - export void opSliceAssign()(T[] obj, size_t a, size_t b) + void opSliceAssign()(T[] obj, size_t a, size_t b) { assert(b <= used && a <= b, "Range viloation"); array.ptr[a .. b] = obj; } - export bool opEquals()(auto ref const Vector!(T) r) const + bool opEquals()(auto ref const Vector!(T) r) const { return used == r.used && array.ptr[0 .. used] == r.array.ptr[0 .. r.used]; } From 7a614686c8899ef66f99c1136282c33f9922749f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Masiukiewicz?= Date: Tue, 8 Nov 2022 22:05:57 +0100 Subject: [PATCH 02/14] Export id generated by becsID --- source/bubel/ecs/traits.d | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/bubel/ecs/traits.d b/source/bubel/ecs/traits.d index 15880fd..42b1753 100644 --- a/source/bubel/ecs/traits.d +++ b/source/bubel/ecs/traits.d @@ -11,8 +11,11 @@ import std.traits; */ ref ushort becsID(T)() { - __gshared ushort id = ushort.max; - return id; + /// Embed id in struct so export can be added to variable definition + static struct LocalStruct { + export __gshared ushort id = ushort.max; + } + return LocalStruct.id; } /************************************************************************************************************************ From 5f4ba90b3e97746f7560ca7ce8b59b07fda8a83c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Masiukiewicz?= Date: Thu, 10 Nov 2022 10:18:46 +0100 Subject: [PATCH 03/14] Add unregisterSystem functionality --- source/bubel/ecs/manager.d | 29 +++++++++++++++++++++++++++++ source/bubel/ecs/system.d | 8 ++++++++ 2 files changed, 37 insertions(+) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 7861649..3140ca2 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -172,6 +172,8 @@ export struct EntityManager foreach (ref system; systems) { + if (system.isAlive() == false) + continue; if (system.m_empty) { if (system.m_update) @@ -236,6 +238,8 @@ export struct EntityManager foreach (ref system; systems) { + if (system.isAlive() == false) + continue; foreach (caller; system.m_event_callers) { event_callers[caller.id]++; @@ -252,6 +256,8 @@ export struct EntityManager foreach (ref system; systems) { + if (system.isAlive() == false) + continue; foreach (caller; system.m_event_callers) { events[caller.id].callers[event_callers[caller.id]].callback = caller.callback; @@ -328,6 +334,21 @@ export struct EntityManager allocator.freeMemory(); } + + /************************************************************************************************************************ + Unregister given system form EntityManager. + */ + void unregisterSystem(Sys)() + { + assert(register_state, "unregisterSystem must be called between beginRegister() and endRegister()."); + ushort system_id = becsID!Sys; + System* system = getSystem(system_id); + assert(system, "System was not registered"); + assert(system.isAlive, "System already unregistered"); + system.destroy(); + *system = System.init; + } + /************************************************************************************************************************ Same as "void registerSystem(Sys)(int priority, int pass = 0)" but use pass name instead of id. */ @@ -1887,6 +1908,8 @@ export struct EntityManager foreach (i, ref system; systems) { + if (system.isAlive() == false) + continue; if (system.m_empty) continue; if (system.m_update is null) @@ -3095,6 +3118,8 @@ export struct EntityManager foreach (ref system; systems) { + if (system.isAlive() == false) + continue; if (system.enabled && system.m_begin) system.m_execute = (cast(bool function(void*)) system.m_begin)( system.m_system_pointer); @@ -3109,6 +3134,10 @@ export struct EntityManager foreach (ref system; systems) { + if (system.isAlive() == false) + { + continue; + } if (system.enabled && system.m_end) (cast(void function(void*)) system.m_end)(system.m_system_pointer); } diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index e571e8b..0da2d96 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -89,6 +89,14 @@ struct System return cast(const(char)[]) m_name; } + /************************************************************************************************************************ + Return false if system was unregistered, true otherwise. + */ + export bool isAlive() nothrow @nogc + { + return m_system_pointer != null; + } + package: void destroy() From c2ba4c632a4767931478380c77c68c73eeb1bfd9 Mon Sep 17 00:00:00 2001 From: Mergul Date: Sat, 12 Nov 2022 12:10:09 +0100 Subject: [PATCH 04/14] Fixes -Assert if callEntitiesFunction is called for system which is not alive -cleanup and formatting --- dub.json | 2 +- source/bubel/ecs/manager.d | 235 +++++++++++++++++++------------------ 2 files changed, 121 insertions(+), 116 deletions(-) diff --git a/dub.json b/dub.json index b3bfa66..1461c9d 100755 --- a/dub.json +++ b/dub.json @@ -63,7 +63,7 @@ ], "dflags": [ "-unittest", - "-cov" + "-cov=ctfe" ] }, { diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 3140ca2..323d2ab 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -69,11 +69,10 @@ export struct EntityManager Initialize ECS. */ export static void initialize(uint threads_count = 1, uint page_size = 32768, - uint block_pages_count = 128) + uint block_pages_count = 128) { if (gEntityManager is null) { - //gEntityManager = Mallocator.make!EntityManager(threads_count); gEntityManager = Mallocator.make!EntityManager(threads_count, page_size, block_pages_count); with (gEntityManager) @@ -183,7 +182,7 @@ export struct EntityManager if (system.m_update is null) { if (system.m_add_entity || system.m_remove_entity - || system.m_change_entity || system.m_event_callers.length) + || system.m_change_entity || system.m_event_callers.length) { foreach (info; &entities_infos.byValue) { @@ -281,7 +280,7 @@ export struct EntityManager foreach (ref event; events) { qsort(event.callers.ptr, event.callers.length, - EventCaller.sizeof, &comapreEventCaller); + EventCaller.sizeof, &comapreEventCaller); } //qsort(event_callers.ptr, event_callers.length, EventInfo.sizeof, &compareUShorts); @@ -334,17 +333,19 @@ export struct EntityManager allocator.freeMemory(); } - /************************************************************************************************************************ Unregister given system form EntityManager. */ void unregisterSystem(Sys)() { - assert(register_state, "unregisterSystem must be called between beginRegister() and endRegister()."); + assert(register_state, "unregisterSystem must be called between beginRegister() and endRegister()."); + ushort system_id = becsID!Sys; System* system = getSystem(system_id); + assert(system, "System was not registered"); assert(system.isAlive, "System already unregistered"); + system.destroy(); *system = System.init; } @@ -376,7 +377,7 @@ export struct EntityManager //alias STC = ParameterStorageClass; assert(register_state, - "registerSystem must be called between beginRegister() and endRegister()."); + "registerSystem must be called between beginRegister() and endRegister()."); version (D_BetterC) assert(pass < passes.length, "Update pass doesn't exist."); else @@ -426,7 +427,7 @@ export struct EntityManager // enum EventName = fullyQualifiedName!(Unqual!(EventParamType));//.stringof; ushort evt = events_map.get(cast(char[]) EventName, ushort.max); assert(evt != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing event \"" ~ EventName ~ "\"."); callers[i].callback = cast(void*)&callEventHandler!(EventParamType); @@ -469,14 +470,14 @@ export struct EntityManager bool checkExcludedComponentsSomething(Sys)() { return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, - typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); + typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); } foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); if (member == "length" || member == "thread_id" || member == "job_id" - || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { //continue; } @@ -659,7 +660,7 @@ export struct EntityManager } static void allocateSystemComponents(ComponentsIndices!component_counts components_info)( - ref System system) + ref System system) { size_t req = components_info.req.length; size_t opt = components_info.optional.length; @@ -693,14 +694,14 @@ export struct EntityManager bool checkExcludedComponentsSomething(Sys)() { return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string, - typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); + typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents); } foreach (member; __traits(allMembers, Sys.EntitiesData)) { alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member)); if (member == "length" || member == "thread_id" || member == "job_id" - || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) + || is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) { if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[])) components_info.entites_array = member; @@ -808,23 +809,23 @@ export struct EntityManager else static if (member == "length") { static assert(isIntegral!(MemberType), - "EntitiesData 'length' member must be integral type."); + "EntitiesData 'length' member must be integral type."); static assert(MemberType.sizeof > 1, - "EntitiesData 'length' member can't be byte or ubyte."); + "EntitiesData 'length' member can't be byte or ubyte."); } else static if (member == "thread_id") { static assert(isIntegral!(MemberType), - "EntitiesData 'thread_id' member must be integral type."); + "EntitiesData 'thread_id' member must be integral type."); static assert(MemberType.sizeof > 1, - "EntitiesData 'thread_id' member can't be byte or ubyte."); + "EntitiesData 'thread_id' member can't be byte or ubyte."); } else static if (member == "job_id") { static assert(isIntegral!(MemberType), - "EntitiesData 'job_id' member must be integral type."); + "EntitiesData 'job_id' member must be integral type."); static assert(MemberType.sizeof > 1, - "EntitiesData 'job_id' member can't be byte or ubyte."); + "EntitiesData 'job_id' member can't be byte or ubyte."); } else static if (!(isArray!(MemberType))) static assert(0, "EntitiesData members should be arrays of elements!"); @@ -838,7 +839,7 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -850,7 +851,7 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -862,7 +863,7 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -874,7 +875,7 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -886,7 +887,7 @@ export struct EntityManager ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -896,14 +897,14 @@ export struct EntityManager } static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info, - EntitiesBlock* block, uint offset, uint entities_count, System* system) + EntitiesBlock* block, uint offset, uint entities_count, System* system) { //enum ComponentsIndices components_info = getComponentsInfo(); static if (components_info.entites_array) { __traits(getMember, input_data, components_info.entites_array) = ( - cast(Entity*) block.dataBegin())[offset .. entities_count]; + cast(Entity*) block.dataBegin())[offset .. entities_count]; } static if (hasMember!(Sys.EntitiesData, "length")) @@ -923,8 +924,7 @@ export struct EntityManager __traits(getMember, input_data, comp_info.name) = ( cast(typeof( (typeof(__traits(getMember, Sys.EntitiesData, comp_info.name))).init[0] - )*) - (cast(void*) block + info.deltas[system.m_components[iii]]) + )*)(cast(void*) block + info.deltas[system.m_components[iii]]) )[offset .. entities_count]; } @@ -932,7 +932,7 @@ export struct EntityManager .. components_info.m_optional_counter]) { if (system.m_optional_components[iii] < info.deltas.length - && info.deltas[system.m_optional_components[iii]] != 0) + && info.deltas[system.m_optional_components[iii]] != 0) { __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember, Sys.EntitiesData, comp_info.name)))*)(cast( @@ -1031,7 +1031,7 @@ export struct EntityManager static if (hasMember!(Sys.EntitiesData, "thread_id")) { input_data.thread_id = cast( - typeof(input_data.thread_id)) data.thread_id; + typeof(input_data.thread_id)) data.thread_id; } static if (hasMember!(Sys.EntitiesData, "job_id")) @@ -1042,7 +1042,7 @@ export struct EntityManager //s.onUpdate(input_data); (cast(typeof(&__traits(getOverloads, s, "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)( - input_data); + input_data); } block = block.next_block; offset = 0; @@ -1112,15 +1112,15 @@ export struct EntityManager foreach (func; __traits(getOverloads, Sys, func_name)) { static if ((Parameters!(func)).length == 1 - && is(Parameters!(func)[0] == Sys.EntitiesData) - && is(ReturnType!(func) == RetType)) + && is(Parameters!(func)[0] == Sys.EntitiesData) + && is(ReturnType!(func) == RetType)) { static RetType callFunc(ref ListenerCallData data) { Sys* s = cast(Sys*) data.system.m_system_pointer; Sys.EntitiesData input_data; fillInputData(input_data, data.block.type_info, - data.block, data.begin, data.end, data.system); + data.block, data.begin, data.end, data.system); static if (is(RetTyp == void)) mixin("s." ~ func_name ~ "(input_data)"); else @@ -1141,8 +1141,8 @@ export struct EntityManager foreach (func; __traits(getOverloads, Sys, func_name)) { static if ((Parameters!(func)).length == 1 - && is(Parameters!(func)[0] == EntityInfo*) - && is(ReturnType!(func) == RetType)) + && is(Parameters!(func)[0] == EntityInfo*) + && is(ReturnType!(func) == RetType)) { static RetType callFunc(void* system_pointer, EntityInfo* info) { @@ -1177,14 +1177,16 @@ export struct EntityManager system.m_priority = priority; //(cast(Sys*) system.m_system_pointer).__ecsInitialize(); //system.jobs = (cast(Sys*) system.m_system_pointer)._ecs_jobs; - static if(__traits(hasMember, Sys ,"__becs_jobs_count"))system.jobs = Mallocator.makeArray!(Job)(Sys.__becs_jobs_count); - else system.jobs = Mallocator.makeArray!(Job)(32); + static if (__traits(hasMember, Sys, "__becs_jobs_count")) + system.jobs = Mallocator.makeArray!(Job)(Sys.__becs_jobs_count); + else + system.jobs = Mallocator.makeArray!(Job)(32); static if (OnUpdateOverloadNum != -1) { Sys* s = cast(Sys*) system.m_system_pointer; system.m_update_delegate = cast(void delegate())&__traits(getOverloads, - s, "onUpdate")[OnUpdateOverloadNum]; + s, "onUpdate")[OnUpdateOverloadNum]; } genCompList(system, components_map); @@ -1192,10 +1194,10 @@ export struct EntityManager foreach (iii, comp_info; components_info.readonlyDeps) { ushort comp = external_dependencies_map.get(cast(const(char)[]) comp_info.type, - ushort.max); + ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -1208,7 +1210,7 @@ export struct EntityManager ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max); version (D_BetterC) assert(comp != ushort.max, - "Can't register system \"" ~ SystemName + "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency."); else assert(comp != ushort.max, "Can't register system \"" ~ SystemName @@ -1300,8 +1302,8 @@ export struct EntityManager // } static if (hasMember!(Comp, "onDestroy") && isFunction!(Comp.onDestroy) - && is(ReturnType!(Comp.onDestroy) == void) - && Parameters!(Comp.onDestroy).length == 0) + && is(ReturnType!(Comp.onDestroy) == void) + && Parameters!(Comp.onDestroy).length == 0) { static void callDestroy(void* pointer) nothrow @nogc { @@ -1312,7 +1314,7 @@ export struct EntityManager } static if (hasMember!(Comp, "onCreate") && isFunction!(Comp.onCreate) - && is(ReturnType!(Comp.onCreate) == void) && Parameters!(Comp.onCreate).length == 0) + && is(ReturnType!(Comp.onCreate) == void) && Parameters!(Comp.onCreate).length == 0) { static void callCreate(void* pointer) nothrow @nogc { @@ -1358,7 +1360,7 @@ export struct EntityManager // } static if (hasMember!(Ev, "onDestroy") && isFunction!(Ev.onDestroy) - && is(ReturnType!(Ev.onDestroy) == void) && Parameters!(Ev.onDestroy).length == 0) + && is(ReturnType!(Ev.onDestroy) == void) && Parameters!(Ev.onDestroy).length == 0) { static void callDestroy(void* pointer) { @@ -1392,10 +1394,10 @@ export struct EntityManager Sys* s; static assert(isDelegate!func, "Function must be delegate."); static assert(__traits(hasMember, Sys, "EntitiesData"), - "Can't call function with system which hasn't EntitesData structure."); + "Can't call function with system which hasn't EntitesData structure."); ///TODO: make possibly to call function to group without system with onUpdate function static assert(__traits(hasMember, Sys, "onUpdate"), - "Can't call function with system which hasn't onUpdate function callback."); + "Can't call function with system which hasn't onUpdate function callback."); // static assert(is(SetFunctionAttributes!(T, functionLinkage!(s.onUpdate), // functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)), // "Function must match system update function."); FIXME: It's lead to crash on android build @@ -1403,7 +1405,9 @@ export struct EntityManager System* system = getSystem(becsID!Sys); assert(system != null, - "System must be registered in EntityManager before any funcion can be called."); + "System must be registered in EntityManager before any funcion can be called."); + assert(system.isAlive(), "System must be alive (registered) in order to call entities function on its entities"); + if (!system.m_any_system_caller) return; @@ -1445,7 +1449,7 @@ export struct EntityManager foreach (info; caller.infos) { CallData data = CallData(caller.system_id, sys, info, - sys.m_update_delegate); + sys.m_update_delegate); data.update(); } } @@ -1467,7 +1471,7 @@ export struct EntityManager assert(!register_state); assert(pass < passes.length); assert(m_dispatch_jobs, - "Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc()."); + "Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc()."); Vector!CallData tmp_datas; tmp_datas.reserve(8); @@ -1480,7 +1484,7 @@ export struct EntityManager void nextJob() { CallData[] callers = m_call_data_allocator.getCallData( - cast(uint) tmp_datas.length); + cast(uint) tmp_datas.length); //callers[0 .. $] = tmp_datas[0 .. $]; memcpy(callers.ptr, &tmp_datas[0], CallData.sizeof * tmp_datas.length); tmp_datas.clear(); @@ -1535,7 +1539,7 @@ export struct EntityManager //if this info will fill job if ((blocks_count - 1) * info.max_entities + entities_count - + info.last_block.entities_count - first_elem >= entities_per_job) + + info.last_block.entities_count - first_elem >= entities_per_job) { int reamaining_entities = (entities_per_job - entities_count - ( first_block.entities_count - first_elem)); @@ -1556,9 +1560,9 @@ export struct EntityManager assert(entities_per_job == full_blocks_count * info.max_entities + entities_count + ( first_block.entities_count - first_elem)); CallData data = CallData(caller.system_id, sys, - info, sys.m_update_delegate, first_block, - cast(ushort)(full_blocks_count + 1), - cast(ushort) first_elem, 0); + info, sys.m_update_delegate, first_block, + cast(ushort)(full_blocks_count + 1), + cast(ushort) first_elem, 0); tmp_datas.add(data); first_elem = 0; blocks_count -= full_blocks_count + 1; @@ -1567,14 +1571,14 @@ export struct EntityManager else { entities_count += full_blocks_count * info.max_entities + ( - first_block.entities_count - first_elem); // - first_elem; + first_block.entities_count - first_elem); // - first_elem; uint last_elem = entities_per_job - entities_count; // + first_elem - 1; assert(last_elem > 0); assert(last_elem <= block.entities_count); CallData data = CallData(caller.system_id, sys, - info, sys.m_update_delegate, first_block, - cast(ushort)(full_blocks_count + 2), - cast(ushort) first_elem, cast(ushort) last_elem); + info, sys.m_update_delegate, first_block, + cast(ushort)(full_blocks_count + 2), + cast(ushort) first_elem, cast(ushort) last_elem); tmp_datas.add(data); first_elem = last_elem; blocks_count -= full_blocks_count + 1; @@ -1591,8 +1595,8 @@ export struct EntityManager uint last_elem = entities_per_job - entities_count; assert(last_elem > 0); CallData data = CallData(caller.system_id, sys, - info, sys.m_update_delegate, first_block, 1, - cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); + info, sys.m_update_delegate, first_block, 1, + cast(ushort) first_elem, cast(ushort)(first_elem + last_elem)); tmp_datas.add(data); first_elem += last_elem; assert(first_elem <= first_block.entities_count); @@ -1612,7 +1616,7 @@ export struct EntityManager { //take whole info blocks CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate, - first_block, cast(ushort) blocks_count, cast(ushort) first_elem); + first_block, cast(ushort) blocks_count, cast(ushort) first_elem); tmp_datas.add(data); entities_count += (blocks_count - 1) * info.max_entities + info.last_block.entities_count - first_elem; @@ -1627,7 +1631,7 @@ export struct EntityManager } export void setMultithreadingCallbacks(void delegate(JobGroup) dispatch_callback, - uint delegate() get_id_callback) + uint delegate() get_id_callback) { m_dispatch_jobs = cast(void delegate(JobGroup jobs) nothrow @nogc) dispatch_callback; m_thread_id_func = cast(uint delegate() nothrow @nogc) get_id_callback; @@ -1692,7 +1696,7 @@ export struct EntityManager if (components[comp].size == 0) continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], - components[comp].init_data.ptr, components[comp].size); + components[comp].init_data.ptr, components[comp].size); } } else @@ -1703,8 +1707,8 @@ export struct EntityManager if (components[comp].size == 0) continue; memcpy(cast(void*) temp.entity_data.ptr + info.tmpl_deltas[comp], - cast(void*) block + info.deltas[comp] + components[comp].size * index, - components[comp].size); + cast(void*) block + info.deltas[comp] + components[comp].size * index, + components[comp].size); } } @@ -1753,7 +1757,7 @@ export struct EntityManager if (components[comp].size == 0) continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], - components[comp].init_data.ptr, components[comp].size); + components[comp].init_data.ptr, components[comp].size); } return temp; @@ -1769,18 +1773,18 @@ export struct EntityManager remove_components_ids = array of components to remove from base template */ export EntityTemplate* allocateTemplate(EntityTemplate* base_tmpl, - ushort[] components_ids, ushort[] remove_components_ids = null) + ushort[] components_ids, ushort[] remove_components_ids = null) { size_t len = base_tmpl.info.components.length + components_ids.length; ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * len))[0 .. len]; memcpy(ids.ptr, base_tmpl.info.components.ptr, - ushort.sizeof * base_tmpl.info.components.length); + ushort.sizeof * base_tmpl.info.components.length); memcpy(ids.ptr + base_tmpl.info.components.length, components_ids.ptr, - ushort.sizeof * components_ids.length); + ushort.sizeof * components_ids.length); qsort(ids.ptr, ids.length, ushort.sizeof, &compareUShorts); qsort(remove_components_ids.ptr, remove_components_ids.length, - ushort.sizeof, &compareUShorts); + ushort.sizeof, &compareUShorts); { uint k = 0; uint j = 1; @@ -1820,20 +1824,20 @@ export struct EntityManager foreach (comp; info.components) { if (comp < base_tmpl.info.tmpl_deltas.length - && base_tmpl.info.tmpl_deltas[comp] != ushort.max) //copy data from base component - { + && base_tmpl.info.tmpl_deltas[comp] != ushort.max) //copy data from base component + { if (components[comp].size == 0) continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], - base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp], - components[comp].size); + base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp], + components[comp].size); } else //fill with default data { if (components[comp].size == 0) continue; memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], - components[comp].init_data.ptr, components[comp].size); + components[comp].init_data.ptr, components[comp].size); } } @@ -1887,7 +1891,7 @@ export struct EntityManager alignNum(info.size, info.alignment); uint block_memory = cast(uint)( - m_page_size - EntitiesBlock.sizeof - (info.size - components_size)); + m_page_size - EntitiesBlock.sizeof - (info.size - components_size)); //uint entity_comps_size = EntityID.sizeof; uint mem_begin = EntitiesBlock.sizeof; @@ -1915,15 +1919,14 @@ export struct EntityManager if (system.m_update is null) { if (system.m_add_entity || system.m_remove_entity - || system.m_change_entity || system.m_event_callers.length) + || system.m_change_entity || system.m_event_callers.length) connectListenerToEntityInfo(*info, cast(uint) i); continue; } addSystemCaller(*info, cast(uint) i); } - info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(gEntityManager.components.length); - //info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(gEntityManager.components.length); + info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); foreach (comp; info.components) @@ -2082,7 +2085,9 @@ export struct EntityManager } ///call Custom Entity Filter test if function exists - if(system.m_filter_entity && !(cast(bool function(void* system_pointer, EntityInfo* info) @nogc nothrow)system.m_filter_entity)(system, &entity))return; + if (system.m_filter_entity && !(cast(bool function(void* system_pointer, EntityInfo* info) @nogc nothrow) system + .m_filter_entity)(system, &entity)) + return; entity.systems[system_id] = true; } @@ -2127,7 +2132,8 @@ export struct EntityManager System* system = &systems[system_id]; connectListenerToEntityInfo(info, system_id); - if(!info.systems[system_id])return; + if (!info.systems[system_id]) + return; uint index = 0; for (; index < passes[system.m_pass].system_callers.length; index++) @@ -2236,7 +2242,7 @@ export struct EntityManager if (comp_size == 0) continue; memcpy(cast(void*) new_block + new_info.deltas[comp] + new_block.entities_count * comp_size, - cast(void*) block + info.deltas[comp] + ind * comp_size, comp_size); + cast(void*) block + info.deltas[comp] + ind * comp_size, comp_size); } new_block.entities_count++; @@ -2250,7 +2256,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count); + new_block.entities_count - 1, new_block.entities_count); } } } @@ -2262,7 +2268,7 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count, del_ids); + new_block.entities_count - 1, new_block.entities_count, del_ids); } } } @@ -2413,7 +2419,7 @@ export struct EntityManager if (!info.systems[listener]) { callAddEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count); + new_block.entities_count - 1, new_block.entities_count); } } } @@ -2425,7 +2431,7 @@ export struct EntityManager if (info.systems[listener]) { callChangeEntityListener(&systems[listener], new_info, new_block, - new_block.entities_count - 1, new_block.entities_count, new_ids); + new_block.entities_count - 1, new_block.entities_count, new_ids); } } } @@ -2468,7 +2474,7 @@ export struct EntityManager { if (components[ref_.component_id].size != 0) data.changeEntitiesList.add( - (cast(ubyte*) ref_.ptr)[0 .. components[ref_.component_id].size]); + (cast(ubyte*) ref_.ptr)[0 .. components[ref_.component_id].size]); } } @@ -2518,12 +2524,12 @@ export struct EntityManager ushort size = components[comp].size; if (size != 0) memcpy(cast(void*) new_block + info.deltas[comp] + new_id * size, - cast(void*) block + info.deltas[comp] + size * index, size); + cast(void*) block + info.deltas[comp] + size * index, size); if (components[comp].create_callback) { components[comp].create_callback( - cast(void*) new_block + info.deltas[comp] + new_id * size); + cast(void*) new_block + info.deltas[comp] + new_id * size); } } @@ -2580,7 +2586,7 @@ export struct EntityManager uint size = components[comp].size; if (size != 0) memcpy(cast(void*) block + info.deltas[comp] + size * id, - tmpl.entity_data.ptr + info.tmpl_deltas[comp], size); + tmpl.entity_data.ptr + info.tmpl_deltas[comp], size); } foreach (comp; replacement) @@ -2602,7 +2608,7 @@ export struct EntityManager if (components[comp].create_callback) { components[comp].create_callback( - cast(void*) block + info.deltas[comp] + id * components[comp].size); + cast(void*) block + info.deltas[comp] + id * components[comp].size); } } @@ -2737,7 +2743,7 @@ export struct EntityManager } private void removeEntityNoID(Entity* entity, EntitiesBlock* block, - bool call_destructors = false) nothrow @nogc + bool call_destructors = false) nothrow @nogc { EntityInfo* info = block.type_info; @@ -2869,7 +2875,7 @@ export struct EntityManager } private static void callAddEntityListener(System* system, EntityInfo* info, - EntitiesBlock* block, int begin, int end) @nogc nothrow + EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; data.system = system; @@ -2880,7 +2886,7 @@ export struct EntityManager } private void callRemoveEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, - int end) @nogc nothrow + int end) @nogc nothrow { foreach (listener; info.remove_listeners) { @@ -2890,7 +2896,7 @@ export struct EntityManager } private static void callRemoveEntityListener(System* system, - EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow + EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow { ListenerCallData data; data.system = system; @@ -2901,7 +2907,7 @@ export struct EntityManager } private void callChangeEntityListener(System* system, EntityInfo* info, - EntitiesBlock* block, int begin, int end, ushort[] ch_ids) @nogc nothrow + EntitiesBlock* block, int begin, int end, ushort[] ch_ids) @nogc nothrow { int i = 0; int j = 0; @@ -3055,7 +3061,7 @@ export struct EntityManager foreach (caller; events[i].callers) { if (call_data.block.type_info.systems[caller.system.m_id] == false - || !caller.system.enabled || !caller.system.willExecute) + || !caller.system.enabled || !caller.system.willExecute) continue; call_data.system_pointer = caller.system.m_system_pointer; (cast(void function(ref EventCallData) nothrow @nogc) caller @@ -3122,7 +3128,7 @@ export struct EntityManager continue; if (system.enabled && system.m_begin) system.m_execute = (cast(bool function(void*)) system.m_begin)( - system.m_system_pointer); + system.m_system_pointer); } } @@ -3135,9 +3141,8 @@ export struct EntityManager foreach (ref system; systems) { if (system.isAlive() == false) - { continue; - } + if (system.enabled && system.m_end) (cast(void function(void*)) system.m_end)(system.m_system_pointer); } @@ -3276,7 +3281,7 @@ export struct EntityManager } qsort(pass.system_callers.array.ptr, pass.system_callers.length, - (SystemCaller*).sizeof, &compareSystems); + (SystemCaller*).sizeof, &compareSystems); foreach (i, caller; pass.system_callers) caller.job_group.id = cast(uint) i; @@ -3403,7 +3408,7 @@ export struct EntityManager if (comp_add_info.length <= id) { EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)( - gEntityManager.components.length); + gEntityManager.components.length); if (comp_add_info !is null) { //new_infos[0 .. comp_add_info.length] = comp_add_info[0 .. $]; @@ -3448,7 +3453,7 @@ export struct EntityManager return new_info; } - EntityInfo* getNewInfoRemove(ushort id) return + EntityInfo* getNewInfoRemove(ushort id) return { /*if (comp_rem_info.length <= id) { @@ -3491,7 +3496,8 @@ export struct EntityManager export bool hasComponent(ushort component_id) { - if(component_id >= deltas.length || !deltas[component_id])return false; + if (component_id >= deltas.length || !deltas[component_id]) + return false; return true; } @@ -3560,7 +3566,7 @@ export struct EntityManager struct EntitiesBlock { ///return pointer to first element in block - export void* dataBegin() nothrow @nogc pure return + export void* dataBegin() nothrow @nogc pure return { ushort dif = EntitiesBlock.sizeof; return cast(void*)&this + dif; @@ -3643,7 +3649,6 @@ export struct EntityManager export void execute() nothrow @nogc { - //gEntityManager.getThreadID(); foreach (ref caller; callers) { caller.thread_id = gEntityManager.threadID(); @@ -3688,32 +3693,32 @@ export struct EntityManager struct ThreadData { - ref Vector!EntityID entitesToRemove() @nogc nothrow return + ref Vector!EntityID entitesToRemove() @nogc nothrow return { return entities_to_remove[data_index]; } - ref SimpleVector changeEntitiesList() @nogc nothrow return + ref SimpleVector changeEntitiesList() @nogc nothrow return { return change_entities_list[data_index]; } - ref Vector!(EntityInfo*) infosToUpdate() @nogc nothrow return + ref Vector!(EntityInfo*) infosToUpdate() @nogc nothrow return { return infos_to_update[data_index]; } - ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow return + ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow return { return entities_to_remove[1 - data_index]; } - ref SimpleVector changeEntitiesListPrev() @nogc nothrow return + ref SimpleVector changeEntitiesListPrev() @nogc nothrow return { return change_entities_list[1 - data_index]; } - ref Vector!(EntityInfo*) infosToUpdatePrev() @nogc nothrow return + ref Vector!(EntityInfo*) infosToUpdatePrev() @nogc nothrow return { return infos_to_update[1 - data_index]; } @@ -3849,5 +3854,5 @@ export struct EntityManager return ret; } } - + } From 6bf8837e8f6f257e8eac4f9ce2558f276a2b6fe2 Mon Sep 17 00:00:00 2001 From: Dawid Masiukiewicz Date: Sat, 12 Nov 2022 11:41:08 +0000 Subject: [PATCH 05/14] Update codecov token --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 555e6d5..f1d8ecc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -56,7 +56,7 @@ coverage_test_dmd: - mkdir reports - binaries/dmd_unittest_cov after_script: - - bash <(curl -s https://codecov.io/bash) -s reports -t 1a0c0169-a721-4085-8252-fed4755dcd8c + - bash <(curl -s https://codecov.io/bash) -s reports -t df87b1d8-85f4-4584-96e3-1315d27ec2c5 wasm: stage: build_wasm From ed0603a67509ce5e846df9eeeec0d52ab22974b6 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 18 Jan 2023 14:40:59 +0100 Subject: [PATCH 06/14] Update copyright notice --- dub.json | 2 +- source/bubel/ecs/atomic.d | 2 +- source/bubel/ecs/attributes.d | 2 +- source/bubel/ecs/block_allocator.d | 2 +- source/bubel/ecs/core.d | 2 +- source/bubel/ecs/entity.d | 2 +- source/bubel/ecs/events.d | 2 +- source/bubel/ecs/hash_map.d | 2 +- source/bubel/ecs/id_manager.d | 2 +- source/bubel/ecs/manager.d | 6 +----- source/bubel/ecs/package.d | 2 +- source/bubel/ecs/simple_vector.d | 2 +- source/bubel/ecs/std.d | 2 +- source/bubel/ecs/system.d | 2 +- source/bubel/ecs/traits.d | 2 +- source/bubel/ecs/vector.d | 2 +- 16 files changed, 16 insertions(+), 20 deletions(-) diff --git a/dub.json b/dub.json index 1461c9d..602117d 100755 --- a/dub.json +++ b/dub.json @@ -5,7 +5,7 @@ "Michał Masiukiewicz", "Dawid Masiukiewicz" ], "description": "Dynamic Entity Component System", - "copyright": "Copyright © 2018-2019, Michał Masiukiewicz, Dawid Masiukiewicz", + "copyright": "Copyright © 2018-2023, Michał Masiukiewicz, Dawid Masiukiewicz", "license": "BSD 3-clause", "sourcePaths" : ["source\/"], "excludedSourceFiles":[ diff --git a/source/bubel/ecs/atomic.d b/source/bubel/ecs/atomic.d index 8ea43df..40f0aa9 100644 --- a/source/bubel/ecs/atomic.d +++ b/source/bubel/ecs/atomic.d @@ -4,7 +4,7 @@ It's internal code. Can be used for atomics if emscripten backend will be used. This module contain atomic operations which include support for emscripten atomics functions. Emscripten functions are contained in API similar to druntime. -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.atomic; diff --git a/source/bubel/ecs/attributes.d b/source/bubel/ecs/attributes.d index d094aad..1a041d4 100644 --- a/source/bubel/ecs/attributes.d +++ b/source/bubel/ecs/attributes.d @@ -17,7 +17,7 @@ Struct EntitiesData } --- -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.attributes; diff --git a/source/bubel/ecs/block_allocator.d b/source/bubel/ecs/block_allocator.d index 6894a17..0ab735e 100644 --- a/source/bubel/ecs/block_allocator.d +++ b/source/bubel/ecs/block_allocator.d @@ -3,7 +3,7 @@ It's internal code. Module contain memory allocator. -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.block_allocator; diff --git a/source/bubel/ecs/core.d b/source/bubel/ecs/core.d index f8511ea..c796423 100644 --- a/source/bubel/ecs/core.d +++ b/source/bubel/ecs/core.d @@ -67,7 +67,7 @@ Struct System1 } --- -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.core; diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index cb3f752..9b42c31 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -1,7 +1,7 @@ /************************************************************************************************************************ Entity module. -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.entity; diff --git a/source/bubel/ecs/events.d b/source/bubel/ecs/events.d index f123e86..11816a1 100644 --- a/source/bubel/ecs/events.d +++ b/source/bubel/ecs/events.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.events; diff --git a/source/bubel/ecs/hash_map.d b/source/bubel/ecs/hash_map.d index 1af0fd8..0ad4dc5 100755 --- a/source/bubel/ecs/hash_map.d +++ b/source/bubel/ecs/hash_map.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.hash_map; diff --git a/source/bubel/ecs/id_manager.d b/source/bubel/ecs/id_manager.d index ccb4fac..2054cbb 100644 --- a/source/bubel/ecs/id_manager.d +++ b/source/bubel/ecs/id_manager.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.id_manager; diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 323d2ab..a34d81c 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -1,7 +1,7 @@ /************************************************************************************************************************ Most important module. Almost every function is called from EntityManager. -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.manager; @@ -10,10 +10,6 @@ import std.algorithm : max; import std.conv : to; import std.traits; -//import core.atomic; -//import core.stdc.stdlib : qsort; -//import core.stdc.string; - import bubel.ecs.system; //not ordered as forward reference bug workaround import bubel.ecs.block_allocator; import bubel.ecs.entity; diff --git a/source/bubel/ecs/package.d b/source/bubel/ecs/package.d index 2b3b7f4..e2d8893 100644 --- a/source/bubel/ecs/package.d +++ b/source/bubel/ecs/package.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module ecs; diff --git a/source/bubel/ecs/simple_vector.d b/source/bubel/ecs/simple_vector.d index 02f3f3d..2fdaf31 100644 --- a/source/bubel/ecs/simple_vector.d +++ b/source/bubel/ecs/simple_vector.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.simple_vector; diff --git a/source/bubel/ecs/std.d b/source/bubel/ecs/std.d index d99a05c..8eb0d48 100644 --- a/source/bubel/ecs/std.d +++ b/source/bubel/ecs/std.d @@ -2,7 +2,7 @@ It's internal code! This module contain implementation of standard functionality. -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.std; diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index 0da2d96..8e9d0ba 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -1,7 +1,7 @@ /************************************************************************************************************************ System module. -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.system; diff --git a/source/bubel/ecs/traits.d b/source/bubel/ecs/traits.d index 42b1753..79901db 100644 --- a/source/bubel/ecs/traits.d +++ b/source/bubel/ecs/traits.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.traits; diff --git a/source/bubel/ecs/vector.d b/source/bubel/ecs/vector.d index e9b061d..6cf6274 100644 --- a/source/bubel/ecs/vector.d +++ b/source/bubel/ecs/vector.d @@ -1,5 +1,5 @@ /************************************************************************************************************************ -Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz +Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.vector; From 65c6ea4489b9c9ad819e3bccff336ed69fa2fe27 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 18 Jan 2023 14:53:26 +0100 Subject: [PATCH 07/14] Fix demos compilation (using Meson) --- demos/meson.build | 2 +- demos/utils/meson.build | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/demos/meson.build b/demos/meson.build index deee071..8a3642d 100644 --- a/demos/meson.build +++ b/demos/meson.build @@ -27,7 +27,7 @@ executable('BubelECSDemos', [demos_src, external_src], bindbc_loader_dep, bindbc_sdl_dep, cimgui_dep, - decs_dep, + bubel_ecs_dep, ecs_utils_dep, sdl2_dep, sdl2_image_dep, diff --git a/demos/utils/meson.build b/demos/utils/meson.build index de9e958..708fc85 100644 --- a/demos/utils/meson.build +++ b/demos/utils/meson.build @@ -5,12 +5,12 @@ subdir('source/ecs_utils') utils_inc = include_directories('source/') # Dependencies -ecs_utils_lib = library('ecs_utils', utils_src, +ecs_utils_lib = library('ECSUtils', utils_src, include_directories : [demos_inc, external_inc, utils_inc], link_args : link_args, d_module_versions : versions, dependencies : [ - decs_dep, + bubel_ecs_dep, bindbc_loader_dep, bindbc_sdl_dep, ] From 9bf6f84d45e1eea4574ff95ba5e1d052576c89c6 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 18 Jan 2023 15:09:25 +0100 Subject: [PATCH 08/14] Update README Add information about how to use library with DUB package manager --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 3f52b93..14e6d75 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,13 @@ Bubel ECS was tested on Linux, Windows, Android and WASM. **Currently library is in beta stage so some significant API changes can appear.** +Package is available on [DUB package repository](https://code.dlang.org/packages/bubel-ecs). Usage: +``` + "dependencies": { + "bubel-ecs": "~>0.1.1" + } +``` + ## Design For core information about Entity-Component-System architectural pattern please read definition described at [Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system). From 0702b007d17546243ca8172ce26148331220d99e Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 9 Mar 2023 11:04:12 +0100 Subject: [PATCH 09/14] Fix unregisterSystem function and add function to get m_system_pointer from System --- source/bubel/ecs/hash_map.d | 6 ++-- source/bubel/ecs/manager.d | 26 ++++++++++------ source/bubel/ecs/system.d | 62 ++++++++++++++++++++++++++++++++++--- 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/source/bubel/ecs/hash_map.d b/source/bubel/ecs/hash_map.d index 0ad4dc5..66a0756 100755 --- a/source/bubel/ecs/hash_map.d +++ b/source/bubel/ecs/hash_map.d @@ -341,7 +341,7 @@ nothrow: int result; foreach (ref Key k; this) { - result = (cast(int delegate(ref Key k) nothrow)dg)(k); + result = (cast(int delegate(ref Key k) nothrow @nogc)dg)(k); if (result) break; } @@ -353,7 +353,7 @@ nothrow: int result; foreach (ref Value v; this) { - result = (cast(int delegate(ref Value v) nothrow)dg)(v); + result = (cast(int delegate(ref Value v) nothrow @nogc)dg)(v); if (result) break; } @@ -365,7 +365,7 @@ nothrow: int result; foreach (ref Key k, ref Value v; this) { - result = (cast(int delegate(ref Key k, ref Value v) nothrow)dg)(k, v); + result = (cast(int delegate(ref Key k, ref Value v) nothrow @nogc)dg)(k, v); if (result) break; } diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index a34d81c..801068d 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -76,7 +76,7 @@ export struct EntityManager UpdatePass* pass = Mallocator.make!UpdatePass; pass.name = Mallocator.makeArray(cast(char[]) "update"); passes.add(pass); - passes_map.add(cast(string) pass.name, cast(ushort)(passes.length - 1)); + passes_map.add(cast(const(char)[]) pass.name, cast(ushort)(passes.length - 1)); } } } @@ -84,7 +84,7 @@ export struct EntityManager /************************************************************************************************************************ Deinitialize and destroy ECS. This function release whole memory. */ - export static void destroy() + export static void destroy() nothrow @nogc { if (gEntityManager is null) return; @@ -334,16 +334,23 @@ export struct EntityManager */ void unregisterSystem(Sys)() { - assert(register_state, "unregisterSystem must be called between beginRegister() and endRegister()."); - ushort system_id = becsID!Sys; System* system = getSystem(system_id); - assert(system, "System was not registered"); - assert(system.isAlive, "System already unregistered"); + unregisterSystem(system); + } - system.destroy(); - *system = System.init; + /************************************************************************************************************************ + Unregister given system form EntityManager. + */ + export void unregisterSystem(System* system) nothrow @nogc + { + assert(register_state, "unregisterSystem must be called between beginRegister() and endRegister()."); + assert(system !is null, "System was not registered"); + assert(system.isAlive, "System already unregistered"); + + //disable, destroy and dispose user created system but keep name and other data + system.destroySystemData(); } /************************************************************************************************************************ @@ -1248,7 +1255,8 @@ export struct EntityManager } /************************************************************************************************************************ - Return system ECS api by id + Return system ECS api by id. + System pointer might become invalid after registration process. It should be get once again after new systems are registered. */ export System* getSystem(ushort id) nothrow @nogc { diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index 8e9d0ba..24098c0 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -97,38 +97,92 @@ struct System return m_system_pointer != null; } + /************************************************************************************************************************ + Return pointer to user side system object + */ + export void* ptr() nothrow @nogc + { + return m_system_pointer; + } + package: - void destroy() + ///destory system. Dispose all data + void destroy() nothrow @nogc + { + import bubel.ecs.std : Mallocator; + + destroySystemData(); + + if (m_name) + { + Mallocator.dispose(m_name); + m_name = null; + } + } + + ///destroy all system data but keeps name which is used for case of system re-registration + void destroySystemData() nothrow @nogc { import bubel.ecs.std : Mallocator; disable(); if (m_destroy) - (cast(void function(void*)) m_destroy)(m_system_pointer); + { + (cast(void function(void*) nothrow @nogc) m_destroy)(m_system_pointer); + m_destroy = null; + } - if (m_name) - Mallocator.dispose(m_name); if (m_components) + { Mallocator.dispose(m_components); + m_components = null; + } if (m_excluded_components) + { Mallocator.dispose(m_excluded_components); + m_excluded_components = null; + } if (m_optional_components) + { Mallocator.dispose(m_optional_components); + m_optional_components = null; + } if (jobs) + { Mallocator.dispose(jobs); + jobs = null; + } if (m_read_only_components) + { Mallocator.dispose(m_read_only_components); + m_read_only_components = null; + } if (m_writable_components) + { Mallocator.dispose(m_writable_components); + m_writable_components = null; + } if (m_readonly_dependencies) + { Mallocator.dispose(m_readonly_dependencies); + m_readonly_dependencies = null; + } if (m_writable_dependencies) + { Mallocator.dispose(m_writable_dependencies); + m_writable_dependencies = null; + } if (m_event_callers) + { Mallocator.dispose(m_event_callers); + m_event_callers = null; + } if (m_system_pointer) + { Mallocator.dispose(m_system_pointer); + m_system_pointer = null; + } } struct EventCaller From 8ac9fa5dbd9afebf6addbd50debd816fd91d0c8d Mon Sep 17 00:00:00 2001 From: Mergul Date: Mon, 24 Apr 2023 23:46:16 +0200 Subject: [PATCH 10/14] Fix crash in commit() when all components were removed from entity Fix crash from issue #2 and add unittest case for it. Also implements general "empty" entity support --- source/bubel/ecs/manager.d | 98 ++++++++++++++++++++---------------- tests/basic.d | 100 +++++++++++++++++++++++++++++++++++++ tests/bugs.d | 29 +++++++++++ 3 files changed, 185 insertions(+), 42 deletions(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 801068d..d6fae94 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -1856,6 +1856,7 @@ export struct EntityManager */ export EntityTemplate* allocateTemplate(EntityTemplate* copy_tmpl) { + assert(copy_tmpl, "copy_tmpl can't be null"); EntityTemplate* tmpl = Mallocator.make!EntityTemplate; tmpl.info = copy_tmpl.info; tmpl.entity_data = Mallocator.makeArray(copy_tmpl.entity_data); @@ -1870,46 +1871,66 @@ export struct EntityManager */ export EntityInfo* getEntityInfo(ushort[] ids) { + if(ids.length == 0)ids = null; EntityInfo* info = entities_infos.get(ids, null); if (info is null) { info = Mallocator.make!EntityInfo; - info.components = Mallocator.makeArray(ids); - info.deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1); - info.size = EntityID.sizeof; info.alignment = EntityID.alignof; - info.tmpl_deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1, ushort.max); - uint components_size = EntityID.sizeof; - - foreach (i, id; ids) + if(ids is null) { - info.alignment = max(info.alignment, components[id].alignment); - alignNum(info.size, components[id].alignment); - info.tmpl_deltas[id] = info.size; - info.size += components[id].size; - components_size += components[id].size; + uint block_memory = cast(uint)( + m_page_size - EntitiesBlock.sizeof - info.size); + uint entites_in_block = block_memory / info.size; + info.max_entities = cast(ushort) entites_in_block; } - alignNum(info.size, info.alignment); - - uint block_memory = cast(uint)( - m_page_size - EntitiesBlock.sizeof - (info.size - components_size)); - //uint entity_comps_size = EntityID.sizeof; - uint mem_begin = EntitiesBlock.sizeof; - - uint entites_in_block = block_memory / info.size; //entity_comps_size; - info.max_entities = cast(ushort) entites_in_block; - ushort current_delta = cast(ushort)(mem_begin + entites_in_block * EntityID.sizeof); - - foreach (i, id; ids) + else { - if (current_delta == 0) - current_delta = ushort.max; - alignNum(current_delta, components[id].alignment); - info.deltas[id] = cast(ushort) current_delta; - current_delta += entites_in_block * components[id].size; + uint components_size = EntityID.sizeof; + + info.components = Mallocator.makeArray(ids); + info.deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1); + info.tmpl_deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1, ushort.max); + + foreach (i, id; ids) + { + info.alignment = max(info.alignment, components[id].alignment); + alignNum(info.size, components[id].alignment); + info.tmpl_deltas[id] = info.size; + info.size += components[id].size; + components_size += components[id].size; + } + alignNum(info.size, info.alignment); + + uint block_memory = cast(uint)( + m_page_size - EntitiesBlock.sizeof - (info.size - components_size)); + //uint entity_comps_size = EntityID.sizeof; + uint mem_begin = EntitiesBlock.sizeof; + + uint entites_in_block = block_memory / info.size; //entity_comps_size; + info.max_entities = cast(ushort) entites_in_block; + ushort current_delta = cast(ushort)(mem_begin + entites_in_block * EntityID.sizeof); + + foreach (i, id; ids) + { + if (current_delta == 0) + current_delta = ushort.max; + alignNum(current_delta, components[id].alignment); + info.deltas[id] = cast(ushort) current_delta; + current_delta += entites_in_block * components[id].size; + } + + info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); + info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); + + foreach (comp; info.components) + { + info.comp_add_info[comp] = info; + info.comp_rem_info[comp] = null; + } } info.systems = Mallocator.makeArray!bool(systems.length); @@ -1930,15 +1951,6 @@ export struct EntityManager addSystemCaller(*info, cast(uint) i); } - info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); - info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length); - - foreach (comp; info.components) - { - info.comp_add_info[comp] = info; - info.comp_rem_info[comp] = null; - } - entities_infos.add(info.components, info); generateListeners(info); @@ -2552,7 +2564,7 @@ export struct EntityManager use you should save ID instead of pointer. Params: - tmpl = pointer entity template allocated by EntityManager. + tmpl = pointer entity template allocated by EntityManager. Can be null in which case empty entity would be added (entity without components) */ export Entity* addEntity(EntityTemplate* tmpl) { @@ -2564,12 +2576,14 @@ export struct EntityManager use you should save ID instead of pointer. Params: - tmpl = pointer entity template allocated by EntityManager. + tmpl = pointer entity template allocated by EntityManager. Can be null in which case empty entity would be added (entity without components) replacement = list of components references to used. Memory form list replace data from template inside new entity. Should be used only for data which vary between most entities (like 3D position etc.) */ export Entity* addEntity(EntityTemplate* tmpl, ComponentRef[] replacement) { - EntityInfo* info = tmpl.info; + EntityInfo* info = void; + if(tmpl)info = tmpl.info; + else info = getEntityInfo(null); ushort index = 0; EntitiesBlock* block; @@ -3446,7 +3460,7 @@ export struct EntityManager break; } } - if (id > components[$ - 1]) + if (components.length == 0 || id > components[$ - 1]) ids[len++] = id; assert(len == components.length + 1); diff --git a/tests/basic.d b/tests/basic.d index 084500a..ea54382 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -113,6 +113,31 @@ struct EmptySystem int count = 0; } +struct EntityCounterSystem +{ + mixin ECS.System!1; + + struct EntitiesData + { + int thread_id; + uint length; + Entity[] entity; + } + + bool onBegin() + { + count = 0; + return true; + } + + void onUpdate(EntitiesData data) + { + count += data.length; + } + + int count = 0; +} + void beforeEveryTest() { becsID!CUnregistered = ushort.max; @@ -243,7 +268,82 @@ unittest gEntityManager.commit(); entity3 = gEntityManager.getEntity(id); assert(!entity3.getComponent!CUnregistered); +} +@("AddEmptyEntity") +unittest +{ + struct OnAddRemoveChangeCounter + { + mixin ECS.System!1; + + struct EntitiesData + { + int thread_id; + uint length; + Entity[] entity; + } + + void onAddEntity(EntitiesData data) + { + add += data.length; + } + + void onRemoveEntity(EntitiesData data) + { + assert(0, "It's impossible to remove entity from being updated by system which accept empty entity"); + } + + int add = 0; + } + + gEntityManager.beginRegister(); + + gEntityManager.registerSystem!EntityCounterSystem(0); + gEntityManager.registerSystem!OnAddRemoveChangeCounter(1); + + gEntityManager.endRegister(); + + CLong long_component = CLong(3); + + Entity* entity = null; + EntityID entity_id = gEntityManager.addEntity(null).id; + + EntityCounterSystem* system = gEntityManager.getSystem!EntityCounterSystem; + assert(system !is null); + assert(system.count == 0); + + OnAddRemoveChangeCounter* add_remove_change_system = gEntityManager.getSystem!OnAddRemoveChangeCounter; + assert(add_remove_change_system !is null); + assert(add_remove_change_system.add == 0); + + gEntityManager.commit(); + assert(add_remove_change_system.add == 1); + + entity = gEntityManager.getEntity(entity_id); + assert(!entity.hasComponent(becsID!CLong)); + assert(entity.getComponent(becsID!CLong) is null); + + + gEntityManager.begin(); + gEntityManager.update(); + assert(system.count == 1); + gEntityManager.end(); + + gEntityManager.addEntityCopy(entity_id); + gEntityManager.addEntityCopy(entity_id); + gEntityManager.addComponents(entity_id, [ComponentRef(&long_component, becsID(long_component))].staticArray); + gEntityManager.commit(); + assert(add_remove_change_system.add == 3, "onAddEntity missed"); + + entity = gEntityManager.getEntity(entity_id); + assert(entity.hasComponent(becsID!CLong)); + assert(*entity.getComponent!CLong == 3); + + gEntityManager.begin(); + gEntityManager.update(); + assert(system.count == 3); + gEntityManager.end(); } //allocate templates diff --git a/tests/bugs.d b/tests/bugs.d index 1a3968c..10a3c62 100644 --- a/tests/bugs.d +++ b/tests/bugs.d @@ -142,5 +142,34 @@ unittest gEntityManager.update(); gEntityManager.end(); + gEntityManager.destroy(); +} + +@("2-empty-entity-crash") +unittest +{ + + gEntityManager.initialize(0); + + gEntityManager.beginRegister(); + + gEntityManager.registerComponent!CInt; + gEntityManager.registerComponent!CFloat; + + gEntityManager.endRegister(); + + + EntityTemplate* tmpl = gEntityManager.allocateTemplate([becsID!CInt, becsID!CFloat].staticArray); + scope(exit) gEntityManager.freeTemplate(tmpl); + + EntityID id = gEntityManager.addEntity(tmpl).id; + // EntityID id2 = gEntityManager.addEntity().id; + + gEntityManager.commit(); + + gEntityManager.removeComponents(id, [becsID!CInt, becsID!CFloat].staticArray); + + gEntityManager.commit(); + gEntityManager.destroy(); } \ No newline at end of file From 9b757720395f9b081ba66c4cb966fa9b763aff2d Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 10 Apr 2025 13:59:21 +0200 Subject: [PATCH 11/14] Add missing export visibility attributes --- source/bubel/ecs/entity.d | 12 ++++++------ source/bubel/ecs/hash_map.d | 2 +- source/bubel/ecs/manager.d | 10 ++++++++++ source/bubel/ecs/system.d | 2 +- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/source/bubel/ecs/entity.d b/source/bubel/ecs/entity.d index 9b42c31..76a8a2f 100644 --- a/source/bubel/ecs/entity.d +++ b/source/bubel/ecs/entity.d @@ -44,7 +44,7 @@ struct Entity return cast(T*)getComponent(becsID!T); } - void* getComponent(ushort component_id) const + export void* getComponent(ushort component_id) const { EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; @@ -54,7 +54,7 @@ struct Entity return (cast(void*)block + info.deltas[component_id] + block.entityIndex(&this) * gEntityManager.components[component_id].size); } - bool hasComponent(ushort component_id) const + export bool hasComponent(ushort component_id) const { EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; @@ -62,7 +62,7 @@ struct Entity return true; } - EntityMeta getMeta() const + export EntityMeta getMeta() const { EntityMeta meta; meta.block = gEntityManager.getMetaData(&this); @@ -85,7 +85,7 @@ struct EntityMeta return cast(T*)getComponent(becsID!T); } - void* getComponent(ushort component_id) const + export void* getComponent(ushort component_id) const { const (EntityManager.EntityInfo)* info = block.type_info; @@ -95,7 +95,7 @@ struct EntityMeta return (cast(void*)block + info.deltas[component_id] + index * gEntityManager.components[component_id].size); } - bool hasComponent(ushort component_id) const + export bool hasComponent(ushort component_id) const { const EntityManager.EntityInfo* info = block.type_info; if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; @@ -133,7 +133,7 @@ export struct EntityTemplate /************************************************************************************************************************ Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime. */ - void* getComponent(ushort component_id) const nothrow @nogc + export void* getComponent(ushort component_id) const nothrow @nogc { if(component_id >= info.tmpl_deltas.length || info.tmpl_deltas[component_id] == ushort.max)return null; return cast(void*)(entity_data.ptr + info.tmpl_deltas[component_id]); diff --git a/source/bubel/ecs/hash_map.d b/source/bubel/ecs/hash_map.d index 66a0756..7ba6137 100755 --- a/source/bubel/ecs/hash_map.d +++ b/source/bubel/ecs/hash_map.d @@ -28,7 +28,7 @@ export ulong defaultHashFunc(T)(auto ref T t) nothrow @nogc } } -ulong hash(byte[] array) nothrow @nogc +export ulong hash(byte[] array) nothrow @nogc { ulong hash = 0; diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index d6fae94..0977786 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -3355,6 +3355,16 @@ export struct EntityManager export ~this() nothrow @nogc { } + + export void opAssign(ComponentInfo c) + { + size = c.size; + alignment = c.alignment; + init_data = c.init_data; + destroy_callback = c.destroy_callback; + create_callback = c.create_callback; + } + ///Component size ushort size; ///Component data alignment diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index 24098c0..e6defd9 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -108,7 +108,7 @@ struct System package: ///destory system. Dispose all data - void destroy() nothrow @nogc + export void destroy() nothrow @nogc { import bubel.ecs.std : Mallocator; From 76a23aa4edffec3db1f233b95a6a52b13567b87f Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 10 Apr 2025 14:00:20 +0200 Subject: [PATCH 12/14] Fix typo --- source/bubel/ecs/system.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/bubel/ecs/system.d b/source/bubel/ecs/system.d index e6defd9..310b53a 100644 --- a/source/bubel/ecs/system.d +++ b/source/bubel/ecs/system.d @@ -13,14 +13,14 @@ import bubel.ecs.manager; System contain data required to proper glue EntityManager with Systems. System callbacks: $(LIST - * void onUpdate(EntitesData); + * void onUpdate(EntitiesData); * void onEnable() - called inside system.enable() function * void onDisable() - called inside system.disable() function * bool onBegin() - called inside manager.begin() * void onEnd() - called inside manager.end() * void onCreate() - called after registration inside registerSystem function * void onDestroy() - called during re-registration and inside manager destructor - * void onAddEntity(EntitesData) - called for every entity which are assigned to system (by adding new entity or changing its components) + * void onAddEntity(EntitiesData) - called for every entity which are assigned to system (by adding new entity or changing its components) * void onRemoveEntity(EntitiesData) - called for every entity removed from system update process * void onChangeEntity(EntitiesData) - called for every entity which components are changed but it was previously assigned to system * void handleEvent(Entity*, Event) - called for every event supported by system From d77317c8163faa6e95f357542f2b771ca32df15a Mon Sep 17 00:00:00 2001 From: Mergul Date: Thu, 10 Apr 2025 14:00:55 +0200 Subject: [PATCH 13/14] Make it possible to use custom runtime (such as numem) --- source/bubel/ecs/manager.d | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/source/bubel/ecs/manager.d b/source/bubel/ecs/manager.d index 0977786..b5220f4 100644 --- a/source/bubel/ecs/manager.d +++ b/source/bubel/ecs/manager.d @@ -27,6 +27,8 @@ alias SerializeVector = bubel.ecs.vector.Vector!ubyte; ///Global EntityManager used for everything. export __gshared EntityManager* gEntityManager = null; +version(D_BetterC) version = NoDRuntime; + /************************************************************************************************************************ Entity manager is responsible for everything. @@ -359,7 +361,7 @@ export struct EntityManager void registerSystem(Sys)(int priority, const(char)[] pass_name) { ushort pass = passes_map.get(pass_name, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(pass != ushort.max, "Update pass doesn't exist."); else assert(pass != ushort.max, "Update pass (Name " ~ pass_name ~ ") doesn't exist."); @@ -381,7 +383,7 @@ export struct EntityManager assert(register_state, "registerSystem must be called between beginRegister() and endRegister()."); - version (D_BetterC) + version (NoDRuntime) assert(pass < passes.length, "Update pass doesn't exist."); else assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist."); @@ -390,7 +392,7 @@ export struct EntityManager enum SystemName = fullName!Sys; //enum SystemName = Sys.stringof; - System system; + System system = System(); system.m_pass = pass; // static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort)) @@ -840,7 +842,7 @@ export struct EntityManager foreach (iii, comp_info; components_info.req) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); @@ -852,7 +854,7 @@ export struct EntityManager foreach (iii, comp_info; components_info.excluded) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); @@ -864,7 +866,7 @@ export struct EntityManager foreach (iii, comp_info; components_info.optional) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); @@ -876,7 +878,7 @@ export struct EntityManager foreach (iii, comp_info; components_info.readonly) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); @@ -888,7 +890,7 @@ export struct EntityManager foreach (iii, comp_info; components_info.mutable) { ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing component."); @@ -1198,7 +1200,7 @@ export struct EntityManager { ushort comp = external_dependencies_map.get(cast(const(char)[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency."); @@ -1211,7 +1213,7 @@ export struct EntityManager foreach (iii, comp_info; components_info.writableDeps) { ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max); - version (D_BetterC) + version (NoDRuntime) assert(comp != ushort.max, "Can't register system \"" ~ SystemName ~ "\" due to non existing dependency."); From f19bce1a57775c0eb995c8603e5ffec97d6634e8 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 14 May 2025 13:26:10 +0200 Subject: [PATCH 14/14] Remove ECSEmscripten as Emscripten version is now supported in LDC (+fix compile scripts) --- compile_wasm.py | 4 +- demos/compile_wasm.py | 10 ++-- meson.build | 2 +- source/bubel/ecs/atomic.d | 121 +------------------------------------- source/bubel/ecs/std.d | 18 ++---- 5 files changed, 15 insertions(+), 140 deletions(-) diff --git a/compile_wasm.py b/compile_wasm.py index 3bd1afd..7214801 100644 --- a/compile_wasm.py +++ b/compile_wasm.py @@ -13,7 +13,7 @@ def compile(sources, output): if file_extension == '.d' and filename != 'package': files.append(os.path.join(r, file)) - ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' + ldc_cmd = 'ldc2 ' + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-emscripten -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' for path in sources: ldc_cmd += '-I' + path + ' ' @@ -33,7 +33,7 @@ def compile(sources, output): shared_flags = '' clean = 0 emc_flags = '' -ldc_flags = '--d-version=ECSEmscripten ' +ldc_flags = '' import_paths = ['source','tests'] build_tests = 0 diff --git a/demos/compile_wasm.py b/demos/compile_wasm.py index 06d31ac..b178260 100644 --- a/demos/compile_wasm.py +++ b/demos/compile_wasm.py @@ -1,7 +1,6 @@ import os import ntpath import sys -import imp def compile(sources, output): files = [] @@ -14,7 +13,7 @@ def compile(sources, output): if file_extension == '.d' and filename != 'package': files.append(os.path.join(r, file)) - ldc_cmd = compiler + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-unknown-wasm -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' + ldc_cmd = compiler + shared_flags + ldc_flags + '-oq -mtriple=wasm32-unknown-emscripten -betterC --output-bc --od=.bc --singleobj --checkaction=C --of=' + output + ' ' for path in sources: ldc_cmd += '-I' + path + ' ' @@ -41,7 +40,7 @@ only_bc = 0 multi = 0 sources = ['tests', 'source'] emc_flags = '-s USE_SDL=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS="[\'png\']" ' -ldc_flags = '--d-version=ECSEmscripten --d-version=SDL_209 --d-version=BindSDL_Static --d-version=BindSDL_Image --d-version=MM_USE_POSIX_THREADS ' +ldc_flags = '--d-version=SDL_209 --d-version=BindSDL_Static --d-version=BindSDL_Image --d-version=MM_USE_POSIX_THREADS ' import_paths = ['external/sources', 'external/imports', 'external/wasm_imports', '../source', 'utils/source', 'simple/source'] for arg in sys.argv[1:]: @@ -121,8 +120,9 @@ emcc_cmd += 'demo.bc ' os.system("mkdir build") -emscripten = imp.load_source('', os.path.expanduser("~") + '/.emscripten') -pack_cmd = emscripten.EMSCRIPTEN_ROOT + '/tools/file_packager.py build/assets.data --preload assets --js-output=build/assets.js' +# emscripten = imp.load_source('', os.path.expanduser("~") + '/.emscripten') +# pack_cmd = emscripten.EMSCRIPTEN_ROOT + '/tools/file_packager.py build/assets.data --preload assets --js-output=build/assets.js' +pack_cmd = os.path.expandvars('$EMSDK/upstream/emscripten') + '/tools/file_packager.py build/assets.data --preload assets --js-output=build/assets.js' print('Packafing files: ' + pack_cmd) os.system(pack_cmd) diff --git a/meson.build b/meson.build index 3f261f8..141cb25 100644 --- a/meson.build +++ b/meson.build @@ -58,7 +58,7 @@ threads_dep = dependency('threads') d_versions = [] deps = [] if host_machine.cpu_family() == 'wasm32' - d_versions += 'ECSEmscripten' + else # meson incorectly adds "-s USE_PTHREADS=1" to ldc2 invocation whe pthreads is added as dependency # add it for non wasm builds diff --git a/source/bubel/ecs/atomic.d b/source/bubel/ecs/atomic.d index 40f0aa9..d8995ae 100644 --- a/source/bubel/ecs/atomic.d +++ b/source/bubel/ecs/atomic.d @@ -9,124 +9,5 @@ License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.atomic; -version (Emscripten) version = ECSEmscripten; +public import core.atomic; -version (ECSEmscripten) -{ - import std.traits; - - enum MemoryOrder - { - acq, - acq_rel, - raw, - rel, - seq - } - - extern (C) ubyte emscripten_atomic_cas_u8(void* addr, ubyte oldVal, ubyte newVal) @nogc nothrow pure; - extern (C) ushort emscripten_atomic_cas_u16(void* addr, ushort oldVal, ushort newVal) @nogc nothrow pure; - extern (C) uint emscripten_atomic_cas_u32(void* addr, uint oldVal, uint newVal) @nogc nothrow pure; - - extern (C) ubyte emscripten_atomic_load_u8(const void* addr) @nogc nothrow pure; - extern (C) ushort emscripten_atomic_load_u16(const void* addr) @nogc nothrow pure; - extern (C) uint emscripten_atomic_load_u32(const void* addr) @nogc nothrow pure; - - extern (C) ubyte emscripten_atomic_store_u8(void* addr, ubyte val) @nogc nothrow pure; - extern (C) ushort emscripten_atomic_store_u16(void* addr, ushort val) @nogc nothrow pure; - extern (C) uint emscripten_atomic_store_u32(void* addr, uint val) @nogc nothrow pure; - - extern (C) ubyte emscripten_atomic_add_u8(void* addr, ubyte val) @nogc nothrow pure; - extern (C) ushort emscripten_atomic_add_u16(void* addr, ushort val) @nogc nothrow pure; - extern (C) uint emscripten_atomic_add_u32(void* addr, uint val) @nogc nothrow pure; - - extern (C) ubyte emscripten_atomic_sub_u8(void* addr, ubyte val) @nogc nothrow pure; - extern (C) ushort emscripten_atomic_sub_u16(void* addr, ushort val) @nogc nothrow pure; - extern (C) uint emscripten_atomic_sub_u32(void* addr, uint val) @nogc nothrow pure; - - public pure nothrow @nogc Unqual!T atomicOp(string op, T, V1)(ref shared T val, V1 mod) - { - static if (op == "+=") - { - static if (is(T == byte) || is(T == ubyte)) - return cast(Unqual!T)(emscripten_atomic_add_u8(cast(void*)&val, - cast(Unqual!T) mod) + 1); - else static if (is(T == short) || is(T == ushort)) - return cast(Unqual!T)(emscripten_atomic_add_u16(cast(void*)&val, - cast(Unqual!T) mod) + 1); - else static if (is(T == int) || is(T == uint)) - return cast(Unqual!T)(emscripten_atomic_add_u32(cast(void*)&val, - cast(Unqual!T) mod) + 1); - else - static assert(0); - } - else static if (op == "-=") - { - static if (is(T == byte) || is(T == ubyte)) - return cast(Unqual!T)(emscripten_atomic_sub_u8(cast(void*)&val, - cast(Unqual!T) mod) - 1); - else static if (is(T == short) || is(T == ushort)) - return cast(Unqual!T)(emscripten_atomic_sub_u16(cast(void*)&val, - cast(Unqual!T) mod) - 1); - else static if (is(T == int) || is(T == uint)) - return cast(Unqual!T)(emscripten_atomic_sub_u32(cast(void*)&val, - cast(Unqual!T) mod) - 1); - else - static assert(0); - } - } - - public pure nothrow @nogc @trusted void atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, - V newval) - { - alias UT = Unqual!T; - static if (is(UT == bool) || is(UT == byte) || is(UT == ubyte)) - emscripten_atomic_store_u8(cast(void*)&val, cast(UT) newval); - else static if (is(UT == short) || is(UT == ushort)) - emscripten_atomic_store_u16(cast(void*)&val, cast(UT) newval); - else static if (is(UT == int) || is(UT == uint)) - emscripten_atomic_store_u32(cast(void*)&val, cast(UT) newval); - else - static assert(0); - } - - public pure nothrow @nogc @trusted T atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)( - ref const T val) - { - alias UT = Unqual!T; - static if (is(UT == bool)) - return emscripten_atomic_load_u8(cast(const void*)&val) != 0; - else static if (is(UT == byte) || is(UT == ubyte)) - return emscripten_atomic_load_u8(cast(const void*)&val); - else static if (is(UT == short) || is(UT == ushort)) - return emscripten_atomic_load_u16(cast(const void*)&val); - else static if (is(UT == int) || is(UT == uint)) - return emscripten_atomic_load_u32(cast(const void*)&val); - else - static assert(0); - } - - public pure nothrow @nogc @trusted bool cas(MemoryOrder succ = MemoryOrder.seq, - MemoryOrder fail = MemoryOrder.seq, T, V1, V2)(T* here, V1 ifThis, V2 writeThis) - { - alias UT = Unqual!T; - static if (is(UT == bool)) - return emscripten_atomic_cas_u8(cast(void*) here, - cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; - else static if (is(UT == byte) || is(UT == ubyte)) - return emscripten_atomic_cas_u8(cast(void*) here, - cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; - else static if (is(UT == short) || is(UT == ushort)) - return emscripten_atomic_cas_u16(cast(void*) here, - cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; - else static if (is(UT == int) || is(UT == uint)) - return emscripten_atomic_cas_u32(cast(void*) here, - cast(Unqual!T) ifThis, cast(Unqual!T) writeThis) == ifThis; - else - static assert(0); - } -} -else -{ - public import core.atomic; -} diff --git a/source/bubel/ecs/std.d b/source/bubel/ecs/std.d index 8eb0d48..8a3e207 100644 --- a/source/bubel/ecs/std.d +++ b/source/bubel/ecs/std.d @@ -7,11 +7,9 @@ License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.std; -version (Emscripten) version = ECSEmscripten; - import std.traits; -version (ECSEmscripten) +version (Emscripten) { extern (C) struct pthread_mutex_t { @@ -29,10 +27,6 @@ version (ECSEmscripten) extern (C) int memcmp(const void* s1, const void* s2, size_t size); extern (C) void exit(int status) nothrow @nogc; - extern (C) void __assert(const(char)* msg, const(char)* file, uint line) - { - exit(-20); - } extern (C) void free(void*) @nogc nothrow @system; extern (C) void* malloc(size_t size) @nogc nothrow @system; @@ -60,7 +54,7 @@ else public import core.stdc.stdlib : qsort; } -version (ECSEmscripten) +version (Emscripten) { } else version (Windows) @@ -89,7 +83,7 @@ else version (Posix) import core.sys.posix.stdlib : posix_memalign; } -version (ECSEmscripten) +version (Emscripten) { private const uint max_alloca = 10000; private __gshared byte[max_alloca] alloca_array; @@ -294,7 +288,7 @@ static struct Mallocator posix_memalign(&ret, alignment, length); //ret = aligned_alloc(alignment, length); else version (Windows) ret = _aligned_malloc(length, alignment); - else version (ECSEmscripten) + else version (Emscripten) posix_memalign(&ret, alignment, length); //malloc(length); else static assert(0, "Unimplemented platform!"); @@ -341,7 +335,7 @@ static struct Mallocator free(cast(void*) object); else version (Windows) _aligned_free(cast(void*) object); - else version (ECSEmscripten) + else version (Emscripten) free(cast(void*) object); else static assert(0, "Unimplemented platform!"); @@ -351,7 +345,7 @@ static struct Mallocator struct Mutex { - version (ECSEmscripten) + version (Emscripten) { void initialize() nothrow @nogc {