From 7c4b8c307fc3cc908178be04f9012d541ab4448d Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Tue, 26 May 2026 20:24:34 -0500 Subject: [PATCH] Fix flocking bug --- cmake/targets/linux.cmake | 3 +++ src/dusk/assert/assert.c | 23 ++++++++++++++++++- src/dusk/entity/component.c | 18 +++++++++++++-- src/dusk/entity/component.h | 20 ++++++++++++---- .../overworld/entityoverworldcamera.c | 3 ++- .../overworld/entityoverworldcamera.h | 7 ++++-- src/dusk/entity/componentlist.h | 19 +++++++-------- src/dusk/scene/overworld/overworldground.c | 1 + src/dusk/scene/overworld/overworldscene.c | 5 ---- src/dusk/scene/scene.c | 2 ++ 10 files changed, 76 insertions(+), 25 deletions(-) diff --git a/cmake/targets/linux.cmake b/cmake/targets/linux.cmake index 7c02bdae..51038f1b 100644 --- a/cmake/targets/linux.cmake +++ b/cmake/targets/linux.cmake @@ -16,6 +16,9 @@ else() ) endif() +# Export symbols so backtrace_symbols() can resolve function names. +target_link_options(${DUSK_LIBRARY_TARGET_NAME} PUBLIC -rdynamic) + # Link required libraries. target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC SDL2 diff --git a/src/dusk/assert/assert.c b/src/dusk/assert/assert.c index 73973d37..f8f4b4dd 100644 --- a/src/dusk/assert/assert.c +++ b/src/dusk/assert/assert.c @@ -9,6 +9,24 @@ #include "log/log.h" #include "util/string.h" +#ifdef DUSK_LINUX + #include + #include + + static void assertLogBacktrace(void) { + void *frames[64]; + int count = backtrace(frames, 64); + char **symbols = backtrace_symbols(frames, count); + logError("Stack trace:\n"); + if(symbols) { + for(int i = 0; i < count; i++) { + logError(" %s\n", symbols[i]); + } + free(symbols); + } + } +#endif + #ifndef DUSK_ASSERTIONS_FAKED #ifdef DUSK_TEST_ASSERT void assertTrueImpl( @@ -33,11 +51,14 @@ ) { if(x != true) { logError( - "Assertion Failed in %s:%i\n\n%s\n", + "Assertion Failed in %s:%i\n\n%s\n\n", file, line, message ); + #ifdef DUSK_LINUX + assertLogBacktrace(); + #endif abort(); } } diff --git a/src/dusk/entity/component.c b/src/dusk/entity/component.c index 272fdb72..532c679f 100644 --- a/src/dusk/entity/component.c +++ b/src/dusk/entity/component.c @@ -12,12 +12,13 @@ componentdefinition_t COMPONENT_DEFINITIONS[] = { [COMPONENT_TYPE_NULL] = { 0 }, - #define X(enm, type, field, iMethod, dMethod) \ + #define X(enm, type, field, iMethod, dMethod, rMethod) \ [COMPONENT_TYPE_##enm] = { \ .enumName = #enm, \ .name = #field, \ .init = iMethod, \ - .dispose = dMethod \ + .dispose = dMethod, \ + .render = rMethod \ }, #include "componentlist.h" @@ -114,6 +115,19 @@ entityid_t componentGetEntitiesWithComponent( return written; } +errorret_t componentRenderAll(void) { + for(entityid_t eid = 0; eid < ENTITY_COUNT_MAX; eid++) { + if(!(ENTITY_MANAGER.entities[eid].state & ENTITY_STATE_ACTIVE)) continue; + for(componentid_t cid = 0; cid < ENTITY_COMPONENT_COUNT_MAX; cid++) { + component_t *cmp = &ENTITY_MANAGER.components[componentGetIndex(eid, cid)]; + if(cmp->type == COMPONENT_TYPE_NULL) continue; + if(!COMPONENT_DEFINITIONS[cmp->type].render) continue; + errorChain(COMPONENT_DEFINITIONS[cmp->type].render(eid, cid)); + } + } + errorOk(); +} + void componentDispose( const entityid_t entityId, const componentid_t componentId diff --git a/src/dusk/entity/component.h b/src/dusk/entity/component.h index 6f86e60d..c723ec02 100644 --- a/src/dusk/entity/component.h +++ b/src/dusk/entity/component.h @@ -8,13 +8,13 @@ #pragma once #include "entitybase.h" -#define X(enumName, type, field, init, dispose) \ +#define X(enumName, type, field, init, dispose, render) \ // do nothing #include "componentlist.h" #undef X typedef union { - #define X(enumName, type, field, init, dispose) type field; + #define X(enumName, type, field, init, dispose, render) type field; #include "componentlist.h" #undef X } componentdata_t; @@ -24,12 +24,13 @@ typedef struct { const char_t *name; void (*init)(const entityid_t, const componentid_t); void (*dispose)(const entityid_t, const componentid_t); + errorret_t (*render)(const entityid_t, const componentid_t); } componentdefinition_t; typedef enum { COMPONENT_TYPE_NULL, - #define X(enumName, type, field, init, dispose) \ + #define X(enumName, type, field, init, dispose, render) \ COMPONENT_TYPE_##enumName, #include "componentlist.h" #undef X @@ -100,11 +101,20 @@ entityid_t componentGetEntitiesWithComponent( /** * Disposes of a component for the entity with component ID. - * + * * @param entityId The entity ID. * @param componentId The component ID. */ void componentDispose( const entityid_t entityId, const componentid_t componentId -); \ No newline at end of file +); + +/** + * Calls the render callback on every active component that defines one. + * Iterates all active entities and all their component slots. No-op for + * components whose definition has render == NULL. + * + * @return Error state. + */ +errorret_t componentRenderAll(void); \ No newline at end of file diff --git a/src/dusk/entity/component/overworld/entityoverworldcamera.c b/src/dusk/entity/component/overworld/entityoverworldcamera.c index 42222982..20618cd3 100644 --- a/src/dusk/entity/component/overworld/entityoverworldcamera.c +++ b/src/dusk/entity/component/overworld/entityoverworldcamera.c @@ -40,7 +40,7 @@ void entityOverworldCameraSetTarget( cam->targetPosCompId = targetPosCompId; } -void entityOverworldCameraUpdate( +errorret_t entityOverworldCameraRender( const entityid_t entityId, const componentid_t componentId ) { @@ -62,4 +62,5 @@ void entityOverworldCameraUpdate( entityCameraLookAtPixelPerfect( entityId, posComp, camComp, center, cam->eyeOffset, cam->scale ); + errorOk(); } diff --git a/src/dusk/entity/component/overworld/entityoverworldcamera.h b/src/dusk/entity/component/overworld/entityoverworldcamera.h index cdc8c2b9..192d2a47 100644 --- a/src/dusk/entity/component/overworld/entityoverworldcamera.h +++ b/src/dusk/entity/component/overworld/entityoverworldcamera.h @@ -7,6 +7,7 @@ #pragma once #include "entity/entitybase.h" +#include "error/error.h" typedef struct { entityid_t targetEntityId; @@ -55,12 +56,14 @@ void entityOverworldCameraSetTarget( ); /** - * Updates the camera position to track the target entity. + * Render callback: updates the camera position to track the target entity. + * Called automatically each frame via componentRenderAll. * * @param entityId The owning entity. * @param componentId This component's ID. + * @return Error state. */ -void entityOverworldCameraUpdate( +errorret_t entityOverworldCameraRender( const entityid_t entityId, const componentid_t componentId ); diff --git a/src/dusk/entity/componentlist.h b/src/dusk/entity/componentlist.h index b6d66e29..80075a5b 100644 --- a/src/dusk/entity/componentlist.h +++ b/src/dusk/entity/componentlist.h @@ -20,13 +20,14 @@ // Field name (lowercase) // Init function (optional) // Dispose function (optional) +// Render function (optional) -X(POSITION, entityposition_t, position, entityPositionInit, NULL) -X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL) -X(RENDERABLE, entityrenderable_t, renderable, entityRenderableInit, entityRenderableDispose) -X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, entityPhysicsDispose) -X(TRIGGER, entitytrigger_t, trigger, entityTriggerInit, NULL) -X(OVERWORLD, entityoverworld_t, overworld, entityOverworldInit, NULL) -X(PLAYER, entityplayer_t, player, entityPlayerInit, NULL) -X(INTERACTABLE, entityinteractable_t, interactable, entityInteractableInit, NULL) -X(OVERWORLD_CAMERA, entityoverworldcamera_t, overworldCamera, entityOverworldCameraInit, NULL) +X(POSITION, entityposition_t, position, entityPositionInit, NULL, NULL) +X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL, NULL) +X(RENDERABLE, entityrenderable_t, renderable, entityRenderableInit, entityRenderableDispose, NULL) +X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, entityPhysicsDispose, NULL) +X(TRIGGER, entitytrigger_t, trigger, entityTriggerInit, NULL, NULL) +X(OVERWORLD, entityoverworld_t, overworld, entityOverworldInit, NULL, NULL) +X(PLAYER, entityplayer_t, player, entityPlayerInit, NULL, NULL) +X(INTERACTABLE, entityinteractable_t, interactable, entityInteractableInit, NULL, NULL) +X(OVERWORLD_CAMERA, entityoverworldcamera_t, overworldCamera, entityOverworldCameraInit, NULL, entityOverworldCameraRender) diff --git a/src/dusk/scene/overworld/overworldground.c b/src/dusk/scene/overworld/overworldground.c index e056771a..67ce17c2 100644 --- a/src/dusk/scene/overworld/overworldground.c +++ b/src/dusk/scene/overworld/overworldground.c @@ -16,6 +16,7 @@ void overworldGroundAdd(overworldground_t *ground) { ground->posCompId = entityAddComponent( ground->entityId, COMPONENT_TYPE_POSITION ); + entityAddComponent(ground->entityId, COMPONENT_TYPE_RENDERABLE); vec3 pos = { -OVERWORLD_GROUND_SIZE, 0.0f, -OVERWORLD_GROUND_SIZE }; vec3 scale = { OVERWORLD_GROUND_SIZE * 2.0f, 1.0f, OVERWORLD_GROUND_SIZE * 2.0f }; entityPositionSetLocalPosition(ground->entityId, ground->posCompId, pos); diff --git a/src/dusk/scene/overworld/overworldscene.c b/src/dusk/scene/overworld/overworldscene.c index 8d1d1ed0..80a27498 100644 --- a/src/dusk/scene/overworld/overworldscene.c +++ b/src/dusk/scene/overworld/overworldscene.c @@ -122,11 +122,6 @@ void overworldSceneInit(void) { errorret_t overworldSceneUpdate(void) { overworldPlayerUpdate(&OVERWORLD.player); - - entityOverworldCameraUpdate( - OVERWORLD.cameraEntityId, OVERWORLD.cameraOverworldCompId - ); - errorOk(); } diff --git a/src/dusk/scene/scene.c b/src/dusk/scene/scene.c index 82c796e6..001cad12 100644 --- a/src/dusk/scene/scene.c +++ b/src/dusk/scene/scene.c @@ -16,6 +16,7 @@ #include "util/string.h" #include "ui/ui.h" #include "scene/scenerenderpipeline.h" +#include "entity/component.h" scenefuncs_t SCENE_FUNCTIONS[SCENE_TYPE_COUNT] = { { 0 }, @@ -71,6 +72,7 @@ errorret_t sceneRender(void) { mat4 proj, view, ident; glm_mat4_identity(ident); + errorChain(componentRenderAll()); errorChain(sceneRenderPipeline(entityCameraGetCurrent())); // UI Rendering