From 9a934f844380573905ff8ebdb4b3deff07166d86 Mon Sep 17 00:00:00 2001 From: Cooliokid956 <68075390+Cooliokid956@users.noreply.github.com> Date: Tue, 21 Oct 2025 12:04:05 -0500 Subject: [PATCH] Static Object Collision / Check for freed CObject (#924) * Static Object Collision * no soc surface pool; bnot * Isaac review --------- Co-authored-by: PeachyPeachSM64 <72323920+PeachyPeachSM64@users.noreply.github.com> --- autogen/convert_structs.py | 1 + autogen/lua_definitions/constants.lua | 3 + autogen/lua_definitions/functions.lua | 21 ++++ autogen/lua_definitions/structs.lua | 4 + docs/lua/constants.md | 1 + docs/lua/functions-7.md | 69 ++++++++++ docs/lua/functions.md | 3 + docs/lua/structs.md | 12 ++ include/surface_terrains.h | 1 + src/engine/surface_collision.c | 10 +- src/engine/surface_collision.h | 6 + src/engine/surface_load.c | 174 +++++++++++++++++++++----- src/engine/surface_load.h | 16 +++ src/game/memory.c | 26 ++++ src/game/memory.h | 1 + src/game/object_list_processor.c | 21 ---- src/game/object_list_processor.h | 5 - src/pc/lua/smlua_cobject.c | 8 ++ src/pc/lua/smlua_cobject_autogen.c | 8 ++ src/pc/lua/smlua_cobject_autogen.h | 1 + src/pc/lua/smlua_constants_autogen.c | 1 + src/pc/lua/smlua_functions_autogen.c | 56 +++++++++ src/pc/lua/smlua_utils.h | 1 + 23 files changed, 388 insertions(+), 61 deletions(-) diff --git a/autogen/convert_structs.py b/autogen/convert_structs.py index 9216d915e..a15eb03da 100644 --- a/autogen/convert_structs.py +++ b/autogen/convert_structs.py @@ -142,6 +142,7 @@ override_field_immutable = { "DialogEntry": [ "unused", "linesPerBox", "leftOffset", "width", "str", "text", "replaced"], "ModFsFile": [ "*" ], "ModFs": [ "*" ], + "StaticObjectCollision": [ "*" ], } override_field_version_excludes = { diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index 601038e72..91e53ffeb 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -10956,6 +10956,9 @@ SURFACE_FLAG_DYNAMIC = (1 << 0) --- @type integer SURFACE_FLAG_NO_CAM_COLLISION = (1 << 1) +--- @type integer +SURFACE_FLAG_INTANGIBLE = (1 << 2) + --- @type integer SURFACE_FLAG_X_PROJECTION = (1 << 3) diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 673c1a31f..7ce58f6e8 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -12295,6 +12295,27 @@ function load_object_collision_model() -- ... end +--- @return StaticObjectCollision +--- Loads the object's collision data into static collision. You may run this only once to capture the object's collision at that frame. +function load_static_object_collision() + -- ... +end + +--- @param col StaticObjectCollision +--- @param tangible boolean +--- Toggles a collection of static object surfaces +function toggle_static_object_collision(col, tangible) + -- ... +end + +--- @param col StaticObjectCollision +--- @param index integer +--- @return Surface +--- Gets a surface corresponding to `index` from the static object collision +function get_static_object_surface(col, index) + -- ... +end + --- @param o Object --- @param index integer --- @return Surface diff --git a/autogen/lua_definitions/structs.lua b/autogen/lua_definitions/structs.lua index 76a1c2a0f..614411477 100644 --- a/autogen/lua_definitions/structs.lua +++ b/autogen/lua_definitions/structs.lua @@ -2337,6 +2337,10 @@ --- @field public dialog5 integer --- @field public dialog6 integer +--- @class StaticObjectCollision +--- @field public index integer +--- @field public length integer + --- @class Surface --- @field public type integer --- @field public flags integer diff --git a/docs/lua/constants.md b/docs/lua/constants.md index 6f7403334..2a9b5aecf 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -4620,6 +4620,7 @@ - SURFACE_CLASS_NOT_SLIPPERY - SURFACE_FLAG_DYNAMIC - SURFACE_FLAG_NO_CAM_COLLISION +- SURFACE_FLAG_INTANGIBLE - SURFACE_FLAG_X_PROJECTION - HAZARD_TYPE_LAVA_FLOOR - HAZARD_TYPE_LAVA_WALL diff --git a/docs/lua/functions-7.md b/docs/lua/functions-7.md index c1c05249a..3c6be9bb4 100644 --- a/docs/lua/functions-7.md +++ b/docs/lua/functions-7.md @@ -32,6 +32,75 @@ Loads the object's collision data into dynamic collision. You must run this ever
+## [load_static_object_collision](#load_static_object_collision) + +### Description +Loads the object's collision data into static collision. You may run this only once to capture the object's collision at that frame. + +### Lua Example +`local StaticObjectCollisionValue = load_static_object_collision()` + +### Parameters +- None + +### Returns +[StaticObjectCollision](structs.md#StaticObjectCollision) + +### C Prototype +`struct StaticObjectCollision *load_static_object_collision();` + +[:arrow_up_small:](#) + +
+ +## [toggle_static_object_collision](#toggle_static_object_collision) + +### Description +Toggles a collection of static object surfaces + +### Lua Example +`toggle_static_object_collision(col, tangible)` + +### Parameters +| Field | Type | +| ----- | ---- | +| col | [StaticObjectCollision](structs.md#StaticObjectCollision) | +| tangible | `boolean` | + +### Returns +- None + +### C Prototype +`void toggle_static_object_collision(struct StaticObjectCollision *col, bool tangible);` + +[:arrow_up_small:](#) + +
+ +## [get_static_object_surface](#get_static_object_surface) + +### Description +Gets a surface corresponding to `index` from the static object collision + +### Lua Example +`local SurfaceValue = get_static_object_surface(col, index)` + +### Parameters +| Field | Type | +| ----- | ---- | +| col | [StaticObjectCollision](structs.md#StaticObjectCollision) | +| index | `integer` | + +### Returns +[Surface](structs.md#Surface) + +### C Prototype +`struct Surface *get_static_object_surface(struct StaticObjectCollision *col, u32 index);` + +[:arrow_up_small:](#) + +
+ ## [obj_get_surface_from_index](#obj_get_surface_from_index) ### Description diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 4ec201ce2..1783c3bae 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -2189,6 +2189,9 @@ - surface_load.h - [load_object_collision_model](functions-7.md#load_object_collision_model) + - [load_static_object_collision](functions-7.md#load_static_object_collision) + - [toggle_static_object_collision](functions-7.md#toggle_static_object_collision) + - [get_static_object_surface](functions-7.md#get_static_object_surface) - [obj_get_surface_from_index](functions-7.md#obj_get_surface_from_index) - [surface_has_force](functions-7.md#surface_has_force) diff --git a/docs/lua/structs.md b/docs/lua/structs.md index 6ba8fff59..0083c2a6c 100644 --- a/docs/lua/structs.md +++ b/docs/lua/structs.md @@ -105,6 +105,7 @@ - [SpawnParticlesInfo](#SpawnParticlesInfo) - [StarPositions](#StarPositions) - [StarsNeededForDialog](#StarsNeededForDialog) +- [StaticObjectCollision](#StaticObjectCollision) - [Surface](#Surface) - [TextureInfo](#TextureInfo) - [TransitionInfo](#TransitionInfo) @@ -3210,6 +3211,17 @@
+## [StaticObjectCollision](#StaticObjectCollision) + +| Field | Type | Access | +| ----- | ---- | ------ | +| index | `integer` | read-only | +| length | `integer` | read-only | + +[:arrow_up_small:](#) + +
+ ## [Surface](#Surface) | Field | Type | Access | diff --git a/include/surface_terrains.h b/include/surface_terrains.h index 091ed64d4..c43924a5f 100644 --- a/include/surface_terrains.h +++ b/include/surface_terrains.h @@ -163,6 +163,7 @@ #define SURFACE_FLAG_DYNAMIC (1 << 0) #define SURFACE_FLAG_NO_CAM_COLLISION (1 << 1) +#define SURFACE_FLAG_INTANGIBLE (1 << 2) #define SURFACE_FLAG_X_PROJECTION (1 << 3) #define HAZARD_TYPE_LAVA_FLOOR 1 diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 96ef6cfcb..1e34afd7f 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -137,9 +137,8 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, surfaceNode = surfaceNode->next; // Exclude a large number of walls immediately to optimize. - if (y < surf->lowerY || y > surf->upperY) { - continue; - } + if (y < surf->lowerY || y > surf->upperY) { continue; } + if (surf->flags & SURFACE_FLAG_INTANGIBLE) { continue; } if (gLevelValues.fixCollisionBugs && gLevelValues.fixCollisionBugsRoundedCorners && !gFindWallDirectionAirborne) { // Check AABB to exclude walls before doing expensive triangle check @@ -399,6 +398,8 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 surf = surfaceNode->surface; surfaceNode = surfaceNode->next; + if (surf->flags & SURFACE_FLAG_INTANGIBLE) { continue; } + x1 = surf->vertex1[0]; z1 = surf->vertex1[2]; z2 = surf->vertex2[2]; @@ -622,7 +623,8 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 if (surf == NULL) { break; } surfaceNode = surfaceNode->next; interpolate = gInterpolatingSurfaces; - + + if (surf->flags & SURFACE_FLAG_INTANGIBLE) { continue; } if (gCheckingSurfaceCollisionsForObject != NULL) { if (surf->object != gCheckingSurfaceCollisionsForObject) { continue; diff --git a/src/engine/surface_collision.h b/src/engine/surface_collision.h index d954b847b..ff5257a57 100644 --- a/src/engine/surface_collision.h +++ b/src/engine/surface_collision.h @@ -38,6 +38,12 @@ struct FloorGeometry f32 originOffset; }; +struct StaticObjectCollision +{ + u32 index; + u16 length; +}; + extern Vec3f gFindWallDirection; extern u8 gFindWallDirectionActive; extern u8 gFindWallDirectionAirborne; diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c index f74eb8110..e5296490e 100644 --- a/src/engine/surface_load.c +++ b/src/engine/surface_load.c @@ -28,12 +28,48 @@ SpatialPartitionCell gStaticSurfacePartition[NUM_CELLS][NUM_CELLS]; SpatialPartitionCell gDynamicSurfacePartition[NUM_CELLS][NUM_CELLS]; +/** + * The total number of surface nodes allocated (a node is allocated for each + * spatial partition cell that a surface intersects). + */ +s32 gSurfaceNodesAllocated; + +/** + * The total number of surfaces allocated. + */ +s32 gSurfacesAllocated; + +/** + * The number of nodes that have been created for static surfaces. + */ +s32 gNumStaticSurfaceNodes; + +/** + * The number of static surfaces in the pool. + */ +s32 gNumStaticSurfaces; + +/** + * The number of nodes that have been created for static object collision surfaces. + */ +s32 gNumSOCSurfaceNodes; + +/** + * The number of static object collision surfaces in the pool. + */ +s32 gNumSOCSurfaces; + /** * Pools of data to contain either surface nodes or surfaces. */ static struct GrowingArray *sSurfaceNodePool = NULL; static struct GrowingArray *sSurfacePool = NULL; +/** + * Pool of data for static object collisions. + */ +static struct GrowingArray *sSOCPool = NULL; + /** * Allocate the part of the surface node pool to contain a surface node. */ @@ -51,6 +87,10 @@ static struct Surface *alloc_surface(void) { return growing_array_alloc(sSurfacePool, sizeof(struct Surface)); } +static struct StaticObjectCollision *alloc_static_object_collision(void) { + return growing_array_alloc(sSOCPool, sizeof(struct StaticObjectCollision)); +} + /** * Iterates through the entire partition, clearing the surfaces. */ @@ -71,6 +111,7 @@ static void clear_spatial_partition(SpatialPartitionCell *cells) { */ static void clear_static_surfaces(void) { clear_spatial_partition(&gStaticSurfacePartition[0][0]); + sSOCPool = growing_array_init(sSOCPool, 0x100, malloc, smlua_free_soc); } /** @@ -479,6 +520,8 @@ void alloc_surface_pools(void) { gSurfacesAllocated = 0; gNumStaticSurfaceNodes = 0; gNumStaticSurfaces = 0; + gNumSOCSurfaceNodes = 0; + gNumSOCSurfaces = 0; gCCMEnteredSlide = 0; reset_red_coins_collected(); @@ -586,6 +629,8 @@ void load_area_terrain(s16 index, s16 *data, s8 *surfaceRooms, s16 *macroObjects gNumStaticSurfaceNodes = gSurfaceNodesAllocated; gNumStaticSurfaces = gSurfacesAllocated; + gNumSOCSurfaceNodes = 0; + gNumSOCSurfaces = 0; } /** @@ -593,8 +638,8 @@ void load_area_terrain(s16 index, s16 *data, s8 *surfaceRooms, s16 *macroObjects */ void clear_dynamic_surfaces(void) { if (!(gTimeStopState & TIME_STOP_ACTIVE)) { - gSurfacesAllocated = gNumStaticSurfaces; - gSurfaceNodesAllocated = gNumStaticSurfaceNodes; + gSurfacesAllocated = gNumStaticSurfaces + gNumSOCSurfaces; + gSurfaceNodesAllocated = gNumStaticSurfaceNodes + gNumSOCSurfaceNodes; clear_spatial_partition(&gDynamicSurfacePartition[0][0]); @@ -650,7 +695,7 @@ void transform_object_vertices(s16 **data, s16 *vertexData) { /** * Load in the surfaces for the gCurrentObject. This includes setting the flags, exertion, and room. */ -void load_object_surfaces(s16** data, s16* vertexData) { +void load_object_surfaces(s16** data, s16* vertexData, bool isSOC) { if (!gCurrentObject) { return; } s32 surfaceType; s32 i; @@ -682,15 +727,16 @@ void load_object_surfaces(s16** data, s16* vertexData) { struct Surface* surface = read_surface_data(vertexData, data); if (surface != NULL) { - - // Set index of first surface - if (gCurrentObject->firstSurface == 0) { - gCurrentObject->firstSurface = gSurfacesAllocated - 1; + if (!isSOC) { + // Set index of first surface + if (gCurrentObject->firstSurface == 0) { + gCurrentObject->firstSurface = gSurfacesAllocated - 1; + } + + // Increase surface count + gCurrentObject->numSurfaces++; } - // Increase surface count - gCurrentObject->numSurfaces++; - surface->object = gCurrentObject; surface->type = surfaceType; @@ -702,7 +748,7 @@ void load_object_surfaces(s16** data, s16* vertexData) { surface->flags |= flags; surface->room = (s8)room; - add_surface(surface, TRUE); + add_surface(surface, !isSOC); } if (hasForce) { @@ -716,9 +762,12 @@ void load_object_surfaces(s16** data, s16* vertexData) { /** * Transform an object's vertices, reload them, and render the object. */ -void load_object_collision_model(void) { +static void load_object_collision_model_internal(bool isSOC) { + static bool sIsLoadingCollision = false; + if (!gCurrentObject) { return; } if (gCurrentObject->collisionData == NULL) { return; } + if (sIsLoadingCollision) { return; } s32 numVertices = 64; if (gCurrentObject->collisionData[0] == COL_INIT()) { @@ -736,6 +785,9 @@ void load_object_collision_model(void) { static s32 sVertexDataCount = 0; static s16* sVertexData = NULL; + // start loading collision + sIsLoadingCollision = true; + // allocate vertex data if (numVertices > sVertexDataCount || sVertexData == NULL) { if (sVertexData) { free(sVertexData); } @@ -746,39 +798,99 @@ void load_object_collision_model(void) { } s16* collisionData = gCurrentObject->collisionData; - f32 tangibleDist = gCurrentObject->oCollisionDistance; u8 anyPlayerInTangibleRange = FALSE; - for (s32 i = 0; i < MAX_PLAYERS; i++) { - f32 dist = dist_between_objects(gCurrentObject, gMarioStates[i].marioObj); - if (dist < tangibleDist) { anyPlayerInTangibleRange = TRUE; } + if (!isSOC) { + f32 tangibleDist = gCurrentObject->oCollisionDistance; + + for (s32 i = 0; i < MAX_PLAYERS; i++) { + f32 dist = dist_between_objects(gCurrentObject, gMarioStates[i].marioObj); + if (dist < tangibleDist) { anyPlayerInTangibleRange = TRUE; } + } + + // If the object collision is supposed to be loaded more than the + // drawing distance of 4000, extend the drawing range. + if (gCurrentObject->oCollisionDistance > 4000.0f) { + gCurrentObject->oDrawingDistance = gCurrentObject->oCollisionDistance; + } } - // If the object collision is supposed to be loaded more than the - // drawing distance of 4000, extend the drawing range. - if (gCurrentObject->oCollisionDistance > 4000.0f) { - gCurrentObject->oDrawingDistance = gCurrentObject->oCollisionDistance; - } - - // Update if no Time Stop, in range, and in the current room. - if (!(gTimeStopState & TIME_STOP_ACTIVE) + // Update if no Time Stop, in range, and in the current room. (or if static) + if (isSOC || + (!(gTimeStopState & TIME_STOP_ACTIVE) && (anyPlayerInTangibleRange) - && !(gCurrentObject->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM)) { + && !(gCurrentObject->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM)) + ) { collisionData++; transform_object_vertices(&collisionData, sVertexData); // TERRAIN_LOAD_CONTINUE acts as an "end" to the terrain data. while (*collisionData != TERRAIN_LOAD_CONTINUE) { - load_object_surfaces(&collisionData, sVertexData); + load_object_surfaces(&collisionData, sVertexData, isSOC); } } - f32 marioDist = dist_between_objects(gCurrentObject, gMarioStates[0].marioObj); - if (marioDist < gCurrentObject->oDrawingDistance * draw_distance_scalar()) { - gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE; - } else { - gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE; + if (!isSOC) { + f32 marioDist = dist_between_objects(gCurrentObject, gMarioStates[0].marioObj); + if (marioDist < gCurrentObject->oDrawingDistance * draw_distance_scalar()) { + gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE; + } else { + gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE; + } } + + // stop loading collision + sIsLoadingCollision = false; +} + +void load_object_collision_model(void) { + load_object_collision_model_internal(false); +} + +struct StaticObjectCollision *load_static_object_collision() { + struct StaticObjectCollision *col; + u32 lastSurfaceIndex = gSurfacesAllocated; + u32 lastSurfaceNodeIndex = gSurfaceNodesAllocated; + u32 lastSOCSurfaceIndex = gNumStaticSurfaces + gNumSOCSurfaces; + u32 lastSOCSurfaceNodeIndex = gNumStaticSurfaceNodes + gNumSOCSurfaceNodes; + + load_object_collision_model_internal(true); + + // Reorder surfaces and nodes and update SOC variables + u32 addedSurfaces = gSurfacesAllocated - lastSurfaceIndex; + u32 addedSurfaceNodes = gSurfaceNodesAllocated - lastSurfaceNodeIndex; + if (addedSurfaces > 0) { + growing_array_move(sSurfacePool, lastSurfaceIndex, lastSOCSurfaceIndex, addedSurfaces); + gNumSOCSurfaces += addedSurfaces; + } + if (addedSurfaceNodes > 0) { + growing_array_move(sSurfaceNodePool, lastSurfaceNodeIndex, lastSOCSurfaceNodeIndex, addedSurfaceNodes); + gNumSOCSurfaceNodes += addedSurfaceNodes; + } + + col = alloc_static_object_collision(); + col->index = lastSOCSurfaceIndex; + col->length = addedSurfaces; + + return col; +} + +void toggle_static_object_collision(struct StaticObjectCollision *col, bool tangible) { + for (s32 i = 0; i < col->length; i++) { + struct Surface *surf = sSurfacePool->buffer[col->index + i]; + if (tangible) { + surf->flags &= ~SURFACE_FLAG_INTANGIBLE; + } else { + surf->flags |= SURFACE_FLAG_INTANGIBLE; + } + } +} + +struct Surface *get_static_object_surface(struct StaticObjectCollision *col, u32 index) { + if (!col) { return NULL; } + if (index >= col->length) { return NULL; } + struct Surface *surf = sSurfacePool->buffer[col->index + index]; + return surf; } struct Surface *obj_get_surface_from_index(struct Object *o, u32 index) { diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index 262958423..d0f2db1ad 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -27,6 +27,13 @@ typedef struct SurfaceNode SpatialPartitionCell[3]; extern SpatialPartitionCell gStaticSurfacePartition[NUM_CELLS][NUM_CELLS]; extern SpatialPartitionCell gDynamicSurfacePartition[NUM_CELLS][NUM_CELLS]; +extern s32 gSurfaceNodesAllocated; +extern s32 gSurfacesAllocated; +extern s32 gNumStaticSurfaceNodes; +extern s32 gNumStaticSurfaces; +extern s32 gNumSOCSurfaceNodes; +extern s32 gNumSOCSurfaces; + void alloc_surface_pools(void); u32 get_area_terrain_size(s16 *data); @@ -38,6 +45,15 @@ Loads the object's collision data into dynamic collision. You must run this every frame in your object's behavior loop for it to have collision |descriptionEnd| */ void load_object_collision_model(void); +/* |description| +Loads the object's collision data into static collision. +You may run this only once to capture the object's collision at that frame. +|descriptionEnd| */ +struct StaticObjectCollision *load_static_object_collision(); +/* |description|Toggles a collection of static object surfaces|descriptionEnd| */ +void toggle_static_object_collision(struct StaticObjectCollision *col, bool tangible); +/* |description|Gets a surface corresponding to `index` from the static object collision|descriptionEnd| */ +struct Surface *get_static_object_surface(struct StaticObjectCollision *col, u32 index); /* |description|Gets a surface corresponding to `index` from the surface pool buffer|descriptionEnd| */ struct Surface *obj_get_surface_from_index(struct Object *o, u32 index); /* |description|Checks if a surface has force|descriptionEnd| */ diff --git a/src/game/memory.c b/src/game/memory.c index 6018a6e33..feca24fd1 100644 --- a/src/game/memory.c +++ b/src/game/memory.c @@ -220,6 +220,32 @@ void *growing_array_alloc(struct GrowingArray *array, u32 size) { return NULL; } +void growing_array_move(struct GrowingArray *array, u32 from, u32 to, u32 count) { + if (array && array->buffer && count > 0 && + (to < from || to > from + count) && + (from + count) <= array->count && to <= array->count) { + + void **temp = malloc(sizeof(void *) * count); + if (!temp) { return; } + + // Copy elements to move to temporary buffer + memcpy(temp, array->buffer + from, sizeof(void *) * count); + + // Remove copied elements from the array + memmove(array->buffer + from, array->buffer + (from + count), sizeof(void *) * (array->count - (from + count))); + + // Make place for the copied elements + // If moving left to right, account for the removed elements + if (to > from) { to -= count; } + memmove(array->buffer + (to + count), array->buffer + to, sizeof(void *) * (array->count - (to + count))); + + // Insert copied elements + memcpy(array->buffer + to, temp, sizeof(void *) * count); + + free(temp); + } +} + void growing_array_free(struct GrowingArray **array) { if (*array) { for (u32 i = 0; i != (*array)->capacity; ++i) { diff --git a/src/game/memory.h b/src/game/memory.h index dba8f7535..d8f469814 100644 --- a/src/game/memory.h +++ b/src/game/memory.h @@ -77,6 +77,7 @@ void growing_pool_free_pool(struct GrowingPool *pool); struct GrowingArray *growing_array_init(struct GrowingArray *array, u32 capacity, GrowingArrayAllocFunc alloc, GrowingArrayFreeFunc free); void *growing_array_alloc(struct GrowingArray *array, u32 size); +void growing_array_move(struct GrowingArray *array, u32 from, u32 to, u32 count); void growing_array_free(struct GrowingArray **array); void growing_array_debug_print(struct GrowingArray *array, const char *name, s32 x, s32 y); diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index 3e901bdc7..1752ae7b4 100644 --- a/src/game/object_list_processor.c +++ b/src/game/object_list_processor.c @@ -122,27 +122,6 @@ const BehaviorScript *gCurBhvCommand; */ s16 gPrevFrameObjectCount; -/** - * The total number of surface nodes allocated (a node is allocated for each - * spatial partition cell that a surface intersects). - */ -s32 gSurfaceNodesAllocated; - -/** - * The total number of surfaces allocated. - */ -s32 gSurfacesAllocated; - -/** - * The number of nodes that have been created for surfaces. - */ -s32 gNumStaticSurfaceNodes; - -/** - * The number of surfaces in the pool. - */ -s32 gNumStaticSurfaces; - struct Object* gCheckingSurfaceCollisionsForObject = NULL; s16 gCheckingSurfaceCollisionsForCamera; s16 gFindFloorIncludeSurfaceIntangible; diff --git a/src/game/object_list_processor.h b/src/game/object_list_processor.h index 24a1acf27..98cb25a95 100644 --- a/src/game/object_list_processor.h +++ b/src/game/object_list_processor.h @@ -91,11 +91,6 @@ extern struct Object *gCurrentObject; extern const BehaviorScript *gCurBhvCommand; extern s16 gPrevFrameObjectCount; -extern s32 gSurfaceNodesAllocated; -extern s32 gSurfacesAllocated; -extern s32 gNumStaticSurfaceNodes; -extern s32 gNumStaticSurfaces; - extern struct Object* gCheckingSurfaceCollisionsForObject; extern s16 gCheckingSurfaceCollisionsForCamera; extern s16 gFindFloorIncludeSurfaceIntangible; diff --git a/src/pc/lua/smlua_cobject.c b/src/pc/lua/smlua_cobject.c index 9b8d0b401..bc8ca1cca 100644 --- a/src/pc/lua/smlua_cobject.c +++ b/src/pc/lua/smlua_cobject.c @@ -650,6 +650,12 @@ int smlua__eq(lua_State *L) { return 1; } +int smlua__bnot(lua_State *L) { + const CObject *a = lua_touserdata(L, 1); + lua_pushboolean(L, !a || a->freed); + return 1; +} + static int smlua_cpointer_get(lua_State* L) { const CPointer *cptr = lua_touserdata(L, 1); const char *key = lua_tostring(L, 2); @@ -690,6 +696,7 @@ void smlua_cobject_init_globals(void) { { "__index", smlua__get_field }, { "__newindex", smlua__set_field }, { "__eq", smlua__eq }, + { "__bnot", smlua__bnot }, { "__metatable", NULL }, { NULL, NULL } }; @@ -700,6 +707,7 @@ void smlua_cobject_init_globals(void) { { "__index", smlua_cpointer_get }, { "__newindex", smlua_cpointer_set }, { "__eq", smlua__eq }, + { "__bnot", smlua__bnot }, { "__metatable", NULL }, { NULL, NULL } }; diff --git a/src/pc/lua/smlua_cobject_autogen.c b/src/pc/lua/smlua_cobject_autogen.c index 2bd02f925..ca833cc68 100644 --- a/src/pc/lua/smlua_cobject_autogen.c +++ b/src/pc/lua/smlua_cobject_autogen.c @@ -2742,6 +2742,12 @@ static struct LuaObjectField sStarsNeededForDialogFields[LUA_STARS_NEEDED_FOR_DI { "dialog6", LVT_U16, offsetof(struct StarsNeededForDialog, dialog6), false, LOT_NONE, 1, sizeof(u16) }, }; +#define LUA_STATIC_OBJECT_COLLISION_FIELD_COUNT 2 +static struct LuaObjectField sStaticObjectCollisionFields[LUA_STATIC_OBJECT_COLLISION_FIELD_COUNT] = { + { "index", LVT_U32, offsetof(struct StaticObjectCollision, index), true, LOT_NONE, 1, sizeof(u32) }, + { "length", LVT_U16, offsetof(struct StaticObjectCollision, length), true, LOT_NONE, 1, sizeof(u16) }, +}; + #define LUA_SURFACE_FIELD_COUNT 16 static struct LuaObjectField sSurfaceFields[LUA_SURFACE_FIELD_COUNT] = { { "flags", LVT_S8, offsetof(struct Surface, flags), false, LOT_NONE, 1, sizeof(s8) }, @@ -2980,6 +2986,7 @@ struct LuaObjectTable sLuaObjectAutogenTable[LOT_AUTOGEN_MAX - LOT_AUTOGEN_MIN] { LOT_SPAWNPARTICLESINFO, sSpawnParticlesInfoFields, LUA_SPAWN_PARTICLES_INFO_FIELD_COUNT }, { LOT_STARPOSITIONS, sStarPositionsFields, LUA_STAR_POSITIONS_FIELD_COUNT }, { LOT_STARSNEEDEDFORDIALOG, sStarsNeededForDialogFields, LUA_STARS_NEEDED_FOR_DIALOG_FIELD_COUNT }, + { LOT_STATICOBJECTCOLLISION, sStaticObjectCollisionFields, LUA_STATIC_OBJECT_COLLISION_FIELD_COUNT }, { LOT_SURFACE, sSurfaceFields, LUA_SURFACE_FIELD_COUNT }, { LOT_TEXTUREINFO, sTextureInfoFields, LUA_TEXTURE_INFO_FIELD_COUNT }, { LOT_TRANSITIONINFO, sTransitionInfoFields, LUA_TRANSITION_INFO_FIELD_COUNT }, @@ -3110,6 +3117,7 @@ const char *sLuaLotNames[] = { [LOT_SPAWNPARTICLESINFO] = "SpawnParticlesInfo", [LOT_STARPOSITIONS] = "StarPositions", [LOT_STARSNEEDEDFORDIALOG] = "StarsNeededForDialog", + [LOT_STATICOBJECTCOLLISION] = "StaticObjectCollision", [LOT_SURFACE] = "Surface", [LOT_TEXTUREINFO] = "TextureInfo", [LOT_TRANSITIONINFO] = "TransitionInfo", diff --git a/src/pc/lua/smlua_cobject_autogen.h b/src/pc/lua/smlua_cobject_autogen.h index b5ec35d19..a79378a98 100644 --- a/src/pc/lua/smlua_cobject_autogen.h +++ b/src/pc/lua/smlua_cobject_autogen.h @@ -123,6 +123,7 @@ enum LuaObjectAutogenType { LOT_SPAWNPARTICLESINFO, LOT_STARPOSITIONS, LOT_STARSNEEDEDFORDIALOG, + LOT_STATICOBJECTCOLLISION, LOT_SURFACE, LOT_TEXTUREINFO, LOT_TRANSITIONINFO, diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index 6966f02fe..e916e2a1b 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -4543,6 +4543,7 @@ char gSmluaConstants[] = "" "SURFACE_CLASS_NOT_SLIPPERY=0x0015\n" "SURFACE_FLAG_DYNAMIC=(1 << 0)\n" "SURFACE_FLAG_NO_CAM_COLLISION=(1 << 1)\n" +"SURFACE_FLAG_INTANGIBLE=(1 << 2)\n" "SURFACE_FLAG_X_PROJECTION=(1 << 3)\n" "HAZARD_TYPE_LAVA_FLOOR=1\n" "HAZARD_TYPE_LAVA_WALL=2\n" diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index c28245176..50125e3ef 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -36485,6 +36485,59 @@ int smlua_func_load_object_collision_model(UNUSED lua_State* L) { return 1; } +int smlua_func_load_static_object_collision(UNUSED lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 0) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "load_static_object_collision", 0, top); + return 0; + } + + + smlua_push_object(L, LOT_STATICOBJECTCOLLISION, load_static_object_collision(), NULL); + + return 1; +} + +int smlua_func_toggle_static_object_collision(lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 2) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "toggle_static_object_collision", 2, top); + return 0; + } + + struct StaticObjectCollision* col = (struct StaticObjectCollision*)smlua_to_cobject(L, 1, LOT_STATICOBJECTCOLLISION); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "toggle_static_object_collision"); return 0; } + bool tangible = smlua_to_boolean(L, 2); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "toggle_static_object_collision"); return 0; } + + toggle_static_object_collision(col, tangible); + + return 1; +} + +int smlua_func_get_static_object_surface(lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 2) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "get_static_object_surface", 2, top); + return 0; + } + + struct StaticObjectCollision* col = (struct StaticObjectCollision*)smlua_to_cobject(L, 1, LOT_STATICOBJECTCOLLISION); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "get_static_object_surface"); return 0; } + u32 index = smlua_to_integer(L, 2); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "get_static_object_surface"); return 0; } + + smlua_push_object(L, LOT_SURFACE, get_static_object_surface(col, index), NULL); + + return 1; +} + int smlua_func_obj_get_surface_from_index(lua_State* L) { if (L == NULL) { return 0; } @@ -38657,6 +38710,9 @@ void smlua_bind_functions_autogen(void) { // surface_load.h smlua_bind_function(L, "load_object_collision_model", smlua_func_load_object_collision_model); + smlua_bind_function(L, "load_static_object_collision", smlua_func_load_static_object_collision); + smlua_bind_function(L, "toggle_static_object_collision", smlua_func_toggle_static_object_collision); + smlua_bind_function(L, "get_static_object_surface", smlua_func_get_static_object_surface); smlua_bind_function(L, "obj_get_surface_from_index", smlua_func_obj_get_surface_from_index); smlua_bind_function(L, "surface_has_force", smlua_func_surface_has_force); diff --git a/src/pc/lua/smlua_utils.h b/src/pc/lua/smlua_utils.h index 25a76c81b..a855b0a02 100644 --- a/src/pc/lua/smlua_utils.h +++ b/src/pc/lua/smlua_utils.h @@ -69,5 +69,6 @@ void smlua_free(void *ptr, u16 lot); static inline void smlua_free_##name(void *ptr) { smlua_free(ptr, lot); } smlua_free_lot(surface, LOT_SURFACE); +smlua_free_lot(soc, LOT_STATICOBJECTCOLLISION); #endif \ No newline at end of file