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>
This commit is contained in:
Cooliokid956 2025-10-21 12:04:05 -05:00 committed by GitHub
parent 98891b7334
commit 9a934f8443
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 388 additions and 61 deletions

View file

@ -142,6 +142,7 @@ override_field_immutable = {
"DialogEntry": [ "unused", "linesPerBox", "leftOffset", "width", "str", "text", "replaced"], "DialogEntry": [ "unused", "linesPerBox", "leftOffset", "width", "str", "text", "replaced"],
"ModFsFile": [ "*" ], "ModFsFile": [ "*" ],
"ModFs": [ "*" ], "ModFs": [ "*" ],
"StaticObjectCollision": [ "*" ],
} }
override_field_version_excludes = { override_field_version_excludes = {

View file

@ -10956,6 +10956,9 @@ SURFACE_FLAG_DYNAMIC = (1 << 0)
--- @type integer --- @type integer
SURFACE_FLAG_NO_CAM_COLLISION = (1 << 1) SURFACE_FLAG_NO_CAM_COLLISION = (1 << 1)
--- @type integer
SURFACE_FLAG_INTANGIBLE = (1 << 2)
--- @type integer --- @type integer
SURFACE_FLAG_X_PROJECTION = (1 << 3) SURFACE_FLAG_X_PROJECTION = (1 << 3)

View file

@ -12295,6 +12295,27 @@ function load_object_collision_model()
-- ... -- ...
end 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 o Object
--- @param index integer --- @param index integer
--- @return Surface --- @return Surface

View file

@ -2337,6 +2337,10 @@
--- @field public dialog5 integer --- @field public dialog5 integer
--- @field public dialog6 integer --- @field public dialog6 integer
--- @class StaticObjectCollision
--- @field public index integer
--- @field public length integer
--- @class Surface --- @class Surface
--- @field public type integer --- @field public type integer
--- @field public flags integer --- @field public flags integer

View file

@ -4620,6 +4620,7 @@
- SURFACE_CLASS_NOT_SLIPPERY - SURFACE_CLASS_NOT_SLIPPERY
- SURFACE_FLAG_DYNAMIC - SURFACE_FLAG_DYNAMIC
- SURFACE_FLAG_NO_CAM_COLLISION - SURFACE_FLAG_NO_CAM_COLLISION
- SURFACE_FLAG_INTANGIBLE
- SURFACE_FLAG_X_PROJECTION - SURFACE_FLAG_X_PROJECTION
- HAZARD_TYPE_LAVA_FLOOR - HAZARD_TYPE_LAVA_FLOOR
- HAZARD_TYPE_LAVA_WALL - HAZARD_TYPE_LAVA_WALL

View file

@ -32,6 +32,75 @@ Loads the object's collision data into dynamic collision. You must run this ever
<br /> <br />
## [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:](#)
<br />
## [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:](#)
<br />
## [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:](#)
<br />
## [obj_get_surface_from_index](#obj_get_surface_from_index) ## [obj_get_surface_from_index](#obj_get_surface_from_index)
### Description ### Description

View file

@ -2189,6 +2189,9 @@
- surface_load.h - surface_load.h
- [load_object_collision_model](functions-7.md#load_object_collision_model) - [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) - [obj_get_surface_from_index](functions-7.md#obj_get_surface_from_index)
- [surface_has_force](functions-7.md#surface_has_force) - [surface_has_force](functions-7.md#surface_has_force)

View file

@ -105,6 +105,7 @@
- [SpawnParticlesInfo](#SpawnParticlesInfo) - [SpawnParticlesInfo](#SpawnParticlesInfo)
- [StarPositions](#StarPositions) - [StarPositions](#StarPositions)
- [StarsNeededForDialog](#StarsNeededForDialog) - [StarsNeededForDialog](#StarsNeededForDialog)
- [StaticObjectCollision](#StaticObjectCollision)
- [Surface](#Surface) - [Surface](#Surface)
- [TextureInfo](#TextureInfo) - [TextureInfo](#TextureInfo)
- [TransitionInfo](#TransitionInfo) - [TransitionInfo](#TransitionInfo)
@ -3210,6 +3211,17 @@
<br /> <br />
## [StaticObjectCollision](#StaticObjectCollision)
| Field | Type | Access |
| ----- | ---- | ------ |
| index | `integer` | read-only |
| length | `integer` | read-only |
[:arrow_up_small:](#)
<br />
## [Surface](#Surface) ## [Surface](#Surface)
| Field | Type | Access | | Field | Type | Access |

View file

@ -163,6 +163,7 @@
#define SURFACE_FLAG_DYNAMIC (1 << 0) #define SURFACE_FLAG_DYNAMIC (1 << 0)
#define SURFACE_FLAG_NO_CAM_COLLISION (1 << 1) #define SURFACE_FLAG_NO_CAM_COLLISION (1 << 1)
#define SURFACE_FLAG_INTANGIBLE (1 << 2)
#define SURFACE_FLAG_X_PROJECTION (1 << 3) #define SURFACE_FLAG_X_PROJECTION (1 << 3)
#define HAZARD_TYPE_LAVA_FLOOR 1 #define HAZARD_TYPE_LAVA_FLOOR 1

View file

@ -137,9 +137,8 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode,
surfaceNode = surfaceNode->next; surfaceNode = surfaceNode->next;
// Exclude a large number of walls immediately to optimize. // Exclude a large number of walls immediately to optimize.
if (y < surf->lowerY || y > surf->upperY) { if (y < surf->lowerY || y > surf->upperY) { continue; }
continue; if (surf->flags & SURFACE_FLAG_INTANGIBLE) { continue; }
}
if (gLevelValues.fixCollisionBugs && gLevelValues.fixCollisionBugsRoundedCorners && !gFindWallDirectionAirborne) { if (gLevelValues.fixCollisionBugs && gLevelValues.fixCollisionBugsRoundedCorners && !gFindWallDirectionAirborne) {
// Check AABB to exclude walls before doing expensive triangle check // 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; surf = surfaceNode->surface;
surfaceNode = surfaceNode->next; surfaceNode = surfaceNode->next;
if (surf->flags & SURFACE_FLAG_INTANGIBLE) { continue; }
x1 = surf->vertex1[0]; x1 = surf->vertex1[0];
z1 = surf->vertex1[2]; z1 = surf->vertex1[2];
z2 = surf->vertex2[2]; z2 = surf->vertex2[2];
@ -623,6 +624,7 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
surfaceNode = surfaceNode->next; surfaceNode = surfaceNode->next;
interpolate = gInterpolatingSurfaces; interpolate = gInterpolatingSurfaces;
if (surf->flags & SURFACE_FLAG_INTANGIBLE) { continue; }
if (gCheckingSurfaceCollisionsForObject != NULL) { if (gCheckingSurfaceCollisionsForObject != NULL) {
if (surf->object != gCheckingSurfaceCollisionsForObject) { if (surf->object != gCheckingSurfaceCollisionsForObject) {
continue; continue;

View file

@ -38,6 +38,12 @@ struct FloorGeometry
f32 originOffset; f32 originOffset;
}; };
struct StaticObjectCollision
{
u32 index;
u16 length;
};
extern Vec3f gFindWallDirection; extern Vec3f gFindWallDirection;
extern u8 gFindWallDirectionActive; extern u8 gFindWallDirectionActive;
extern u8 gFindWallDirectionAirborne; extern u8 gFindWallDirectionAirborne;

View file

@ -28,12 +28,48 @@
SpatialPartitionCell gStaticSurfacePartition[NUM_CELLS][NUM_CELLS]; SpatialPartitionCell gStaticSurfacePartition[NUM_CELLS][NUM_CELLS];
SpatialPartitionCell gDynamicSurfacePartition[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. * Pools of data to contain either surface nodes or surfaces.
*/ */
static struct GrowingArray *sSurfaceNodePool = NULL; static struct GrowingArray *sSurfaceNodePool = NULL;
static struct GrowingArray *sSurfacePool = 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. * 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)); 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. * 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) { static void clear_static_surfaces(void) {
clear_spatial_partition(&gStaticSurfacePartition[0][0]); 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; gSurfacesAllocated = 0;
gNumStaticSurfaceNodes = 0; gNumStaticSurfaceNodes = 0;
gNumStaticSurfaces = 0; gNumStaticSurfaces = 0;
gNumSOCSurfaceNodes = 0;
gNumSOCSurfaces = 0;
gCCMEnteredSlide = 0; gCCMEnteredSlide = 0;
reset_red_coins_collected(); reset_red_coins_collected();
@ -586,6 +629,8 @@ void load_area_terrain(s16 index, s16 *data, s8 *surfaceRooms, s16 *macroObjects
gNumStaticSurfaceNodes = gSurfaceNodesAllocated; gNumStaticSurfaceNodes = gSurfaceNodesAllocated;
gNumStaticSurfaces = gSurfacesAllocated; 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) { void clear_dynamic_surfaces(void) {
if (!(gTimeStopState & TIME_STOP_ACTIVE)) { if (!(gTimeStopState & TIME_STOP_ACTIVE)) {
gSurfacesAllocated = gNumStaticSurfaces; gSurfacesAllocated = gNumStaticSurfaces + gNumSOCSurfaces;
gSurfaceNodesAllocated = gNumStaticSurfaceNodes; gSurfaceNodesAllocated = gNumStaticSurfaceNodes + gNumSOCSurfaceNodes;
clear_spatial_partition(&gDynamicSurfacePartition[0][0]); 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. * 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; } if (!gCurrentObject) { return; }
s32 surfaceType; s32 surfaceType;
s32 i; s32 i;
@ -682,7 +727,7 @@ void load_object_surfaces(s16** data, s16* vertexData) {
struct Surface* surface = read_surface_data(vertexData, data); struct Surface* surface = read_surface_data(vertexData, data);
if (surface != NULL) { if (surface != NULL) {
if (!isSOC) {
// Set index of first surface // Set index of first surface
if (gCurrentObject->firstSurface == 0) { if (gCurrentObject->firstSurface == 0) {
gCurrentObject->firstSurface = gSurfacesAllocated - 1; gCurrentObject->firstSurface = gSurfacesAllocated - 1;
@ -690,6 +735,7 @@ void load_object_surfaces(s16** data, s16* vertexData) {
// Increase surface count // Increase surface count
gCurrentObject->numSurfaces++; gCurrentObject->numSurfaces++;
}
surface->object = gCurrentObject; surface->object = gCurrentObject;
surface->type = surfaceType; surface->type = surfaceType;
@ -702,7 +748,7 @@ void load_object_surfaces(s16** data, s16* vertexData) {
surface->flags |= flags; surface->flags |= flags;
surface->room = (s8)room; surface->room = (s8)room;
add_surface(surface, TRUE); add_surface(surface, !isSOC);
} }
if (hasForce) { 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. * 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) { return; }
if (gCurrentObject->collisionData == NULL) { return; } if (gCurrentObject->collisionData == NULL) { return; }
if (sIsLoadingCollision) { return; }
s32 numVertices = 64; s32 numVertices = 64;
if (gCurrentObject->collisionData[0] == COL_INIT()) { if (gCurrentObject->collisionData[0] == COL_INIT()) {
@ -736,6 +785,9 @@ void load_object_collision_model(void) {
static s32 sVertexDataCount = 0; static s32 sVertexDataCount = 0;
static s16* sVertexData = NULL; static s16* sVertexData = NULL;
// start loading collision
sIsLoadingCollision = true;
// allocate vertex data // allocate vertex data
if (numVertices > sVertexDataCount || sVertexData == NULL) { if (numVertices > sVertexDataCount || sVertexData == NULL) {
if (sVertexData) { free(sVertexData); } if (sVertexData) { free(sVertexData); }
@ -746,9 +798,11 @@ void load_object_collision_model(void) {
} }
s16* collisionData = gCurrentObject->collisionData; s16* collisionData = gCurrentObject->collisionData;
f32 tangibleDist = gCurrentObject->oCollisionDistance;
u8 anyPlayerInTangibleRange = FALSE; u8 anyPlayerInTangibleRange = FALSE;
if (!isSOC) {
f32 tangibleDist = gCurrentObject->oCollisionDistance;
for (s32 i = 0; i < MAX_PLAYERS; i++) { for (s32 i = 0; i < MAX_PLAYERS; i++) {
f32 dist = dist_between_objects(gCurrentObject, gMarioStates[i].marioObj); f32 dist = dist_between_objects(gCurrentObject, gMarioStates[i].marioObj);
if (dist < tangibleDist) { anyPlayerInTangibleRange = TRUE; } if (dist < tangibleDist) { anyPlayerInTangibleRange = TRUE; }
@ -759,26 +813,84 @@ void load_object_collision_model(void) {
if (gCurrentObject->oCollisionDistance > 4000.0f) { if (gCurrentObject->oCollisionDistance > 4000.0f) {
gCurrentObject->oDrawingDistance = gCurrentObject->oCollisionDistance; gCurrentObject->oDrawingDistance = gCurrentObject->oCollisionDistance;
} }
}
// Update if no Time Stop, in range, and in the current room. // Update if no Time Stop, in range, and in the current room. (or if static)
if (!(gTimeStopState & TIME_STOP_ACTIVE) if (isSOC ||
(!(gTimeStopState & TIME_STOP_ACTIVE)
&& (anyPlayerInTangibleRange) && (anyPlayerInTangibleRange)
&& !(gCurrentObject->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM)) { && !(gCurrentObject->activeFlags & ACTIVE_FLAG_IN_DIFFERENT_ROOM))
) {
collisionData++; collisionData++;
transform_object_vertices(&collisionData, sVertexData); transform_object_vertices(&collisionData, sVertexData);
// TERRAIN_LOAD_CONTINUE acts as an "end" to the terrain data. // TERRAIN_LOAD_CONTINUE acts as an "end" to the terrain data.
while (*collisionData != TERRAIN_LOAD_CONTINUE) { while (*collisionData != TERRAIN_LOAD_CONTINUE) {
load_object_surfaces(&collisionData, sVertexData); load_object_surfaces(&collisionData, sVertexData, isSOC);
} }
} }
if (!isSOC) {
f32 marioDist = dist_between_objects(gCurrentObject, gMarioStates[0].marioObj); f32 marioDist = dist_between_objects(gCurrentObject, gMarioStates[0].marioObj);
if (marioDist < gCurrentObject->oDrawingDistance * draw_distance_scalar()) { if (marioDist < gCurrentObject->oDrawingDistance * draw_distance_scalar()) {
gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE; gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
} else { } else {
gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE; 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) { struct Surface *obj_get_surface_from_index(struct Object *o, u32 index) {

View file

@ -27,6 +27,13 @@ typedef struct SurfaceNode SpatialPartitionCell[3];
extern SpatialPartitionCell gStaticSurfacePartition[NUM_CELLS][NUM_CELLS]; extern SpatialPartitionCell gStaticSurfacePartition[NUM_CELLS][NUM_CELLS];
extern SpatialPartitionCell gDynamicSurfacePartition[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); void alloc_surface_pools(void);
u32 get_area_terrain_size(s16 *data); 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 You must run this every frame in your object's behavior loop for it to have collision
|descriptionEnd| */ |descriptionEnd| */
void load_object_collision_model(void); 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| */ /* |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); struct Surface *obj_get_surface_from_index(struct Object *o, u32 index);
/* |description|Checks if a surface has force|descriptionEnd| */ /* |description|Checks if a surface has force|descriptionEnd| */

View file

@ -220,6 +220,32 @@ void *growing_array_alloc(struct GrowingArray *array, u32 size) {
return NULL; 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) { void growing_array_free(struct GrowingArray **array) {
if (*array) { if (*array) {
for (u32 i = 0; i != (*array)->capacity; ++i) { for (u32 i = 0; i != (*array)->capacity; ++i) {

View file

@ -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); 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_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_free(struct GrowingArray **array);
void growing_array_debug_print(struct GrowingArray *array, const char *name, s32 x, s32 y); void growing_array_debug_print(struct GrowingArray *array, const char *name, s32 x, s32 y);

View file

@ -122,27 +122,6 @@ const BehaviorScript *gCurBhvCommand;
*/ */
s16 gPrevFrameObjectCount; 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; struct Object* gCheckingSurfaceCollisionsForObject = NULL;
s16 gCheckingSurfaceCollisionsForCamera; s16 gCheckingSurfaceCollisionsForCamera;
s16 gFindFloorIncludeSurfaceIntangible; s16 gFindFloorIncludeSurfaceIntangible;

View file

@ -91,11 +91,6 @@ extern struct Object *gCurrentObject;
extern const BehaviorScript *gCurBhvCommand; extern const BehaviorScript *gCurBhvCommand;
extern s16 gPrevFrameObjectCount; extern s16 gPrevFrameObjectCount;
extern s32 gSurfaceNodesAllocated;
extern s32 gSurfacesAllocated;
extern s32 gNumStaticSurfaceNodes;
extern s32 gNumStaticSurfaces;
extern struct Object* gCheckingSurfaceCollisionsForObject; extern struct Object* gCheckingSurfaceCollisionsForObject;
extern s16 gCheckingSurfaceCollisionsForCamera; extern s16 gCheckingSurfaceCollisionsForCamera;
extern s16 gFindFloorIncludeSurfaceIntangible; extern s16 gFindFloorIncludeSurfaceIntangible;

View file

@ -650,6 +650,12 @@ int smlua__eq(lua_State *L) {
return 1; 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) { static int smlua_cpointer_get(lua_State* L) {
const CPointer *cptr = lua_touserdata(L, 1); const CPointer *cptr = lua_touserdata(L, 1);
const char *key = lua_tostring(L, 2); const char *key = lua_tostring(L, 2);
@ -690,6 +696,7 @@ void smlua_cobject_init_globals(void) {
{ "__index", smlua__get_field }, { "__index", smlua__get_field },
{ "__newindex", smlua__set_field }, { "__newindex", smlua__set_field },
{ "__eq", smlua__eq }, { "__eq", smlua__eq },
{ "__bnot", smlua__bnot },
{ "__metatable", NULL }, { "__metatable", NULL },
{ NULL, NULL } { NULL, NULL }
}; };
@ -700,6 +707,7 @@ void smlua_cobject_init_globals(void) {
{ "__index", smlua_cpointer_get }, { "__index", smlua_cpointer_get },
{ "__newindex", smlua_cpointer_set }, { "__newindex", smlua_cpointer_set },
{ "__eq", smlua__eq }, { "__eq", smlua__eq },
{ "__bnot", smlua__bnot },
{ "__metatable", NULL }, { "__metatable", NULL },
{ NULL, NULL } { NULL, NULL }
}; };

View file

@ -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) }, { "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 #define LUA_SURFACE_FIELD_COUNT 16
static struct LuaObjectField sSurfaceFields[LUA_SURFACE_FIELD_COUNT] = { static struct LuaObjectField sSurfaceFields[LUA_SURFACE_FIELD_COUNT] = {
{ "flags", LVT_S8, offsetof(struct Surface, flags), false, LOT_NONE, 1, sizeof(s8) }, { "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_SPAWNPARTICLESINFO, sSpawnParticlesInfoFields, LUA_SPAWN_PARTICLES_INFO_FIELD_COUNT },
{ LOT_STARPOSITIONS, sStarPositionsFields, LUA_STAR_POSITIONS_FIELD_COUNT }, { LOT_STARPOSITIONS, sStarPositionsFields, LUA_STAR_POSITIONS_FIELD_COUNT },
{ LOT_STARSNEEDEDFORDIALOG, sStarsNeededForDialogFields, LUA_STARS_NEEDED_FOR_DIALOG_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_SURFACE, sSurfaceFields, LUA_SURFACE_FIELD_COUNT },
{ LOT_TEXTUREINFO, sTextureInfoFields, LUA_TEXTURE_INFO_FIELD_COUNT }, { LOT_TEXTUREINFO, sTextureInfoFields, LUA_TEXTURE_INFO_FIELD_COUNT },
{ LOT_TRANSITIONINFO, sTransitionInfoFields, LUA_TRANSITION_INFO_FIELD_COUNT }, { LOT_TRANSITIONINFO, sTransitionInfoFields, LUA_TRANSITION_INFO_FIELD_COUNT },
@ -3110,6 +3117,7 @@ const char *sLuaLotNames[] = {
[LOT_SPAWNPARTICLESINFO] = "SpawnParticlesInfo", [LOT_SPAWNPARTICLESINFO] = "SpawnParticlesInfo",
[LOT_STARPOSITIONS] = "StarPositions", [LOT_STARPOSITIONS] = "StarPositions",
[LOT_STARSNEEDEDFORDIALOG] = "StarsNeededForDialog", [LOT_STARSNEEDEDFORDIALOG] = "StarsNeededForDialog",
[LOT_STATICOBJECTCOLLISION] = "StaticObjectCollision",
[LOT_SURFACE] = "Surface", [LOT_SURFACE] = "Surface",
[LOT_TEXTUREINFO] = "TextureInfo", [LOT_TEXTUREINFO] = "TextureInfo",
[LOT_TRANSITIONINFO] = "TransitionInfo", [LOT_TRANSITIONINFO] = "TransitionInfo",

View file

@ -123,6 +123,7 @@ enum LuaObjectAutogenType {
LOT_SPAWNPARTICLESINFO, LOT_SPAWNPARTICLESINFO,
LOT_STARPOSITIONS, LOT_STARPOSITIONS,
LOT_STARSNEEDEDFORDIALOG, LOT_STARSNEEDEDFORDIALOG,
LOT_STATICOBJECTCOLLISION,
LOT_SURFACE, LOT_SURFACE,
LOT_TEXTUREINFO, LOT_TEXTUREINFO,
LOT_TRANSITIONINFO, LOT_TRANSITIONINFO,

View file

@ -4543,6 +4543,7 @@ char gSmluaConstants[] = ""
"SURFACE_CLASS_NOT_SLIPPERY=0x0015\n" "SURFACE_CLASS_NOT_SLIPPERY=0x0015\n"
"SURFACE_FLAG_DYNAMIC=(1 << 0)\n" "SURFACE_FLAG_DYNAMIC=(1 << 0)\n"
"SURFACE_FLAG_NO_CAM_COLLISION=(1 << 1)\n" "SURFACE_FLAG_NO_CAM_COLLISION=(1 << 1)\n"
"SURFACE_FLAG_INTANGIBLE=(1 << 2)\n"
"SURFACE_FLAG_X_PROJECTION=(1 << 3)\n" "SURFACE_FLAG_X_PROJECTION=(1 << 3)\n"
"HAZARD_TYPE_LAVA_FLOOR=1\n" "HAZARD_TYPE_LAVA_FLOOR=1\n"
"HAZARD_TYPE_LAVA_WALL=2\n" "HAZARD_TYPE_LAVA_WALL=2\n"

View file

@ -36485,6 +36485,59 @@ int smlua_func_load_object_collision_model(UNUSED lua_State* L) {
return 1; 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) { int smlua_func_obj_get_surface_from_index(lua_State* L) {
if (L == NULL) { return 0; } if (L == NULL) { return 0; }
@ -38657,6 +38710,9 @@ void smlua_bind_functions_autogen(void) {
// surface_load.h // surface_load.h
smlua_bind_function(L, "load_object_collision_model", smlua_func_load_object_collision_model); 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, "obj_get_surface_from_index", smlua_func_obj_get_surface_from_index);
smlua_bind_function(L, "surface_has_force", smlua_func_surface_has_force); smlua_bind_function(L, "surface_has_force", smlua_func_surface_has_force);

View file

@ -69,5 +69,6 @@ void smlua_free(void *ptr, u16 lot);
static inline void smlua_free_##name(void *ptr) { smlua_free(ptr, lot); } static inline void smlua_free_##name(void *ptr) { smlua_free(ptr, lot); }
smlua_free_lot(surface, LOT_SURFACE); smlua_free_lot(surface, LOT_SURFACE);
smlua_free_lot(soc, LOT_STATICOBJECTCOLLISION);
#endif #endif