/************************************************************************************************************************ System module. Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.system; import bubel.ecs.entity; import bubel.ecs.manager; /************************************************************************************************************************ System contain data required to proper glue EntityManager with Systems. System callbacks: $(LIST * void onUpdate(EntitesData); * void onEnable() - called inside system.enable() function * void onDisable() - called inside system.disable() function * bool onBegin() - called inside manager.begin() * void onEnd() - called inside manager.end() * void onCreate() - called after registration inside registerSystem function * void onDestroy() - called during re-registration and inside manager destructor * void onAddEntity(EntitesData) - called for every entity which are assigned to system (by adding new entity or changing its components) * void onRemoveEntity(EntitiesData) - called for every entity removed from system update process * void onChangeEntity(EntitiesData) - called for every entity which components are changed but it was previously assigned to system * void handleEvent(Entity*, Event) - called for every event supported by system ) */ struct System { /************************************************************************************************************************ Check if system is enabled. */ export bool enabled() nothrow @nogc { return m_enabled; } /************************************************************************************************************************ Enable system. If actually it is enabled function do nothing. */ export void enable() nothrow @nogc { if (!m_enabled && m_enable) (cast(void function(void*) nothrow @nogc) m_enable)(m_system_pointer); m_enabled = true; } /************************************************************************************************************************ Disable system. If actually it is disabled function do nothing. */ export void disable() nothrow @nogc { if (m_enabled && m_disable) (cast(void function(void*) nothrow @nogc) m_disable)(m_system_pointer); m_enabled = false; } /************************************************************************************************************************ Get system priority. */ export int priority() nothrow @nogc { return m_priority; } /************************************************************************************************************************ Get if system will be executed during current frame. Should be checked after manager.begin(). Its value is setted as result of manager.onBegin() callback. */ export bool willExecute() nothrow @nogc { return m_execute; } /************************************************************************************************************************ Get system id. */ export ushort id() nothrow @nogc { return m_id; } /************************************************************************************************************************ Get system name. */ export const(char)[] name() nothrow @nogc { return cast(const(char)[]) m_name; } /************************************************************************************************************************ Return false if system was unregistered, true otherwise. */ export bool isAlive() nothrow @nogc { return m_system_pointer != null; } /************************************************************************************************************************ Return pointer to user side system object */ export void* ptr() nothrow @nogc { return m_system_pointer; } package: ///destory system. Dispose all data 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*) nothrow @nogc) m_destroy)(m_system_pointer); m_destroy = null; } 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 { ushort id; void* callback; } ///should system be executed in current update? bool m_execute = true; ///system id ushort m_id; ///is system empty? Empty systems don't update entities, and is called once per update bool m_empty = false; ///should system update and catch events? bool m_enabled = false; ///system priority int m_priority; ///pointer to system implementation void* m_system_pointer; ///system pass index int m_pass; ///system name char[] m_name; ///required components ushort[] m_components; ///excluded components ushort[] m_excluded_components; ///optional components ushort[] m_optional_components; EntityManager.Job[] jobs; //System*[] m_dependencies; ushort[] m_read_only_components; ushort[] m_writable_components; ushort[] m_readonly_dependencies; ushort[] m_writable_dependencies; EntityManager.SystemCaller* m_any_system_caller; EventCaller[] m_event_callers; //void function(ref EntityManager.CallData data) m_update; void* m_update; ///workaroud for DMD bug with upper line void delegate() m_update_delegate; //void function(void* system_pointer) m_enable; //void function(void* system_pointer) m_disable; //void function(void* system_pointer) m_create; //void function(void* system_pointer) m_destroy; //void function(void* system_pointer) m_begin; //void function(void* system_pointer) m_end; void* m_enable; void* m_disable; void* m_create; void* m_destroy; void* m_begin; void* m_end; void* m_add_entity; void* m_remove_entity; void* m_change_entity; void* m_filter_entity; //void function(ref EntityManager.CallData data) m_initialize; //void function(ref EntityManager.CallData data) m_deinitilize; void* m_initialize; void* m_deinitilize; }