conversion to c by gemini 4 argon
This commit is contained in:
1 parent
b70e2d21d2
commit
f9356f9ba7
369 files changed
+18074
-107634
No files matched your search
@@ -0,0 +1,115 @@
|
||||
#include <Entity/Entity.h>
|
||||
|
||||
#include <Core/Common/serialization.h>
|
||||
#include <Core/Memory/Utils.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void serialize_entity(Archive* ar, Entity* entity)
|
||||
{
|
||||
Assert(ar != NULL);
|
||||
Assert(entity != NULL);
|
||||
|
||||
// Entity fields
|
||||
serialize_class(ar, ClassKind(Entity), entity);
|
||||
|
||||
// Derived fields
|
||||
if (entity->derived_kind != NULL && entity->derived != NULL)
|
||||
{
|
||||
serialize_class(ar, entity->derived_kind, entity->derived);
|
||||
}
|
||||
}
|
||||
|
||||
internal void init_Entity(void* payload)
|
||||
{
|
||||
Assert(payload != NULL);
|
||||
Entity* entity = (Entity*)payload;
|
||||
MemZeroStruct(entity);
|
||||
}
|
||||
|
||||
internal void serialize_Entity(Archive* ar, uint16 version, void* payload)
|
||||
{
|
||||
(void)version;
|
||||
Assert(ar != NULL);
|
||||
Assert(payload != NULL);
|
||||
Entity* entity = (Entity*)payload;
|
||||
SERIALIZE_U64(ar, id, &entity->ID);
|
||||
SERIALIZE_VEC4(ar, position, &entity->position);
|
||||
}
|
||||
|
||||
DEFINE_CLASS_VERSIONED(Entity, 1, NULL)
|
||||
|
||||
String format_entity_id(Arena* arena, EntityID entity_id)
|
||||
{
|
||||
Assert(arena != NULL);
|
||||
|
||||
// Format:
|
||||
// U = UserID
|
||||
// LC = Local Entity Counter
|
||||
// UU_LCLCLCLCLCLCLC
|
||||
uint8 user_id = get_user_id(entity_id);
|
||||
uint64 counter = get_local_counter(entity_id);
|
||||
|
||||
const size_t kBufferSize = 18;
|
||||
char* buffer = ArenaPushArray(arena, char, kBufferSize);
|
||||
Assert(buffer != NULL);
|
||||
|
||||
juliet_snprintf(buffer, kBufferSize, "%02X_%014llX", (unsigned int)user_id, (unsigned long long)counter);
|
||||
String result = { .Str = buffer, .Size = kBufferSize - 1 };
|
||||
return result;
|
||||
}
|
||||
|
||||
bool8 parse_entity_id(String str, EntityID* out_id)
|
||||
{
|
||||
Assert(out_id != NULL);
|
||||
|
||||
bool8 result = false;
|
||||
*out_id = kInvalid_entity_id;
|
||||
|
||||
if (!(str.Size != 17 || str.Str == NULL || str.Str[2] != '_'))
|
||||
{
|
||||
char user_hex[3] = { str.Str[0], str.Str[1], '\0' };
|
||||
char* end = user_hex;
|
||||
uint8 user_id = (uint8)strtoul(user_hex, &end, 16);
|
||||
if (end != user_hex && user_id != kInvalid_user_id)
|
||||
{
|
||||
char* counter_hex = str.Str + 3;
|
||||
end = counter_hex;
|
||||
uint64 counter = strtoull(counter_hex, &end, 16);
|
||||
if (end != counter_hex && counter < kEntityID_user_id_mask)
|
||||
{
|
||||
*out_id = make_entity_id(user_id, counter);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const Class* resolve_entity_class(uint8 kind, uint32 crc)
|
||||
{
|
||||
Assert(kind <= ENTITY(Count));
|
||||
|
||||
const Class* class_ptr = kEntity_type_class_ptr[kind];
|
||||
Assert(class_ptr != NULL);
|
||||
Assert(class_get_crc(class_ptr) == crc);
|
||||
|
||||
return class_ptr;
|
||||
}
|
||||
|
||||
const Class* find_class_by_name(String name)
|
||||
{
|
||||
Assert(IsValidString(name));
|
||||
|
||||
const Class* result = NULL;
|
||||
const uint32 name_crc = crc32_bytes(name.Str, name.Size);
|
||||
for (uint8 kind = 0; kind < ENTITY(Count); ++kind)
|
||||
{
|
||||
const Class* class_ptr = resolve_entity_class(kind, name_crc);
|
||||
if (class_ptr != NULL)
|
||||
{
|
||||
result = class_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
#include <Entity/Entity.h>
|
||||
|
||||
#include <Core/Common/serialization.h>
|
||||
|
||||
void serialize(Archive& ar, NonNullPtr<Entity> entity)
|
||||
{
|
||||
// Entity fields
|
||||
serialize(ar, Entity::kind, entity.Get());
|
||||
|
||||
// Derived fields
|
||||
if (entity->derived_kind != nullptr && entity->derived != nullptr)
|
||||
{
|
||||
serialize(ar, entity->derived_kind, entity->derived);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_CLASS_VERSIONED(Entity, 1, nullptr)
|
||||
internal void serialize(Archive& ar, uint16 /*version*/, Entity& entity)
|
||||
{
|
||||
SERIALIZE(ar, id, entity.ID);
|
||||
SERIALIZE(ar, position, entity.position);
|
||||
}
|
||||
|
||||
String format_entity_id(NonNullPtr<Arena> arena, EntityID entity_id)
|
||||
{
|
||||
// Format:
|
||||
// U = UserID
|
||||
// LC = Local Entity Counter
|
||||
// UU_LCLCLCLCLCLCLC
|
||||
uint8 user_id = get_user_id(entity_id);
|
||||
uint64 counter = get_local_counter(entity_id);
|
||||
|
||||
constexpr size_t kBufferSize = 18;
|
||||
char* buffer = ArenaPushArray<char>(arena, kBufferSize);
|
||||
Assert(buffer);
|
||||
|
||||
juliet_snprintf(buffer, kBufferSize, "%02X_%014llX", (unsigned int)user_id, counter);
|
||||
return { buffer, kBufferSize - 1 };
|
||||
}
|
||||
|
||||
bool parse_entity_id(String str, EntityID& out_id)
|
||||
{
|
||||
bool result = false;
|
||||
out_id = kInvalid_entity_id;
|
||||
|
||||
if (!(str.Size != 17 || str.Str == nullptr || str.Str[2] != '_'))
|
||||
{
|
||||
char user_hex[3]{ str.Str[0], str.Str[1], '\0' };
|
||||
char* end = user_hex;
|
||||
uint8 user_id = strtoul(user_hex, &end, 16);
|
||||
if (end != user_hex && user_id != kInvalid_user_id)
|
||||
{
|
||||
char* counter_hex = str.Str + 3;
|
||||
end = counter_hex;
|
||||
uint64 counter = strtoull(counter_hex, &end, 16);
|
||||
if (end != counter_hex && counter < kEntityID_user_id_mask)
|
||||
{
|
||||
out_id = make_entity_id(user_id, counter);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const Class* resolve_entity_class(uint8 kind, uint32 crc)
|
||||
{
|
||||
Assert(kind <= ENTITY(Count));
|
||||
|
||||
NonNullPtr<const Class> class_ptr = kEntity_type_class_ptr[kind];
|
||||
Assert(class_ptr->CRC == crc);
|
||||
|
||||
return class_ptr.Get();
|
||||
}
|
||||
|
||||
const Class* find_class_by_name(String name)
|
||||
{
|
||||
Assert(IsValid(name));
|
||||
|
||||
const Class* result = nullptr;
|
||||
const uint32 name_crc = crc32(name.Str, name.Size);
|
||||
for (uint8 kind = 0; kind < ENTITY(Count); ++kind)
|
||||
{
|
||||
const Class* class_ptr = resolve_entity_class(kind, name_crc);
|
||||
if (class_ptr != nullptr)
|
||||
{
|
||||
result = class_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
+48
-51
@@ -6,98 +6,95 @@
|
||||
#include <Entity/entity_common.h>
|
||||
#include <Entity/EntityManager.h>
|
||||
|
||||
struct Entity final
|
||||
typedef struct Entity Entity;
|
||||
struct Entity
|
||||
{
|
||||
DECLARE_CLASS()
|
||||
|
||||
EntityID ID = 0;
|
||||
const Class* derived_kind = nullptr;
|
||||
DerivedType derived = nullptr;
|
||||
Vector4 position = {};
|
||||
bool is_dirty = false;
|
||||
EntityID ID;
|
||||
const Class* derived_kind;
|
||||
DerivedType derived;
|
||||
Vector4 position;
|
||||
bool8 is_dirty;
|
||||
};
|
||||
DECLARE_CLASS(Entity)
|
||||
|
||||
// Can reinterpret cast to this to have the offset of Base and Kind for any entity
|
||||
// Can cast to this to have the offset of base for any entity
|
||||
typedef struct EntityTemplate EntityTemplate;
|
||||
struct EntityTemplate
|
||||
{
|
||||
DECLARE_ENTITY();
|
||||
DECLARE_ENTITY()
|
||||
};
|
||||
|
||||
//
|
||||
template <typename EntityType>
|
||||
concept EntityConcept = requires(EntityType entity) {
|
||||
{ EntityType::kind } -> std::convertible_to<const Class*>;
|
||||
requires std::same_as<decltype(entity.base), Entity*>;
|
||||
};
|
||||
|
||||
inline constexpr EntityID make_entity_id(uint8 user_id, uint64 local_counter)
|
||||
static inline EntityID make_entity_id(uint8 user_id, uint64 local_counter)
|
||||
{
|
||||
Assert(user_id != kInvalid_user_id);
|
||||
Assert((local_counter & kEntityID_user_id_mask) == kInvalid_entity_id);
|
||||
|
||||
EntityID result = kInvalid_user_id;
|
||||
result = ((EntityID)user_id << kEntityID_user_id_shift) | (local_counter & kEntityID_user_id_mask);
|
||||
EntityID result = ((EntityID)user_id << kEntityID_user_id_shift) | (local_counter & kEntityID_user_id_mask);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline constexpr uint8 get_user_id(EntityID entity_id)
|
||||
static inline uint8 get_user_id(EntityID entity_id)
|
||||
{
|
||||
return (((uint8)entity_id & kEntityID_user_id_mask) << kEntityID_user_id_shift);
|
||||
return (uint8)((entity_id & kEntityID_user_id_mask) >> kEntityID_user_id_shift);
|
||||
}
|
||||
|
||||
inline constexpr uint64 get_local_counter(EntityID entity_id)
|
||||
static inline uint64 get_local_counter(EntityID entity_id)
|
||||
{
|
||||
return (uint64)entity_id & kEntityID_user_id_mask;
|
||||
return (uint64)entity_id & ~kEntityID_user_id_mask;
|
||||
}
|
||||
|
||||
inline constexpr bool is_entity_id_valid(EntityID entity_id)
|
||||
static inline bool8 is_entity_id_valid(EntityID entity_id)
|
||||
{
|
||||
bool result = entity_id != kInvalid_entity_id;
|
||||
bool8 result = (entity_id != kInvalid_entity_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename EntityType>
|
||||
requires EntityConcept<EntityType>
|
||||
[[nodiscard]] bool IsA(const Entity* entity)
|
||||
static inline bool8 IsEntityA(const Entity* entity, const Class* kind)
|
||||
{
|
||||
Assert(entity != nullptr);
|
||||
return entity->derived_kind == EntityType::kind;
|
||||
Assert(entity != NULL);
|
||||
return entity->derived_kind == kind;
|
||||
}
|
||||
|
||||
template <typename EntityType>
|
||||
requires EntityConcept<EntityType>
|
||||
[[nodiscard]] EntityType* MakeEntity(EntityManager& manager, float x, float y, float z)
|
||||
{
|
||||
Entity* base_ptr = allocate_entity(manager, EntityType::kind);
|
||||
Assert(base_ptr);
|
||||
#define IsEntityOfType(entity_ptr, EntityType) IsEntityA((entity_ptr), ClassKind(EntityType))
|
||||
|
||||
base_ptr->ID = EntityManager::ID++;
|
||||
static inline void* make_entity_by_class(EntityManager* manager, const Class* kind, float x, float y, float z)
|
||||
{
|
||||
Assert(manager != NULL);
|
||||
Assert(kind != NULL);
|
||||
|
||||
Entity* base_ptr = allocate_entity(manager, kind);
|
||||
Assert(base_ptr != NULL);
|
||||
|
||||
base_ptr->ID = g_entity_manager_id++;
|
||||
|
||||
base_ptr->position.x = x;
|
||||
base_ptr->position.y = y;
|
||||
base_ptr->position.z = z;
|
||||
base_ptr->position.w = 1.0f;
|
||||
|
||||
return (EntityType*)base_ptr->derived;
|
||||
return base_ptr->derived;
|
||||
}
|
||||
|
||||
template <typename EntityType>
|
||||
requires EntityConcept<EntityType>
|
||||
[[nodiscard]] EntityType* DownCast(Entity* entity)
|
||||
#define MakeEntity(EntityType, manager_ptr, x, y, z) \
|
||||
((EntityType*)make_entity_by_class((manager_ptr), ClassKind(EntityType), (x), (y), (z)))
|
||||
|
||||
static inline void* down_cast_entity(Entity* entity, const Class* kind)
|
||||
{
|
||||
Assert(entity != nullptr);
|
||||
Assert(IsA<EntityType>(entity));
|
||||
return static_cast<EntityType*>(entity->derived);
|
||||
Assert(entity != NULL);
|
||||
Assert(IsEntityA(entity, kind));
|
||||
return entity->derived;
|
||||
}
|
||||
|
||||
void serialize(Archive& ar, NonNullPtr<Entity> entity);
|
||||
#define DownCastEntity(EntityType, entity_ptr) ((EntityType*)down_cast_entity((entity_ptr), ClassKind(EntityType)))
|
||||
|
||||
JULIET_API uint8 get_local_user_id();
|
||||
void serialize_entity(Archive* ar, Entity* entity);
|
||||
|
||||
JULIET_API String format_entity_id(NonNullPtr<Arena> arena, EntityID id);
|
||||
JULIET_API uint8 get_local_user_id(void);
|
||||
|
||||
JULIET_API bool parse_entity_id(String str, EntityID& outId);
|
||||
JULIET_API String format_entity_id(Arena* arena, EntityID id);
|
||||
|
||||
[[nodiscard]] const Class* find_class_by_name(String name);
|
||||
JULIET_API bool8 parse_entity_id(String str, EntityID* outId);
|
||||
|
||||
[[nodiscard]] const Class* resolve_entity_class(uint8 kind, uint32 crc);
|
||||
const Class* find_class_by_name(String name);
|
||||
|
||||
const Class* resolve_entity_class(uint8 kind, uint32 crc);
|
||||
@@ -0,0 +1,190 @@
|
||||
#include <Entity/EntityManager.h>
|
||||
|
||||
#include <Core/Common/serialization.h>
|
||||
#include <Core/Memory/Utils.h>
|
||||
#include <Data/World.h>
|
||||
#include <Engine/user.h>
|
||||
#include <Entity/Entity.h>
|
||||
#include <Entity/entity_types.h>
|
||||
#include <game.h>
|
||||
#include <Graphics/MeshRenderer.h>
|
||||
|
||||
EntityID g_entity_manager_id = 0;
|
||||
|
||||
void InitEntityManager(World* world)
|
||||
{
|
||||
Assert(world != NULL);
|
||||
|
||||
EntityManager* newManager = ArenaPushStruct(world->WorldArena, EntityManager);
|
||||
newManager->next_local_counter = 1ULL;
|
||||
world->EntityManager = newManager;
|
||||
|
||||
VectorArenaCreate(&newManager->Entities, Entity, world->WorldArena, 100000 JULIET_DEBUG_PARAM("Entities"));
|
||||
|
||||
ArenaParams by_type_params = { .ReserveSize = Kilobytes(1),
|
||||
.CommitSize = Kilobytes(1),
|
||||
.Name = "" JULIET_DEBUG_ONLY(, .DoNotReserveMore = true) };
|
||||
for (uint8 i = 0; i < ENTITY(Count); ++i)
|
||||
{
|
||||
by_type_params.Name = kEntity_type_names[i];
|
||||
newManager->by_type[i].arena = ArenaAllocate(by_type_params);
|
||||
newManager->by_type[i].array = NULL;
|
||||
newManager->by_type[i].count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ShutdownEntityManager(void)
|
||||
{
|
||||
EntityManager* manager = GetEntityManager();
|
||||
for (uint8 i = 0; i < ENTITY(Count); ++i)
|
||||
{
|
||||
ArenaRelease(manager->by_type[i].arena);
|
||||
}
|
||||
|
||||
vector_arena_destroy(&manager->Entities);
|
||||
}
|
||||
|
||||
EntityManager* GetEntityManager(void)
|
||||
{
|
||||
EntityManager* entityManager = GetGameState()->World->EntityManager;
|
||||
Assert(entityManager != NULL);
|
||||
return entityManager;
|
||||
}
|
||||
|
||||
EntityID generate_next_entity_id(EntityManager* manager)
|
||||
{
|
||||
Assert(manager != NULL);
|
||||
|
||||
UserID user = get_local_user_id();
|
||||
Assert(user != kInvalid_user_id);
|
||||
Assert(manager->next_local_counter != kEntityID_user_id_mask);
|
||||
|
||||
EntityID new_id = make_entity_id(user, manager->next_local_counter);
|
||||
manager->next_local_counter += 1ULL;
|
||||
return new_id;
|
||||
}
|
||||
|
||||
EntityTemplate* RegisterEntity(EntityManager* manager, Entity* base, DerivedType entity)
|
||||
{
|
||||
Assert(manager != NULL);
|
||||
Assert(base != NULL);
|
||||
|
||||
base->ID = g_entity_manager_id++;
|
||||
base->derived = entity;
|
||||
|
||||
VectorArenaPushPtr(Entity, &manager->Entities, base);
|
||||
|
||||
EntityTemplate* ptr = (EntityTemplate*)ArenaPushSize(
|
||||
manager->by_type[base->derived_kind->kind].arena, base->derived_kind->size_of, base->derived_kind->alignment,
|
||||
false JULIET_DEBUG_PARAM(kEntity_type_names[base->derived_kind->kind]));
|
||||
MemCopy(ptr, entity, base->derived_kind->size_of);
|
||||
manager->by_type[base->derived_kind->kind].count += 1;
|
||||
|
||||
ptr->base = VectorArenaBack(Entity, &manager->Entities);
|
||||
|
||||
if (manager->by_type[base->derived_kind->kind].array == NULL)
|
||||
{
|
||||
manager->by_type[base->derived_kind->kind].array = ptr;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
Entity* allocate_entity(EntityManager* manager, const Class* derived_type_class)
|
||||
{
|
||||
Assert(manager != NULL);
|
||||
Assert(derived_type_class != NULL);
|
||||
Assert(derived_type_class->kind < ENTITY(Count));
|
||||
Assert(derived_type_class->size_of >= sizeof(EntityTemplate));
|
||||
Assert(derived_type_class->alignment > 0);
|
||||
Assert(derived_type_class->initialize_fct != NULL);
|
||||
|
||||
Entity base_template = { 0 };
|
||||
base_template.derived_kind = derived_type_class;
|
||||
base_template.is_dirty = true;
|
||||
|
||||
VectorArenaPushPtr(Entity, &manager->Entities, &base_template);
|
||||
Entity* base_ptr = VectorArenaBack(Entity, &manager->Entities);
|
||||
Assert(base_ptr != NULL);
|
||||
|
||||
typed_entity_array* typed_array = &manager->by_type[derived_type_class->kind];
|
||||
Assert(typed_array->arena != NULL);
|
||||
|
||||
void* derived = ArenaPushSize(typed_array->arena, derived_type_class->size_of, derived_type_class->alignment,
|
||||
false JULIET_DEBUG_PARAM(kEntity_type_names[derived_type_class->kind]));
|
||||
Assert(derived != NULL);
|
||||
derived_type_class->initialize_fct(derived);
|
||||
|
||||
EntityTemplate* derived_template = (EntityTemplate*)derived;
|
||||
|
||||
base_ptr->derived = derived;
|
||||
derived_template->base = base_ptr;
|
||||
|
||||
if (typed_array->array == NULL)
|
||||
{
|
||||
typed_array->array = derived_template;
|
||||
}
|
||||
typed_array->count += 1;
|
||||
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
void UpdateEntityManager(EntityManager* manager)
|
||||
{
|
||||
Assert(manager != NULL);
|
||||
|
||||
// Todo : inert by definition dont move, but this is for test
|
||||
typed_entity_array* by_type = &manager->by_type[ENTITY(Inert)];
|
||||
for (index_t i = 0; i < by_type->count; ++i)
|
||||
{
|
||||
Inert* inert = ((Inert*)by_type->array) + i;
|
||||
if (inert->MeshInstance != indexMax)
|
||||
{
|
||||
Matrix transform =
|
||||
MatrixTranslation(inert->base->position.x, inert->base->position.y, inert->base->position.z);
|
||||
SetMeshInstanceTransform(inert->MeshInstance, &transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Entity* deserialize_entity(Archive* ar, EntityManager* manager)
|
||||
{
|
||||
Assert(ar != NULL);
|
||||
Assert(manager != NULL);
|
||||
Assert(ar->loading);
|
||||
|
||||
String class_name = { 0 };
|
||||
SERIALIZE_STR(ar, Class, &class_name);
|
||||
|
||||
const Class* class_ptr = find_class_by_name(class_name);
|
||||
Assert(class_ptr != NULL);
|
||||
|
||||
Entity* entity_base = allocate_entity(manager, class_ptr);
|
||||
Assert(entity_base != NULL);
|
||||
|
||||
serialize_entity(ar, entity_base);
|
||||
|
||||
if (entity_base->ID >= g_entity_manager_id)
|
||||
{
|
||||
g_entity_manager_id = entity_base->ID + 1;
|
||||
}
|
||||
|
||||
entity_base->is_dirty = false;
|
||||
|
||||
return entity_base;
|
||||
}
|
||||
|
||||
void update_local_counter(EntityManager* manager, EntityID entity_id)
|
||||
{
|
||||
Assert(manager != NULL);
|
||||
|
||||
uint8 user_id = get_local_user_id();
|
||||
if (get_user_id(entity_id) == user_id)
|
||||
{
|
||||
uint64 counter = get_local_counter(entity_id);
|
||||
if (counter >= manager->next_local_counter)
|
||||
{
|
||||
manager->next_local_counter = counter + 1ULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
#include <Entity/EntityManager.h>
|
||||
|
||||
#include <Core/Common/EnumUtils.h>
|
||||
#include <Core/Common/serialization.h>
|
||||
#include <Data/World.h>
|
||||
#include <Entity/Entity.h>
|
||||
#include <Entity/entity_types.h>
|
||||
#include <game.h>
|
||||
#include <Graphics/MeshRenderer.h>
|
||||
#include "Engine/user.h"
|
||||
|
||||
EntityID EntityManager::ID = 0;
|
||||
|
||||
void InitEntityManager(NonNullPtr<World> world)
|
||||
{
|
||||
EntityManager* newManager = ArenaPushStruct<EntityManager>(world->WorldArena);
|
||||
world->EntityManager = newManager;
|
||||
|
||||
newManager->Entities.Create(world->WorldArena JULIET_DEBUG_PARAM("Entities"));
|
||||
|
||||
ArenaParams by_type_params{ .ReserveSize = Kilobytes(1),
|
||||
.CommitSize = Kilobytes(1),
|
||||
.Name = "" JULIET_DEBUG_ONLY(, .CanReserveMore = false) };
|
||||
for (uint8 i = 0; i < ENTITY(Count); ++i)
|
||||
{
|
||||
by_type_params.Name = kEntity_type_names[i];
|
||||
newManager->by_type[i].arena = ArenaAllocate(by_type_params);
|
||||
newManager->by_type[i].array = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ShutdownEntityManager()
|
||||
{
|
||||
auto& manager = GetEntityManager();
|
||||
for (typed_entity_array& type : manager.by_type)
|
||||
{
|
||||
ArenaRelease(type.arena);
|
||||
}
|
||||
|
||||
manager.Entities.Destroy();
|
||||
}
|
||||
|
||||
EntityManager& GetEntityManager()
|
||||
{
|
||||
NonNullPtr entityManager = GetGameState()->World->EntityManager;
|
||||
return *entityManager;
|
||||
}
|
||||
|
||||
EntityID generate_next_entity_id(EntityManager& manager)
|
||||
{
|
||||
UserID user = get_local_user_id();
|
||||
Assert(user != kInvalid_user_id);
|
||||
Assert(manager.next_local_counter != kEntityID_user_id_mask);
|
||||
|
||||
EntityID new_id = make_entity_id(user, manager.next_local_counter);
|
||||
manager.next_local_counter += 1ULL;
|
||||
return new_id;
|
||||
}
|
||||
|
||||
EntityTemplate* RegisterEntity(EntityManager& manager, Entity* base, DerivedType entity)
|
||||
{
|
||||
base->ID = EntityManager::ID++;
|
||||
base->derived = entity;
|
||||
|
||||
manager.Entities.PushBack(*base);
|
||||
|
||||
auto* ptr = (EntityTemplate*)ArenaPushSize(manager.by_type[base->derived_kind->kind].arena,
|
||||
base->derived_kind->size_of, base->derived_kind->alignment,
|
||||
false JULIET_DEBUG_PARAM(kEntity_type_names[base->derived_kind->kind]));
|
||||
MemCopy(ptr, entity, base->derived_kind->size_of);
|
||||
manager.by_type[base->derived_kind->kind].count += 1;
|
||||
|
||||
ptr->base = manager.Entities.Back();
|
||||
|
||||
if (manager.by_type[base->derived_kind->kind].array == nullptr)
|
||||
{
|
||||
manager.by_type[base->derived_kind->kind].array = ptr;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
Entity* allocate_entity(EntityManager& manager, NonNullPtr<const Class> derived_type_class)
|
||||
{
|
||||
Assert(derived_type_class->kind < ENTITY(Count));
|
||||
Assert(derived_type_class->size_of >= sizeof(EntityTemplate));
|
||||
Assert(derived_type_class->alignment > 0);
|
||||
Assert(derived_type_class->initialize_fct);
|
||||
|
||||
Entity base_template = {};
|
||||
base_template.derived_kind = derived_type_class;
|
||||
base_template.is_dirty = true;
|
||||
|
||||
manager.Entities.PushBack(base_template);
|
||||
Entity* base_ptr = manager.Entities.Back();
|
||||
Assert(base_ptr);
|
||||
|
||||
typed_entity_array& typed_array = manager.by_type[derived_type_class->kind];
|
||||
Assert(typed_array.arena);
|
||||
|
||||
void* derived = ArenaPushSize(typed_array.arena, derived_type_class->size_of, derived_type_class->alignment,
|
||||
false JULIET_DEBUG_PARAM(kEntity_type_names[derived_type_class->kind]));
|
||||
Assert(derived);
|
||||
derived_type_class->initialize_fct(derived);
|
||||
|
||||
auto* derived_template = (EntityTemplate*)derived;
|
||||
|
||||
base_ptr->derived = derived;
|
||||
derived_template->base = base_ptr;
|
||||
|
||||
if (typed_array.array == nullptr)
|
||||
{
|
||||
typed_array.array = derived_template;
|
||||
}
|
||||
typed_array.count += 1;
|
||||
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
void UpdateEntityManager(EntityManager& manager)
|
||||
{
|
||||
// Todo : inert by definition dont move, but this is for test
|
||||
auto& by_type = manager.by_type[ENTITY(Inert)];
|
||||
for (index_t i = 0; i < by_type.count; ++i)
|
||||
{
|
||||
Inert* inert = reinterpret_cast<Inert*>(by_type.array) + i;
|
||||
if (inert->MeshInstance != indexMax)
|
||||
{
|
||||
SetMeshInstanceTransform(inert->MeshInstance,
|
||||
MatrixTranslation(inert->base->position.x, inert->base->position.y,
|
||||
inert->base->position.z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Entity* deserialize_entity(Archive& ar, EntityManager& manager)
|
||||
{
|
||||
Assert(ar.loading);
|
||||
|
||||
String class_name;
|
||||
SERIALIZE(ar, Class, class_name);
|
||||
|
||||
NonNullPtr<const Class> class_ptr = find_class_by_name(class_name);
|
||||
|
||||
NonNullPtr<Entity> entity_base = allocate_entity(manager, class_ptr);
|
||||
|
||||
serialize(ar, entity_base);
|
||||
|
||||
if (entity_base->ID >= EntityManager::ID)
|
||||
{
|
||||
EntityManager::ID = entity_base->ID + 1;
|
||||
}
|
||||
|
||||
entity_base->is_dirty = false;
|
||||
|
||||
return entity_base;
|
||||
}
|
||||
|
||||
void update_local_counter(EntityManager& manager, EntityID entity_id)
|
||||
{
|
||||
uint8 user_id = get_local_user_id();
|
||||
if (get_user_id(entity_id) == user_id)
|
||||
{
|
||||
uint64 counter = get_local_counter(entity_id);
|
||||
if (counter >= manager.next_local_counter)
|
||||
{
|
||||
manager.next_local_counter = counter + 1ULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
-16
@@ -3,11 +3,13 @@
|
||||
#include <Core/Container/Vector.h>
|
||||
#include <Entity/entity_common.h>
|
||||
|
||||
struct World;
|
||||
struct EntityTemplate;
|
||||
struct Entity;
|
||||
struct Class;
|
||||
typedef struct World World;
|
||||
typedef struct EntityTemplate EntityTemplate;
|
||||
typedef struct Entity Entity;
|
||||
typedef struct Class Class;
|
||||
typedef struct Archive Archive;
|
||||
|
||||
typedef struct typed_entity_array typed_entity_array;
|
||||
struct typed_entity_array
|
||||
{
|
||||
Arena* arena;
|
||||
@@ -15,22 +17,24 @@ struct typed_entity_array
|
||||
size_t count;
|
||||
};
|
||||
|
||||
typedef struct EntityManager EntityManager;
|
||||
struct EntityManager
|
||||
{
|
||||
static EntityID ID;
|
||||
uint64 next_local_counter = 1ULL;
|
||||
uint64 next_local_counter;
|
||||
|
||||
// TODO: Should be a pool
|
||||
VectorArena<Entity, 100'000> Entities;
|
||||
VectorArena Entities;
|
||||
|
||||
typed_entity_array by_type[ENTITY(Count)];
|
||||
typed_entity_array by_type[Entity_Type_Count];
|
||||
};
|
||||
|
||||
void InitEntityManager(NonNullPtr<World> world);
|
||||
void ShutdownEntityManager();
|
||||
EntityManager& GetEntityManager();
|
||||
EntityTemplate* RegisterEntity(EntityManager& manager, Entity* base, DerivedType entity);
|
||||
[[nodiscard]] Entity* allocate_entity(EntityManager& manager, NonNullPtr<const Class> derived_type_class);
|
||||
void UpdateEntityManager(EntityManager& manager);
|
||||
[[nodiscard]] Entity* deserialize_entity(Archive& archive, EntityManager& manager);
|
||||
void update_local_counter(EntityManager& manager, EntityID entity_id);
|
||||
extern EntityID g_entity_manager_id;
|
||||
|
||||
void InitEntityManager(World* world);
|
||||
void ShutdownEntityManager(void);
|
||||
EntityManager* GetEntityManager(void);
|
||||
EntityTemplate* RegisterEntity(EntityManager* manager, Entity* base, DerivedType entity);
|
||||
Entity* allocate_entity(EntityManager* manager, const Class* derived_type_class);
|
||||
void UpdateEntityManager(EntityManager* manager);
|
||||
Entity* deserialize_entity(Archive* archive, EntityManager* manager);
|
||||
void update_local_counter(EntityManager* manager, EntityID entity_id);
|
||||
@@ -5,17 +5,16 @@
|
||||
|
||||
// clang-format off
|
||||
#define AS_STR(name) #name
|
||||
const char* kEntity_type_names[] = {
|
||||
const char* kEntity_type_names[] = {
|
||||
ENTITY_TYPE_LIST(AS_STR)
|
||||
"Count"
|
||||
};
|
||||
#undef AS_STR
|
||||
|
||||
#define AS_CLASS(name) name::kind
|
||||
const Class* kEntity_type_class_ptr[]
|
||||
{
|
||||
#define AS_CLASS(name) &class_kind_##name
|
||||
const Class* kEntity_type_class_ptr[] = {
|
||||
ENTITY_TYPE_LIST(AS_CLASS)
|
||||
nullptr
|
||||
NULL
|
||||
};
|
||||
#undef AS_CLASS
|
||||
// clang-format on
|
||||
+26
-24
@@ -1,46 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Common/EnumUtils.h>
|
||||
#include <Engine/Class.h>
|
||||
|
||||
struct Class;
|
||||
using DerivedType = void*;
|
||||
using EntityID = uint64_t;
|
||||
typedef void* DerivedType;
|
||||
typedef uint64 EntityID;
|
||||
|
||||
constexpr uint8 kInvalid_user_id = 0U;
|
||||
constexpr EntityID kInvalid_entity_id = 0ULL;
|
||||
|
||||
constexpr EntityID kEntityID_user_id_shift = 56ULL;
|
||||
constexpr EntityID kEntityID_user_id_mask = 0xFF00'0000'0000'0000ULL;
|
||||
#define kInvalid_user_id ((uint8)0U)
|
||||
#define kInvalid_entity_id ((EntityID)0ULL)
|
||||
#define kEntityID_user_id_shift ((EntityID)56ULL)
|
||||
#define kEntityID_user_id_mask ((EntityID)0xFF00000000000000ULL)
|
||||
|
||||
// clang-format off
|
||||
#define ENTITY_TYPE_LIST(X) X(Inert),
|
||||
|
||||
#define AS_ENUM(name) name
|
||||
enum class Entity_Type : uint8
|
||||
typedef uint8 Entity_Type;
|
||||
#define AS_ENUM(name) Entity_Type_##name
|
||||
enum
|
||||
{
|
||||
ENTITY_TYPE_LIST(AS_ENUM)
|
||||
Count
|
||||
Entity_Type_Count
|
||||
};
|
||||
#undef AS_ENUM
|
||||
|
||||
extern const char* kEntity_type_names[];
|
||||
extern const char* kEntity_type_names[];
|
||||
extern const Class* kEntity_type_class_ptr[];
|
||||
|
||||
#define ENTITY(kind) ToUnderlying(Entity_Type::kind)
|
||||
#define ENTITY(kind) ((uint8)Entity_Type_##kind)
|
||||
// clang-format on
|
||||
|
||||
struct Entity;
|
||||
typedef struct Entity Entity;
|
||||
|
||||
#define DECLARE_ENTITY() \
|
||||
Entity* base; \
|
||||
DECLARE_CLASS()
|
||||
#define DECLARE_ENTITY() Entity* base;
|
||||
|
||||
#define DEFINE_ENTITY_VERSIONED(entity, version) \
|
||||
constexpr Class entityKind##entity = \
|
||||
MakeClass(ConstString(#entity), (uint8)Entity_Type::entity, (version), &class_kind_Entity, sizeof(entity), \
|
||||
alignof(entity), (&initialize_thunk<entity>), (&serialize_thunk<entity>)); \
|
||||
Class* entity::kind = const_cast<Class*>(&entityKind##entity);
|
||||
#define DEFINE_ENTITY_VERSIONED(entity, version_num) \
|
||||
const Class class_kind_##entity = { \
|
||||
.Name = ConstString(#entity), \
|
||||
.kind = (uint8)Entity_Type_##entity, \
|
||||
.version = (version_num), \
|
||||
.base_class = &class_kind_Entity, \
|
||||
.initialize_fct = init_##entity, \
|
||||
.serialize_fct = serialize_##entity, \
|
||||
.size_of = sizeof(entity), \
|
||||
.alignment = AlignOf(entity) \
|
||||
};
|
||||
|
||||
// Note: Needed by every classes see define above
|
||||
// Note: Needed by every entity class (see define above)
|
||||
extern const Class class_kind_Entity;
|
||||
@@ -0,0 +1,22 @@
|
||||
#include <Entity/entity_types.h>
|
||||
|
||||
#include <Core/Common/serialization.h>
|
||||
|
||||
internal void init_Inert(void* payload)
|
||||
{
|
||||
Assert(payload != NULL);
|
||||
Inert* inert = (Inert*)payload;
|
||||
inert->base = NULL;
|
||||
inert->MeshInstance = indexMax;
|
||||
}
|
||||
|
||||
internal void serialize_Inert(Archive* ar, uint16 version, void* payload)
|
||||
{
|
||||
(void)version;
|
||||
Assert(ar != NULL);
|
||||
Assert(payload != NULL);
|
||||
Inert* inert = (Inert*)payload;
|
||||
SERIALIZE_U64(ar, MeshInstance, &inert->MeshInstance);
|
||||
}
|
||||
|
||||
DEFINE_ENTITY_VERSIONED(Inert, 1)
|
||||
@@ -1,9 +0,0 @@
|
||||
#include <Entity/entity_types.h>
|
||||
|
||||
#include <Core/Common/serialization.h>
|
||||
|
||||
DEFINE_ENTITY_VERSIONED(Inert, 1)
|
||||
internal void serialize(Archive& ar, uint16 /*version*/, Inert& inert)
|
||||
{
|
||||
SERIALIZE(ar, MeshInstance, inert.MeshInstance);
|
||||
}
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
#include <Entity/entity_common.h>
|
||||
|
||||
typedef struct Inert Inert;
|
||||
struct Inert
|
||||
{
|
||||
DECLARE_ENTITY()
|
||||
|
||||
index_t MeshInstance = indexMax;
|
||||
index_t MeshInstance;
|
||||
};
|
||||
DECLARE_CLASS(Inert)
|
||||
Reference in new issue
Block a user