updating serialization tdd with latest changes

This commit is contained in:
2026-09-07 20:05:17 -04:00
parent b1de6ccc49
commit 3123d2f2e6
4 changed files with 454 additions and 1378 deletions
@@ -206,13 +206,13 @@ When `GetOrLoadTemplate` is invoked with a relative path:
6. **Default Base Setup**: Initialize a local `Entity defaultBase`:
```cpp
Entity defaultBase = {};
defaultBase.Kind = entityClass;
defaultBase.Derived = archetypeMem;
defaultBase.derived_kind = entityClass;
defaultBase.derived = archetypeMem;
```
7. **Back-Pointer Linking**: Set `entity_template::Base` in the archetype memory:
7. **Back-Pointer Linking**: Set `entity_template::base` in the archetype memory:
```cpp
auto* archetypeTemplate = reinterpret_cast<entity_template*>(archetypeMem);
archetypeTemplate->Base = &cachedEntry->DefaultBase;
archetypeTemplate->base = &cachedEntry->DefaultBase;
```
8. **KV Property Parsing**: Parse all key-value pairs in the template `.jasset` file and write their deserialized values directly into `archetypeMem` and `defaultBase`.
9. **Cache Insertion**: Store the fully baked `CachedTemplate` record in `cache->Templates`.
@@ -228,21 +228,22 @@ In Juliet, an entity is split into two tightly coupled structures:
```cpp
struct Entity final
{
EntityID ID = 0;
Class* Kind = nullptr;
DerivedType Derived = nullptr; // Points to the specialized struct
float X = 0.0f;
float Y = 0.0f;
float Z = 0.0f;
DECLARE_CLASS()
EntityID ID = 0;
Class* derived_kind = nullptr;
DerivedType derived = nullptr; // Points to the specialized struct
Vector4 position = {};
bool is_dirty = false;
};
```
2. **`Derived` (Specialized Type)**: e.g., `Inert`, `Collectible`, `Player`. The first member is always `DECLARE_ENTITY()`, which expands to:
```cpp
Entity* Base; // Back-pointer to the base Entity
static Class* Kind;
Entity* base; // Back-pointer to the base Entity
DECLARE_CLASS() // static Class* kind;
```
Because `DerivedType` stores a back-pointer (`Base`) to `Entity`, **a shallow memory copy of an archetype invalidates this pointer**! The loading pipeline must explicitly restore this invariant.
Because `DerivedType` stores a back-pointer (`base`) to `Entity`, **a shallow memory copy of an archetype invalidates this pointer**! The loading pipeline must explicitly restore this invariant.
### 4.2 The 5-Step Instantiation Pipeline
When an entity instance is spawned or deserialized from a `.jasset` file, the engine executes this strict 5-step sequence:
@@ -400,12 +401,12 @@ void ApplyKvDeltaOverrides(Entity* base, void* derived, Class* cls, String kvCon
}
// Check base properties first
if (StringCompare(pair.Key, ConstString("Position")) == 0)
if (StringCompare(pair.Key, ConstString("Position")) == 0 || StringCompare(pair.Key, ConstString("position")) == 0)
{
Vector3 pos = ParseVector3(pair.Value);
base->X = pos.X;
base->Y = pos.Y;
base->Z = pos.Z;
base->position.x = pos.x;
base->position.y = pos.y;
base->position.z = pos.z;
continue;
}
@@ -483,8 +484,8 @@ bool CreateTemplateFromEntity(World& world,
Assert(entityIndex < manager.Entities.Size());
Entity* sourceEntity = &manager.Entities[entityIndex];
Class* entityKind = sourceEntity->Kind;
void* derivedMem = sourceEntity->Derived;
Class* entityKind = sourceEntity->derived_kind;
void* derivedMem = sourceEntity->derived;
// Format destination template path
String templatePath = Format(scratchArena, "Assets/Templates/{}.jasset", CStr(templateName));
@@ -561,11 +562,11 @@ void RenderEntityPropertyInspector(Entity* entity, CachedTemplate* archetype)
}
// Iterate through properties
Class* cls = entity->Kind;
Class* cls = entity->derived_kind;
for (size_t i = 0; i < cls->PropertyCount; ++i)
{
const PropertyDescriptor& prop = cls->Properties[i];
void* instanceField = static_cast<uint8*>(entity->Derived) + prop.Offset;
void* instanceField = static_cast<uint8*>(entity->derived) + prop.Offset;
void* templateField = isTemplated ? (static_cast<uint8*>(archetype->DefaultDerivedMemory) + prop.Offset) : nullptr;
const bool isOverridden = isTemplated && (MemCompare(instanceField, templateField, GetPropertySize(prop.Type)) != 0);
@@ -605,10 +606,10 @@ Reverting an entire entity to its template archetype restores all properties whi
```cpp
void RevertEntityToTemplate(NonNullPtr<Entity> instance, NonNullPtr<const CachedTemplate> archetype)
{
Assert(instance->Kind == archetype->EntityKind);
Assert(instance->derived_kind == archetype->EntityKind);
Assert(archetype->DefaultDerivedMemory != nullptr);
void* derivedMem = instance->Derived;
void* derivedMem = instance->derived;
const size_t derivedSize = archetype->EntityKind->size_of;
// Preserve the current Base pointer
@@ -619,16 +620,16 @@ void RevertEntityToTemplate(NonNullPtr<Entity> instance, NonNullPtr<const Cached
// 2. Re-establish the Base back-pointer
auto* templateDerived = reinterpret_cast<entity_template*>(derivedMem);
templateDerived->Base = basePtr;
templateDerived->base = basePtr;
// 3. Mark visual / physics state as updated
if (instance->Kind->kind == ENTITY(Inert))
if (instance->derived_kind->kind == ENTITY(Inert))
{
auto* inert = reinterpret_cast<Inert*>(derivedMem);
if (inert->MeshInstance != indexMax)
{
SetMeshInstanceTransform(inert->MeshInstance,
MatrixTranslation(basePtr->X, basePtr->Y, basePtr->Z));
MatrixTranslation(basePtr->position.x, basePtr->position.y, basePtr->position.z));
}
}
}
@@ -844,17 +845,17 @@ namespace UnitTest
Assert(instance != nullptr);
// Verify Step 1 & 2: Base spatial delta applied, non-overridden derived property retained
Assert(instance->X == 100.0f);
Assert(instance->Y == 200.0f);
Assert(instance->Z == 300.0f);
Assert(instance->position.x == 100.0f);
Assert(instance->position.y == 200.0f);
Assert(instance->position.z == 300.0f);
auto* inertDerived = DownCast<Inert>(instance);
Assert(inertDerived != nullptr);
Assert(inertDerived->MeshInstance == 42); // Retained from template!
// Verify Step 3: CRITICAL back-pointer fixup check
Assert(inertDerived->Base == instance);
Assert(instance->Derived == inertDerived);
Assert(inertDerived->base == instance);
Assert(instance->derived == inertDerived);
ShutdownEntityManager();
ShutdownWorld(&world);
@@ -900,12 +901,12 @@ namespace UnitTest
Assert(inertDerived->MeshInstance == 100);
// Verify world position is preserved across revert
Assert(instance->X == 5.0f);
Assert(instance->Y == 5.0f);
Assert(instance->Z == 5.0f);
Assert(instance->position.x == 5.0f);
Assert(instance->position.y == 5.0f);
Assert(instance->position.z == 5.0f);
// Verify back-pointer invariant preserved after revert
Assert(inertDerived->Base == instance);
Assert(inertDerived->base == instance);
ShutdownEntityManager();
ShutdownWorld(&world);