Compare commits
27 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f19bce1a57 | |||
| d77317c816 | |||
| 76a23aa4ed | |||
| 9b75772039 | |||
| 50fa2ce19c | |||
| 8ac9fa5dbd | |||
| beb1837c43 | |||
| 0702b007d1 | |||
| 9bf6f84d45 | |||
| 65c6ea4489 | |||
| ed0603a675 | |||
| 6bf8837e8f | |||
| 6af3028070 | |||
| c2ba4c632a | |||
| 5f4ba90b3e | |||
| 881d6d113b | |||
| 7a614686c8 | |||
| 6c4109d86c | |||
| c0246ce2af | |||
| a8d48f1218 | |||
| ce47bfc65a | |||
| 56ce8c3f9c | |||
| bd2afce19a | |||
| 24a07a05e5 | |||
| 014e9cee8d | |||
| d01ebd960a | |||
| 4f416c7557 |
33 changed files with 1075 additions and 2644 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -13,7 +13,3 @@
|
|||
!compile_android.py
|
||||
!.gitlab-ci.yml
|
||||
!LICENSE
|
||||
!c-api
|
||||
!c-api/*.h
|
||||
!c-api/*.d
|
||||
!c-api/*.c
|
||||
|
|
@ -23,7 +23,7 @@ build_code:
|
|||
|
||||
test_dmd_debug:
|
||||
stage: test
|
||||
image: frolvlad/alpine-glibc
|
||||
image: debian:buster-slim
|
||||
script:
|
||||
- binaries/dmd_debug_unittest
|
||||
artifacts:
|
||||
|
|
@ -31,7 +31,7 @@ test_dmd_debug:
|
|||
junit: test_report.xml
|
||||
test_dmd:
|
||||
stage: test
|
||||
image: frolvlad/alpine-glibc
|
||||
image: debian:buster-slim
|
||||
script:
|
||||
- binaries/dmd_release_unittest
|
||||
artifacts:
|
||||
|
|
@ -39,7 +39,7 @@ test_dmd:
|
|||
junit: test_report.xml
|
||||
test_dmd_betterC:
|
||||
stage: test
|
||||
image: frolvlad/alpine-glibc
|
||||
image: debian:buster-slim
|
||||
script:
|
||||
- binaries/dmd_debug_unittest_bc
|
||||
artifacts:
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
207
c-api/becs.h
207
c-api/becs.h
|
|
@ -1,207 +0,0 @@
|
|||
#ifndef __BECS__
|
||||
#define __BECS__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdalign.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct BECSSystem
|
||||
{
|
||||
|
||||
}BECSSystem;
|
||||
|
||||
typedef struct BECSArray
|
||||
{
|
||||
size_t size;
|
||||
void* ptr;
|
||||
}BECSArray;
|
||||
|
||||
typedef struct EntityID
|
||||
{
|
||||
///Index to entity in IDManager.
|
||||
uint32_t id;
|
||||
///Counter required for reusing ID.
|
||||
uint32_t counter;
|
||||
}EntityID;
|
||||
|
||||
typedef struct Entity
|
||||
{
|
||||
///Entity ID.
|
||||
EntityID id;
|
||||
}Entity;
|
||||
|
||||
typedef struct ComponentRef
|
||||
{
|
||||
///pointer to component
|
||||
void* ptr;
|
||||
///component index
|
||||
uint16_t id;
|
||||
}ComponentRef;
|
||||
|
||||
typedef ComponentRef EventRef;
|
||||
|
||||
typedef struct BECSComponentInfo
|
||||
{
|
||||
///Component size
|
||||
uint16_t size;
|
||||
///Component data alignment
|
||||
uint16_t alignment;
|
||||
///Initialization data
|
||||
BECSArray init_data;
|
||||
///Pointer to component destroy callback
|
||||
void* destroy_callback;
|
||||
///Pointer to component create callback
|
||||
void* create_callback;
|
||||
//void* create_callback;
|
||||
}BECSComponentInfo;
|
||||
|
||||
typedef struct BECSEventRegisterInfo
|
||||
{
|
||||
///Component size
|
||||
uint16_t size;
|
||||
///Component data alignment
|
||||
uint16_t alignment;
|
||||
}BECSEventRegisterInfo;
|
||||
|
||||
typedef struct EntityTemplate
|
||||
{
|
||||
/*///Entity components data
|
||||
BECSArray entity_data;
|
||||
///Pointer to entity type info.
|
||||
void* info;*/
|
||||
}EntityTemplate;
|
||||
|
||||
enum BECSSystemComponentAttribute
|
||||
{
|
||||
required = 0,
|
||||
optional = 1,
|
||||
excluded = 2
|
||||
};
|
||||
|
||||
enum BECSSystemComponentAccess
|
||||
{
|
||||
writable = 0,
|
||||
readonly = 1
|
||||
};
|
||||
|
||||
typedef struct BECSSystemComponentInfo
|
||||
{
|
||||
uint16_t id;
|
||||
enum BECSSystemComponentAttribute attribute;
|
||||
enum BECSSystemComponentAccess access;
|
||||
}BECSSystemComponentInfo;
|
||||
|
||||
///C-API structure conatin only subset of real data which can be accessed directly. Component arrays can be retrived using function calls.
|
||||
typedef struct BECSListenerCallData
|
||||
{
|
||||
uint32_t count;
|
||||
void* context;
|
||||
}BECSListenerCallData;
|
||||
|
||||
///C-API structure conatin only subset of real data which can be accessed directly. Component arrays can be retrived using function calls.
|
||||
typedef struct BECSSystemCallData
|
||||
{
|
||||
uint32_t count;
|
||||
uint32_t thread_id;
|
||||
uint32_t job_id;
|
||||
void* context;
|
||||
}BECSSystemCallData;
|
||||
|
||||
///C-API structure conatin only subset of real data which can be accessed directly. Component arrays can be retrived using function calls.
|
||||
typedef struct BECSEventCallData
|
||||
{
|
||||
Entity* entity;
|
||||
void* event;
|
||||
void* context;
|
||||
}BECSEventCallData;
|
||||
|
||||
typedef struct BECSEventCallback
|
||||
{
|
||||
uint16_t id;
|
||||
void (*callback)(BECSEventCallData* data);
|
||||
}BECSEventCallback;
|
||||
|
||||
typedef struct BECSSystemRegisterInfo
|
||||
{
|
||||
uint32_t pass_id;
|
||||
int32_t priority;
|
||||
uint32_t max_jobs;
|
||||
|
||||
size_t components_count;
|
||||
BECSSystemComponentInfo* components;
|
||||
|
||||
size_t event_handlers_count;
|
||||
BECSEventCallback* event_handlers;
|
||||
|
||||
size_t system_size;
|
||||
void* init_data;
|
||||
|
||||
void (*on_update)(BECSSystemCallData* call_data);
|
||||
void (*on_create)(void* system_pointer);
|
||||
void (*on_destroy)(void* system_pointer);
|
||||
void (*on_enable)(void* system_pointer);
|
||||
void (*on_disable)(void* system_pointer);
|
||||
char (*on_begin)(void* system_pointer);
|
||||
void (*on_end)(void* system_pointer);
|
||||
void (*on_add_entity)(BECSListenerCallData*);
|
||||
void (*on_remove_entity)(BECSListenerCallData*);
|
||||
void (*on_change_entity)(BECSListenerCallData*);
|
||||
void (*filter_entity)(void* system_pointer, void* info);
|
||||
}BECSSystemRegisterInfo;
|
||||
|
||||
void becsInitialize();
|
||||
void becsDestroy();
|
||||
|
||||
void becsBeginRegister();
|
||||
void becsEndRegister();
|
||||
|
||||
void becsBegin();
|
||||
void becsEnd();
|
||||
void becsCommit();
|
||||
|
||||
void becsUpdate(uint16_t pass_id);
|
||||
void becsUpdateMT(uint16_t pass_id);
|
||||
|
||||
uint16_t becsRegisterComponent(const char* name, BECSComponentInfo info);
|
||||
uint16_t becsRegisterEvent(const char* name, BECSEventRegisterInfo info);
|
||||
uint16_t becsRegisterSystem(const char* name, BECSSystemRegisterInfo info);
|
||||
uint16_t becsRegisterPass(const char* name);
|
||||
|
||||
Entity* becsAddEntity(EntityTemplate* template);
|
||||
Entity* becsAddEntityCopy(EntityID id);
|
||||
void becsRemoveEntity(EntityID id);
|
||||
|
||||
Entity* becsGetEntity(EntityID id);
|
||||
|
||||
void becsAddComponents(const EntityID entity_id, size_t length, ComponentRef* comps);
|
||||
void becsRemoveComponents(const EntityID entity_id, size_t length, uint16_t* comps);
|
||||
|
||||
EntityTemplate* becsAllocateTemplate(uint32_t count, uint16_t* components);
|
||||
EntityTemplate* becsAllocateTemplateFromEntity(EntityID id, uint8_t fill_default);
|
||||
EntityTemplate* becsAllocateTemplateCopy(EntityTemplate* tmpl);
|
||||
EntityTemplate* becsAllocateTemplateFromTemplate(EntityTemplate* tmpl, size_t new_count, uint16_t* components, size_t remove_count, uint16_t* remove_components);
|
||||
void becsFreeTemplate(EntityTemplate* tmpl);
|
||||
|
||||
void* becsEntityGetComponent(Entity* entity, uint16_t component_id);
|
||||
|
||||
void* becsSystemCallDataGetComponentArray(BECSSystemCallData* data, uint16_t component_id);
|
||||
Entity* becsSystemCallDataGetEntitiesArray(BECSSystemCallData* data);
|
||||
|
||||
void* becsListenerCallDataGetComponentArray(BECSListenerCallData* data, uint16_t component_id);
|
||||
Entity* becsListenerCallDataGetEntitiesArray(BECSListenerCallData* data);
|
||||
|
||||
void becsCallEntitiesFunction(uint16_t system_id, void (*on_update)(BECSSystemCallData* call_data), void* context);
|
||||
|
||||
void becsSendEvent(EntityID id, EventRef event);
|
||||
|
||||
#define BECS_REGISTER_COMPONENT(comp) \
|
||||
({ \
|
||||
void* mem_ptr = malloc(sizeof(comp)); \
|
||||
memcpy(mem_ptr, &comp, sizeof(comp)); \
|
||||
becsRegisterComponent(#comp, (BECSComponentInfo){sizeof(comp), alignof(comp), (BECSArray){sizeof(comp), mem_ptr}, 0, 0}); \
|
||||
})
|
||||
|
||||
//BECSComponentInfo(sizeof(comp), 4, 0, 0, 0));
|
||||
|
||||
#endif //__BECS__
|
||||
306
c-api/manager.d
306
c-api/manager.d
|
|
@ -1,306 +0,0 @@
|
|||
module manager;
|
||||
|
||||
import bubel.ecs.manager;
|
||||
import bubel.ecs.entity;
|
||||
import bubel.ecs.events;
|
||||
import bubel.ecs.system;
|
||||
import bubel.ecs.std;
|
||||
|
||||
import core.stdc.string;
|
||||
|
||||
extern (C):
|
||||
/*
|
||||
struct BECSComponentInfo
|
||||
{
|
||||
///Component size
|
||||
ushort size;
|
||||
///Component data alignment
|
||||
ushort alignment;
|
||||
///Initialization data
|
||||
ubyte[] init_data;
|
||||
///Pointer to component destroy callback
|
||||
void* destroy_callback;
|
||||
///Pointer to component create callback
|
||||
void* create_callback;
|
||||
//void* create_callback;
|
||||
}*/
|
||||
|
||||
alias BECSComponentInfo = EntityManager.ComponentInfo;
|
||||
// alias BECSEventCallData = EntityManager.EventCallData;
|
||||
|
||||
enum BECSSystemComponentAttribute
|
||||
{
|
||||
required = 0,
|
||||
optional = 1,
|
||||
excluded = 2
|
||||
}
|
||||
|
||||
enum BECSSystemComponentAccess
|
||||
{
|
||||
writable = 0,
|
||||
readonly = 1
|
||||
}
|
||||
|
||||
struct BECSSystemComponentInfo
|
||||
{
|
||||
ushort id;
|
||||
BECSSystemComponentAttribute attribute;
|
||||
BECSSystemComponentAccess access;
|
||||
}
|
||||
|
||||
struct BECSEventCallback
|
||||
{
|
||||
ushort id;
|
||||
void function(EntityManager.EventCallData* data) callback;
|
||||
}
|
||||
|
||||
struct BECSSystemRegisterInfo
|
||||
{
|
||||
uint pass_id;
|
||||
int priority;
|
||||
uint max_jobs;
|
||||
|
||||
BECSSystemComponentInfo[] components;
|
||||
BECSEventCallback[] event_handlers;
|
||||
|
||||
byte[] init_data;
|
||||
|
||||
void function(EntityManager.SystemCallData* call_data) on_update;
|
||||
void function(void* system_pointer) on_create;
|
||||
void function(void* system_pointer) on_destroy;
|
||||
void function(void* system_pointer) on_enable;
|
||||
void function(void* system_pointer) on_disable;
|
||||
bool function(void* system_pointer) on_begin;
|
||||
void function(void* system_pointer) on_end;
|
||||
void function(EntityManager.ListenerCallData*) on_add_entity;
|
||||
void function(EntityManager.ListenerCallData*) on_remove_entity;
|
||||
void function(EntityManager.ListenerCallData*) on_change_entity;
|
||||
void function(void* system_pointer, EntityManager.EntityInfo* info) filter_entity;
|
||||
}
|
||||
|
||||
alias BECSEventRegisterInfo = EntityManager.EventRegisterInfo;
|
||||
|
||||
void becsInitialize()
|
||||
{
|
||||
EntityManager.initialize();
|
||||
}
|
||||
|
||||
void becsDestroy()
|
||||
{
|
||||
EntityManager.destroy();
|
||||
}
|
||||
|
||||
void becsBeginRegister()
|
||||
{
|
||||
gEntityManager.beginRegister();
|
||||
}
|
||||
|
||||
void becsEndRegister()
|
||||
{
|
||||
gEntityManager.endRegister();
|
||||
}
|
||||
|
||||
void becsBegin()
|
||||
{
|
||||
gEntityManager.begin();
|
||||
}
|
||||
|
||||
void becsEnd()
|
||||
{
|
||||
gEntityManager.end();
|
||||
}
|
||||
|
||||
void becsCommit()
|
||||
{
|
||||
gEntityManager.commit();
|
||||
}
|
||||
|
||||
void becsUpdate(ushort pass_id)
|
||||
{
|
||||
gEntityManager.update(pass_id);
|
||||
}
|
||||
|
||||
void becsUpdateMT(ushort pass_id)
|
||||
{
|
||||
gEntityManager.update(pass_id);
|
||||
}
|
||||
|
||||
ushort becsRegisterPass(const (char)* name)
|
||||
{
|
||||
return gEntityManager.registerPass(name[0 .. strlen(name)]);
|
||||
}
|
||||
|
||||
ushort becsRegisterComponent(const(char)* name, BECSComponentInfo info)
|
||||
{
|
||||
return gEntityManager.registerComponent(name[0 .. strlen(name)], info);
|
||||
}
|
||||
|
||||
ushort becsRegisterEvent(const(char)* name, BECSEventRegisterInfo info)
|
||||
{
|
||||
return gEntityManager.registerEvent(name[0 .. strlen(name)], info);
|
||||
}
|
||||
|
||||
ushort becsRegisterSystem(const(char)* name, BECSSystemRegisterInfo info)
|
||||
{
|
||||
System system;
|
||||
|
||||
if(info.init_data.length)
|
||||
{
|
||||
system.m_system_pointer = malloc(info.init_data.length);
|
||||
memcpy(system.m_system_pointer, info.init_data.ptr, info.init_data.length);
|
||||
}
|
||||
|
||||
if(info.event_handlers.length)
|
||||
{
|
||||
system.m_event_callers = Mallocator.makeArray!(System.EventCaller)(info.event_handlers.length);
|
||||
foreach(i, BECSEventCallback callback; info.event_handlers)
|
||||
{
|
||||
system.m_event_callers[i].id = callback.id;
|
||||
system.m_event_callers[i].callback = callback.callback;
|
||||
}
|
||||
}
|
||||
|
||||
system.m_update = info.on_update;
|
||||
system.m_create = info.on_create;
|
||||
system.m_destroy = info.on_destroy;
|
||||
system.m_enable = info.on_enable;
|
||||
system.m_disable = info.on_disable;
|
||||
system.m_begin = info.on_begin;
|
||||
system.m_end = info.on_end;
|
||||
system.m_add_entity = info.on_add_entity;
|
||||
system.m_remove_entity = info.on_remove_entity;
|
||||
system.m_change_entity = info.on_change_entity;
|
||||
system.m_filter_entity = info.filter_entity;
|
||||
|
||||
if(info.components.length)
|
||||
{
|
||||
uint req;
|
||||
uint opt;
|
||||
foreach(comp; info.components)
|
||||
{
|
||||
if(comp.attribute == BECSSystemComponentAttribute.required)req++;
|
||||
else if(comp.attribute == BECSSystemComponentAttribute.optional)opt++;
|
||||
}
|
||||
if(req)system.m_components = Mallocator.makeArray!ushort(req);
|
||||
if(opt)system.m_optional_components = Mallocator.makeArray!ushort(opt);
|
||||
req = 0;
|
||||
opt = 0;
|
||||
foreach(comp; info.components)
|
||||
{
|
||||
if(comp.attribute == BECSSystemComponentAttribute.required)
|
||||
{
|
||||
system.m_components[req++] = comp.id;
|
||||
}
|
||||
else if(comp.attribute == BECSSystemComponentAttribute.optional)
|
||||
{
|
||||
system.m_optional_components[opt++] = comp.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
system.m_empty = true;
|
||||
}
|
||||
return gEntityManager.registerSystem(name[0 .. strlen(name)], system);
|
||||
}
|
||||
|
||||
EntityTemplate* becsAllocateTemplate(uint count, ushort* components)
|
||||
{
|
||||
return gEntityManager.allocateTemplate(components[0 .. count]);
|
||||
}
|
||||
|
||||
EntityTemplate* becsAllocateTemplateFromEntity(EntityID id, bool fill_default)
|
||||
{
|
||||
return gEntityManager.allocateTemplate(id, fill_default);
|
||||
}
|
||||
|
||||
EntityTemplate* becsAllocateTemplateCopy(EntityTemplate* tmpl)
|
||||
{
|
||||
return gEntityManager.allocateTemplate(tmpl);
|
||||
}
|
||||
|
||||
EntityTemplate* becsAllocateTemplateFromTemplate(EntityTemplate* tmpl, size_t new_count, ushort* components, size_t remove_count, ushort* remove_components)
|
||||
{
|
||||
return gEntityManager.allocateTemplate(tmpl, components[0 .. new_count], remove_components[0 .. remove_count]);
|
||||
}
|
||||
|
||||
void becsFreeTemplate(EntityTemplate* tmpl)
|
||||
{
|
||||
gEntityManager.freeTemplate(tmpl);
|
||||
}
|
||||
|
||||
Entity* becsAddEntity(EntityTemplate* tmpl)
|
||||
{
|
||||
return gEntityManager.addEntity(tmpl);
|
||||
}
|
||||
|
||||
Entity* becsAddEntityCopy(EntityID id)
|
||||
{
|
||||
return gEntityManager.addEntityCopy(id);
|
||||
}
|
||||
|
||||
void becsRemoveEntity(EntityID id)
|
||||
{
|
||||
gEntityManager.removeEntity(id);
|
||||
}
|
||||
|
||||
Entity* becsGetEntity(EntityID id)
|
||||
{
|
||||
return gEntityManager.getEntity(id);
|
||||
}
|
||||
|
||||
void* becsEntityGetComponent(Entity* entity, ushort component_id)
|
||||
{
|
||||
return entity.getComponent(component_id);
|
||||
}
|
||||
|
||||
void* becsSystemCallDataGetComponentArray(EntityManager.SystemCallData* data, ushort component_id)
|
||||
{
|
||||
if(data.info.deltas.length <= component_id || data.info.deltas[component_id] == 0)return null;
|
||||
return cast(void*)data.block + data.info.deltas[component_id];
|
||||
}
|
||||
|
||||
Entity* becsSystemCallDataGetEntitiesArray(EntityManager.SystemCallData* data)
|
||||
{
|
||||
return cast(Entity*)data.block.dataBegin();
|
||||
}
|
||||
|
||||
void* becsListenerCallDataGetComponentArray(EntityManager.ListenerCallData* data, ushort component_id)
|
||||
{
|
||||
if(data.info.deltas.length <= component_id || data.info.deltas[component_id] == 0)return null;
|
||||
return cast(void*)data.block + data.info.deltas[component_id];
|
||||
}
|
||||
|
||||
Entity* becsListenerCallDataGetEntitiesArray(EntityManager.ListenerCallData* data)
|
||||
{
|
||||
return cast(Entity*)data.block.dataBegin();
|
||||
}
|
||||
|
||||
void becsCallEntitiesFunction(ushort system_id, void function(EntityManager.SystemCallData*) callback, void* context)
|
||||
{
|
||||
System* system = gEntityManager.getSystem(system_id);
|
||||
|
||||
if (!system.m_any_system_caller)
|
||||
return;
|
||||
|
||||
foreach (info; system.m_any_system_caller.infos)
|
||||
{
|
||||
EntityManager.CallData data = EntityManager.CallData(system.id, system, info, context, cast(void*)callback);
|
||||
data.update();
|
||||
}
|
||||
}
|
||||
|
||||
void becsAddComponents(const EntityID entity_id, ComponentRef[] comps)
|
||||
{
|
||||
gEntityManager.addComponents(entity_id, comps);
|
||||
}
|
||||
|
||||
void becsRemoveComponents(const EntityID entity_id, ushort[] comps)
|
||||
{
|
||||
gEntityManager.removeComponents(entity_id, comps);
|
||||
}
|
||||
|
||||
void becsSendEvent(EntityID id, EventRef event)
|
||||
{
|
||||
gEntityManager.sendEvent(id, event);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
src += files(
|
||||
'manager.d'
|
||||
)
|
||||
|
||||
c_src = files(
|
||||
'test.c'
|
||||
)
|
||||
1051
c-api/test.c
1051
c-api/test.c
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:]:
|
||||
|
|
@ -75,7 +74,7 @@ for arg in sys.argv[1:]:
|
|||
elif(arg == '-opt'):
|
||||
shared_flags += '-O3 '
|
||||
ldc_flags += '-release -enable-inlining '
|
||||
emc_flags += '--llvm-lto 3 '
|
||||
emc_flags += '--llvm-lto 3 -s SIMD=1 '
|
||||
elif(arg == '-quiet'):
|
||||
emc_flags += "-Wl,--no-check-features "
|
||||
elif(arg == '--clean'):
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ sdl2_image_dep = dependency('SDL2_image')
|
|||
|
||||
subdir('utils') # Utils library
|
||||
|
||||
executable('decs-demos', [demos_src, external_src],
|
||||
executable('BubelECSDemos', [demos_src, external_src],
|
||||
include_directories : [demos_inc, external_inc],
|
||||
d_module_versions : versions,
|
||||
link_with : [ecs_lib, ecs_utils_lib],
|
||||
|
|
@ -27,7 +27,7 @@ executable('decs-demos', [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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
]
|
||||
|
|
|
|||
8
dub.json
8
dub.json
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "bubel_ecs",
|
||||
"targetName" : "bubel_ecs",
|
||||
"name": "bubel-ecs",
|
||||
"targetName" : "BubelECS",
|
||||
"authors": [
|
||||
"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":[
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
],
|
||||
"dflags": [
|
||||
"-unittest",
|
||||
"-cov"
|
||||
"-cov=ctfe"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
55
meson.build
55
meson.build
|
|
@ -1,17 +1,15 @@
|
|||
project('decs', 'd', version : '0.1.0')
|
||||
project('bubel-ecs', 'd', version : '0.5.0')
|
||||
|
||||
# Options
|
||||
betterC_opt = get_option('betterC')
|
||||
BuildDemos_opt = get_option('BuildDemos')
|
||||
BuildTests_opt = get_option('BuildTests')
|
||||
LTO_otp = get_option('LTO')
|
||||
C_API_opt = get_option('C-API')
|
||||
|
||||
summary('betterC enabled', betterC_opt)
|
||||
summary('build demos', BuildDemos_opt)
|
||||
summary('build tests', BuildTests_opt)
|
||||
summary('LTO enabled', LTO_otp)
|
||||
summary('C-API enabled', C_API_opt)
|
||||
|
||||
meson_minimum_version = '>=0.57.1'
|
||||
assert(meson.version().version_compare(meson_minimum_version), 'Newer verson of meson required, current version: @0@, required: @1@'.format(meson.version(), meson_minimum_version))
|
||||
|
|
@ -20,14 +18,7 @@ assert(meson.version().version_compare(meson_minimum_version), 'Newer verson of
|
|||
src = files()
|
||||
subdir('source')
|
||||
|
||||
inc = [include_directories('source/')]
|
||||
|
||||
#C API files
|
||||
if C_API_opt
|
||||
c_src = files()
|
||||
subdir('c-api')
|
||||
inc += include_directories('c-api/')
|
||||
endif
|
||||
inc = include_directories('source/')
|
||||
|
||||
# Arguments
|
||||
args = []
|
||||
|
|
@ -58,49 +49,39 @@ if betterC_opt
|
|||
endif
|
||||
endif
|
||||
|
||||
if comp_id == 'gcc'
|
||||
args+='-pthread'
|
||||
link_args+='-pthread'
|
||||
endif
|
||||
|
||||
add_project_arguments(args, language : 'd')
|
||||
add_project_link_arguments(link_args, language : 'd')
|
||||
|
||||
# Dependencies
|
||||
threads_dep = dependency('threads')
|
||||
|
||||
ecs_lib = library('decs',
|
||||
d_versions = []
|
||||
deps = []
|
||||
if host_machine.cpu_family() == 'wasm32'
|
||||
|
||||
else
|
||||
# meson incorectly adds "-s USE_PTHREADS=1" to ldc2 invocation whe pthreads is added as dependency
|
||||
# add it for non wasm builds
|
||||
deps += threads_dep
|
||||
endif
|
||||
|
||||
ecs_lib = library('BubelECS',
|
||||
src,
|
||||
d_module_versions : d_versions,
|
||||
include_directories : [inc],
|
||||
)
|
||||
|
||||
decs_dep = declare_dependency(
|
||||
bubel_ecs_dep = declare_dependency(
|
||||
include_directories : [inc],
|
||||
link_with : ecs_lib,
|
||||
dependencies : threads_dep,
|
||||
dependencies : deps,
|
||||
)
|
||||
|
||||
meson.override_dependency('bubel-ecs', bubel_ecs_dep)
|
||||
|
||||
# Tests
|
||||
if BuildTests_opt
|
||||
subdir('tests')
|
||||
|
||||
executable('d-api-tests',
|
||||
['tests/tests.d'],
|
||||
include_directories : [inc],
|
||||
d_args : args,
|
||||
link_args : link_args,
|
||||
dependencies : decs_dep,
|
||||
)
|
||||
|
||||
if C_API_opt
|
||||
add_languages('c')
|
||||
executable('c-api-tests',
|
||||
['c-api/test.c'],
|
||||
include_directories : [inc],
|
||||
dependencies : decs_dep,
|
||||
)
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
# Demos
|
||||
|
|
|
|||
|
|
@ -2,4 +2,3 @@ option('betterC', type: 'boolean', value: false)
|
|||
option('BuildDemos', type: 'boolean', value: false)
|
||||
option('BuildTests', type: 'boolean', value: false)
|
||||
option('LTO', type: 'boolean', value: false)
|
||||
option('C-API', type: 'boolean', value: false)
|
||||
|
|
|
|||
|
|
@ -4,129 +4,10 @@ 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
/************************************************************************************************************************
|
||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||
*/
|
||||
module bubel.ecs.events;
|
||||
|
||||
import bubel.ecs.block_allocator;
|
||||
|
|
@ -8,8 +12,6 @@ import bubel.ecs.traits : becsID;
|
|||
|
||||
import std.algorithm.comparison : max;
|
||||
|
||||
alias EventRef = ComponentRef;
|
||||
|
||||
package struct EventManager
|
||||
{
|
||||
|
||||
|
|
@ -32,17 +34,12 @@ package struct EventManager
|
|||
}
|
||||
|
||||
export void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) nothrow @nogc
|
||||
{
|
||||
sendEvent(id, EventRef(&event, becsID!Ev), thread_id);
|
||||
}
|
||||
|
||||
export void sendEvent(EntityID id, EventRef event, uint thread_id = 0) nothrow @nogc
|
||||
{
|
||||
uint block_id = current_index + thread_id;
|
||||
|
||||
EventData* data = &events[event.component_id];
|
||||
EventData* data = &events[becsID!Ev];
|
||||
EventBlock* block = data.blocks[block_id];
|
||||
EntityManager.EventInfo* info = &manager.events[event.component_id];
|
||||
//EntityManager.EventInfo* info = &manager.events[Ev.event_id];
|
||||
//event.entity_id = id;
|
||||
|
||||
if (block is null)
|
||||
|
|
@ -68,11 +65,10 @@ package struct EventManager
|
|||
data.blocks[block_id] = block;
|
||||
}
|
||||
|
||||
uint size = info.size + EntityID.sizeof;
|
||||
uint size = Ev.sizeof + EntityID.sizeof;
|
||||
void* ptr = cast(void*) block + data.data_offset + block.count * size;
|
||||
*cast(EntityID*)ptr = id;
|
||||
memcpy(ptr + EntityID.sizeof, event.ptr, info.size);
|
||||
//*cast(Ev*)(ptr + EntityID.sizeof) = event;
|
||||
*cast(Ev*)(ptr + EntityID.sizeof) = event;
|
||||
//Ev* event_array = cast(Ev*)(cast(void*) block + data.data_offset);
|
||||
//event_array[block.count] = event;
|
||||
block.count++;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
module bubel.ecs.hash_map;
|
||||
/************************************************************************************************************************
|
||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||
*/
|
||||
module bubel.ecs.hash_map;
|
||||
|
||||
import std.traits;
|
||||
|
||||
|
|
@ -24,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;
|
||||
|
||||
|
|
@ -332,36 +336,36 @@ nothrow:
|
|||
return result;
|
||||
}
|
||||
|
||||
export int byKey(scope int delegate(Key k) nothrow dg)
|
||||
export int byKey(scope int delegate(ref Key k) dg)
|
||||
{
|
||||
int result;
|
||||
foreach (ref Key k; this)
|
||||
{
|
||||
result = dg(k);
|
||||
result = (cast(int delegate(ref Key k) nothrow @nogc)dg)(k);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export int byValue(scope int delegate(ref Value k) nothrow dg)
|
||||
export int byValue(scope int delegate(ref Value v) dg)
|
||||
{
|
||||
int result;
|
||||
foreach (ref Value v; this)
|
||||
{
|
||||
result = dg(v);
|
||||
result = (cast(int delegate(ref Value v) nothrow @nogc)dg)(v);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export int byKeyValue(scope int delegate(ref Key k, ref Value v) nothrow dg)
|
||||
export int byKeyValue(scope int delegate(ref Key k, ref Value v) dg)
|
||||
{
|
||||
int result;
|
||||
foreach (ref Key k, ref Value v; this)
|
||||
{
|
||||
result = dg(k, v);
|
||||
result = (cast(int delegate(ref Key k, ref Value v) nothrow @nogc)dg)(k, v);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
/************************************************************************************************************************
|
||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||
*/
|
||||
module bubel.ecs.id_manager;
|
||||
|
||||
import bubel.ecs.entity;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,3 +1,7 @@
|
|||
/************************************************************************************************************************
|
||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||
*/
|
||||
module ecs;
|
||||
|
||||
public import bubel.ecs.core;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
/************************************************************************************************************************
|
||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||
*/
|
||||
module bubel.ecs.simple_vector;
|
||||
|
||||
import bubel.ecs.std;
|
||||
|
|
|
|||
|
|
@ -2,16 +2,14 @@
|
|||
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;
|
||||
|
||||
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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -89,38 +89,100 @@ struct System
|
|||
return cast(const(char)[]) m_name;
|
||||
}
|
||||
|
||||
//package:
|
||||
/************************************************************************************************************************
|
||||
Return false if system was unregistered, true otherwise.
|
||||
*/
|
||||
export bool isAlive() nothrow @nogc
|
||||
{
|
||||
return m_system_pointer != null;
|
||||
}
|
||||
|
||||
void destroy()
|
||||
/************************************************************************************************************************
|
||||
Return pointer to user side system object
|
||||
*/
|
||||
export void* ptr() nothrow @nogc
|
||||
{
|
||||
return m_system_pointer;
|
||||
}
|
||||
|
||||
package:
|
||||
|
||||
///destory system. Dispose all data
|
||||
export void destroy() nothrow @nogc
|
||||
{
|
||||
import bubel.ecs.std : Mallocator;
|
||||
|
||||
destroySystemData();
|
||||
|
||||
if (m_name)
|
||||
{
|
||||
Mallocator.dispose(m_name);
|
||||
m_name = null;
|
||||
}
|
||||
}
|
||||
|
||||
///destroy all system data but keeps name which is used for case of system re-registration
|
||||
void destroySystemData() nothrow @nogc
|
||||
{
|
||||
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
|
||||
|
|
@ -170,7 +232,7 @@ struct System
|
|||
|
||||
//void function(ref EntityManager.CallData data) m_update;
|
||||
void* m_update; ///workaroud for DMD bug with upper line
|
||||
//void delegate() m_update_delegate;
|
||||
void delegate() m_update_delegate;
|
||||
|
||||
//void function(void* system_pointer) m_enable;
|
||||
//void function(void* system_pointer) m_disable;
|
||||
|
|
@ -198,6 +260,6 @@ struct System
|
|||
|
||||
//void function(ref EntityManager.CallData data) m_initialize;
|
||||
//void function(ref EntityManager.CallData data) m_deinitilize;
|
||||
// void* m_initialize;
|
||||
// void* m_deinitilize;
|
||||
void* m_initialize;
|
||||
void* m_deinitilize;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
/************************************************************************************************************************
|
||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||
*/
|
||||
module bubel.ecs.traits;
|
||||
|
||||
import std.traits;
|
||||
|
|
@ -7,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;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
/************************************************************************************************************************
|
||||
Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
|
||||
License: BSD 3-clause, see LICENSE file in project root folder.
|
||||
*/
|
||||
module bubel.ecs.vector;
|
||||
|
||||
import core.bitop;
|
||||
|
|
|
|||
102
tests/basic.d
102
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
|
||||
|
|
@ -650,8 +750,6 @@ unittest
|
|||
|
||||
void onAddEntity(EntitiesData data)
|
||||
{
|
||||
foreach(i; 0..data.length)
|
||||
data.long_[i] += 1;
|
||||
add++;
|
||||
assert(add_order == 1);
|
||||
add_order++;
|
||||
|
|
|
|||
29
tests/bugs.d
29
tests/bugs.d
|
|
@ -144,3 +144,32 @@ unittest
|
|||
|
||||
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();
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ tests_src = files(
|
|||
'vector.d'
|
||||
)
|
||||
|
||||
exe = executable('decs-tests',
|
||||
exe = executable('BubelECSTests',
|
||||
tests_src,
|
||||
include_directories : [inc, include_directories('..')],
|
||||
d_args : args,
|
||||
|
|
|
|||
|
|
@ -283,13 +283,13 @@ struct ChangeTestSystem
|
|||
|
||||
bool onBegin()
|
||||
{
|
||||
// writeln("On Test System begin.");
|
||||
////writeln("On Test System begin.");
|
||||
return true;
|
||||
}
|
||||
|
||||
void onEnd()
|
||||
{
|
||||
// writeln("On Test System end.");
|
||||
////writeln("On Test System end.");
|
||||
}
|
||||
|
||||
void initialize(ref Entity entity, ref TestComp comp)
|
||||
|
|
@ -307,10 +307,10 @@ struct ChangeTestSystem
|
|||
|
||||
void onUpdate(EntitiesData data)
|
||||
{
|
||||
/*foreach (i; 0 .. data.length)
|
||||
foreach (i; 0 .. data.length)
|
||||
{
|
||||
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -318,8 +318,6 @@ struct TestSystem
|
|||
{
|
||||
mixin ECS.System!16; //__gshared ushort system_id;
|
||||
|
||||
uint print = 1;
|
||||
|
||||
void onCreate()
|
||||
{
|
||||
//writeln("On Test System create.");
|
||||
|
|
@ -345,14 +343,13 @@ struct TestSystem
|
|||
|
||||
bool onBegin()
|
||||
{
|
||||
if(print)printf("On Test System begin.\n");
|
||||
////writeln("On Test System begin.");
|
||||
return true;
|
||||
}
|
||||
|
||||
void onEnd()
|
||||
{
|
||||
if(print)printf("On Test System end.\n");
|
||||
print = 0;
|
||||
////writeln("On Test System end.");
|
||||
}
|
||||
|
||||
void initialize(ref Entity entity, ref TestComp comp)
|
||||
|
|
@ -409,7 +406,7 @@ struct TestSystemWithHighPriority
|
|||
|
||||
void initialize(ref Entity entity, ref TestComp comp)
|
||||
{
|
||||
|
||||
int o = 1;
|
||||
}
|
||||
|
||||
void onUpdate(EntitiesData data)
|
||||
|
|
@ -847,7 +844,6 @@ else:
|
|||
//dur = (MonoTime.currTime - time).total!"usecs";
|
||||
//writeln("Entities adding: ", dur, " usecs");
|
||||
printf("Entities adding: %f usecs\n", cast(float)(Time.getUSecTime() - time));
|
||||
Mallocator.dispose(idss);
|
||||
time = Time.getUSecTime();
|
||||
|
||||
uint blocks = 0;
|
||||
|
|
@ -1025,6 +1021,8 @@ else:
|
|||
gEntityManager.freeTemplate(copy_default_tempalte);
|
||||
EntityManager.destroy();
|
||||
|
||||
Mallocator.dispose(idss);
|
||||
|
||||
printf("end\n"); //*/
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue