Skip to content

Instantly share code, notes, and snippets.

@nikki93
Created July 26, 2021 09:35
Show Gist options
  • Save nikki93/96f681669a0b29297c9ba8dc059cd805 to your computer and use it in GitHub Desktop.
Save nikki93/96f681669a0b29297c9ba8dc059cd805 to your computer and use it in GitHub Desktop.
#pragma once
#include "core.hh"
//
// Entities
//
using Entity = entt::entity;
inline constexpr auto nullEntity = entt::null;
// The global entity registry
inline entt::registry registry;
// Create a new entity
inline Entity createEntity() {
return registry.create();
}
inline Entity createEntity(Entity hint) {
return registry.create(hint);
}
// Destroy an entity
inline Seq<void (*)(Entity), 32> componentRemovers;
inline void destroyEntity(Entity ent) {
for (auto &remover : componentRemovers) {
remover(ent);
}
registry.destroy(ent);
}
// Check that an entity exists
inline bool exists(Entity ent) {
return registry.valid(ent);
}
//
// Components
//
// Component pools
template<typename T>
inline void remove(Entity ent);
template<typename F>
void each(F &&f);
inline bool entitiesClearedOnExit = false;
template<typename T>
struct ComponentPool : entt::storage<T> {
ComponentPool() {
componentRemovers.push_back(remove<T>);
}
~ComponentPool() {
if (!entitiesClearedOnExit) {
each(destroyEntity);
entitiesClearedOnExit = true;
}
}
};
template<typename T>
inline ComponentPool<T> componentPool;
// Check whether entity has a component
template<typename T>
inline bool has(Entity ent) {
return componentPool<std::remove_const_t<T>>.contains(ent);
}
// Get a component on an entity
template<typename T>
inline decltype(auto) get(Entity ent) {
if constexpr (std::is_const_v<T>) {
return (const T &)componentPool<std::remove_const_t<T>>.get(ent);
} else {
return componentPool<T>.get(ent);
}
}
// Add a component to an entity
template<typename T>
inline decltype(auto) add(Entity ent, T &&value = {}) {
static_assert(!std::is_const_v<T>);
if (has<T>(ent)) {
return get<T>(ent);
} else {
auto &comp = componentPool<T>.emplace(ent, std::forward<T>(value));
if constexpr (requires { add(comp, ent); }) {
add(comp, ent);
}
if constexpr (isComponentType<T>) {
forEachProp(comp, [&](auto propTag, auto &propVal) {
if constexpr (requires { set(propTag, comp, ent); }) {
set(propTag, comp, ent);
}
});
}
return comp;
}
}
// Remove a component from an entity
template<typename T>
inline void remove(Entity ent) {
static_assert(!std::is_const_v<T>);
if (has<T>(ent)) {
if constexpr (requires { remove(*((T *)nullptr), ent); }) {
remove(get<T>(ent), ent);
}
componentPool<T>.remove(ent);
}
}
// Query component combinations
template<typename T>
struct Each {};
template<typename R, typename C>
struct Each<R (C::*)(Entity ent) const> {
template<typename F>
static void each(F &&f) {
registry.each(std::forward<F>(f));
}
};
template<typename R, typename C, typename T, typename... Ts>
struct Each<R (C::*)(Entity ent, T &, Ts &...) const> {
static void each(auto &&f) {
for (auto ent : static_cast<entt::sparse_set &>(componentPool<std::remove_const_t<T>>)) {
if ((has<Ts>(ent) && ...)) {
f(ent, get<T>(ent), get<Ts>(ent)...);
}
}
}
};
template<typename R, typename... Args>
inline void each(R (&f)(Args...)) {
each([&](Args... args) {
f(std::forward<Args>(args)...);
});
}
template<typename F>
inline void each(F &&f) {
if constexpr (requires { &F::operator(); }) {
Each<decltype(&F::operator())>::each(std::forward<F>(f));
} else {
each(std::forward<F>(f));
}
}
// Sort component data
template<typename T, typename F>
inline void sort(F &&f) {
static_assert(!std::is_const_v<T>);
componentPool<T>.sort(std::forward<F>(f));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment