Add dynamic object limit

This commit is contained in:
Sunketchupm 2026-03-13 03:31:50 -04:00
parent 006fc1dcd2
commit 0f07bb9d2d
26 changed files with 260 additions and 71 deletions

View file

@ -35,6 +35,7 @@ in_files = [
"src/game/player_palette.h",
"src/engine/graph_node.h",
"include/PR/gbi.h",
"src/game/object_list_processor.h",
]
out_filename_c = 'src/pc/lua/smlua_cobject_autogen.c'

View file

@ -6668,7 +6668,10 @@ TIME_STOP_MARIO_OPENED_DOOR = (1 << 5)
TIME_STOP_ACTIVE = (1 << 6)
--- @type integer
OBJECT_POOL_CAPACITY = 1200
OBJECT_POOL_CAPACITY = 0xFFFFFFFF
--- @type integer
OBJECT_POOL_NODE_CAPACITY = 256
OBJ_LIST_PLAYER = 0 --- @type ObjectList
OBJ_LIST_EXT = 1 --- @type ObjectList

View file

@ -12124,6 +12124,12 @@ function obj_anim_skip_interpolation(o)
-- ...
end
--- @return integer
--- Gets the amount of objects in this area
function obj_get_count()
-- ...
end
--- Resets every modified dialog back to vanilla
function smlua_text_utils_reset_all()
-- ...

View file

@ -1282,6 +1282,11 @@
--- @field public overridePaletteIndex integer
--- @field public overridePaletteIndexLp integer
--- @class NumTimesCalled
--- @field public floor integer
--- @field public ceil integer
--- @field public wall integer
--- @class Object
--- @field public header ObjectNode
--- @field public prevObj Object
@ -2062,6 +2067,12 @@
--- @field public gfx GraphNodeObject
--- @field public next ObjectNode
--- @field public prev ObjectNode
--- @field public pool ObjectPoolNode
--- @class ObjectPoolNode
--- @field public pool Object[]
--- @field public freeList ObjectNode
--- @field public next ObjectPoolNode
--- @class ObjectWarpNode
--- @field public node WarpNode

View file

@ -2907,6 +2907,7 @@
- TIME_STOP_MARIO_OPENED_DOOR
- TIME_STOP_ACTIVE
- OBJECT_POOL_CAPACITY
- OBJECT_POOL_NODE_CAPACITY
### [enum ObjectList](#ObjectList)
| Identifier | Value |

View file

@ -3622,6 +3622,27 @@ Skips animation interpolation for a frame
<br />
## [obj_get_count](#obj_get_count)
### Description
Gets the amount of objects in this area
### Lua Example
`local integerValue = obj_get_count()`
### Parameters
- None
### Returns
- `integer`
### C Prototype
`u32 obj_get_count(void);`
[:arrow_up_small:](#)
<br />
---
# functions from smlua_text_utils.h

View file

@ -2143,6 +2143,7 @@
- [set_whirlpools](functions-7.md#set_whirlpools)
- [obj_skip_interpolation](functions-7.md#obj_skip_interpolation)
- [obj_anim_skip_interpolation](functions-7.md#obj_anim_skip_interpolation)
- [obj_get_count](functions-7.md#obj_get_count)
<br />

View file

@ -66,9 +66,11 @@
- [ModFsFile](#ModFsFile)
- [NametagsSettings](#NametagsSettings)
- [NetworkPlayer](#NetworkPlayer)
- [NumTimesCalled](#NumTimesCalled)
- [Object](#Object)
- [ObjectHitbox](#ObjectHitbox)
- [ObjectNode](#ObjectNode)
- [ObjectPoolNode](#ObjectPoolNode)
- [ObjectWarpNode](#ObjectWarpNode)
- [Painting](#Painting)
- [PaintingValues](#PaintingValues)
@ -1869,6 +1871,18 @@
<br />
## [NumTimesCalled](#NumTimesCalled)
| Field | Type | Access |
| ----- | ---- | ------ |
| floor | `integer` | |
| ceil | `integer` | |
| wall | `integer` | |
[:arrow_up_small:](#)
<br />
## [Object](#Object)
| Field | Type | Access |
@ -2674,6 +2688,19 @@
| gfx | [GraphNodeObject](structs.md#GraphNodeObject) | read-only |
| next | [ObjectNode](structs.md#ObjectNode) | read-only |
| prev | [ObjectNode](structs.md#ObjectNode) | read-only |
| pool | [ObjectPoolNode](structs.md#ObjectPoolNode) | |
[:arrow_up_small:](#)
<br />
## [ObjectPoolNode](#ObjectPoolNode)
| Field | Type | Access |
| ----- | ---- | ------ |
| pool | `Array` <`Object`> | read-only |
| freeList | [ObjectNode](structs.md#ObjectNode) | read-only |
| next | [ObjectPoolNode](structs.md#ObjectPoolNode) | |
[:arrow_up_small:](#)

View file

@ -232,6 +232,7 @@ struct ObjectNode
struct GraphNodeObject gfx;
struct ObjectNode *next;
struct ObjectNode *prev;
struct ObjectPoolNode* pool;
};
// NOTE: Since ObjectNode is the first member of Object, it is difficult to determine

View file

@ -644,11 +644,11 @@ void clear_dynamic_surfaces(void) {
clear_spatial_partition(&gDynamicSurfacePartition[0][0]);
for (u16 i = 0; i < OBJECT_POOL_CAPACITY; i++) {
struct Object *obj = &gObjectPool[i];
traverse_object_pools(
struct Object *obj = &node->pool[i];
obj->firstSurface = 0;
obj->numSurfaces = 0;
}
)
}
}

View file

@ -12,14 +12,16 @@ void bhv_object_bubble_loop(void) {
f32 bubbleY = o->oPosY;
if (bubbleY > waterY) {
if (gFreeObjectList.next) {
bubbleSplash = spawn_object_at_origin(o, 0, MODEL_SMALL_WATER_SPLASH, bhvBubbleSplash);
if (bubbleSplash != NULL) {
bubbleSplash->oPosX = o->oPosX;
bubbleSplash->oPosY = bubbleY + 5.0f;
bubbleSplash->oPosZ = o->oPosZ;
traverse_object_pools(
if (node != NULL && node->freeList.next != NULL) {
bubbleSplash = spawn_object_at_origin(o, 0, MODEL_SMALL_WATER_SPLASH, bhvBubbleSplash);
if (bubbleSplash != NULL) {
bubbleSplash->oPosX = o->oPosX;
bubbleSplash->oPosY = bubbleY + 5.0f;
bubbleSplash->oPosZ = o->oPosZ;
}
}
}
)
o->activeFlags = ACTIVE_FLAG_DEACTIVATED;
}

View file

@ -16,8 +16,8 @@ void bhv_tree_snow_or_leaf_loop(void) {
obj_mark_for_deletion(o);
if (o->oTimer > 100)
obj_mark_for_deletion(o);
if (gPrevFrameObjectCount > (OBJECT_POOL_CAPACITY * 212 / 240))
obj_mark_for_deletion(o);
//if (gPrevFrameObjectCount > (OBJECT_POOL_CAPACITY * 212 / 240))
// obj_mark_for_deletion(o);
o->oFaceAnglePitch += o->oAngleVelPitch;
o->oFaceAngleRoll += o->oAngleVelRoll;
o->oVelY += -3.0f;

View file

@ -63,8 +63,11 @@ void bhv_small_water_wave_loop(void) {
if (o->oPosY > sp1C) {
o->activeFlags = ACTIVE_FLAG_DEACTIVATED;
o->oPosY += 5.0f;
if (gFreeObjectList.next != NULL)
spawn_object(o, MODEL_SMALL_WATER_SPLASH, bhvObjectWaterSplash);
traverse_object_pools(
if (node != NULL && node->freeList.next != NULL) {
spawn_object(o, MODEL_SMALL_WATER_SPLASH, bhvObjectWaterSplash);
}
)
}
if (o->oInteractStatus & INT_STATUS_INTERACTED)
obj_mark_for_deletion(o);

View file

@ -716,15 +716,17 @@ struct Object *try_to_spawn_object(s16 offsetY, f32 scale, struct Object *parent
const BehaviorScript *behavior) {
struct Object *obj;
if (gFreeObjectList.next != NULL) {
traverse_object_pools(
if (node == NULL || node->freeList.next == NULL) { return NULL; }
obj = spawn_object(parent, model, behavior);
if (obj == NULL) { return NULL; }
obj->oPosY += offsetY;
obj_scale(obj, scale);
return obj;
} else {
return NULL;
}
)
return NULL;
}
struct Object *spawn_object_with_scale(struct Object *parent, s32 model, const BehaviorScript *behavior, f32 scale) {
@ -2547,16 +2549,16 @@ void cur_obj_spawn_particles(struct SpawnParticlesInfo *info) {
s32 numParticles = info->count;
// If there are a lot of objects already, limit the number of particles
if (gPrevFrameObjectCount > (OBJECT_POOL_CAPACITY * 150 / 240) && numParticles > 10) {
/*if (gPrevFrameObjectCount > (OBJECT_POOL_CAPACITY * 150 / 240) && numParticles > 10) {
numParticles = 10;
}
}*/
// We're close to running out of object slots, so don't spawn particles at
// all
if (gPrevFrameObjectCount > (OBJECT_POOL_CAPACITY * 210 / 240)) {
/*if (gPrevFrameObjectCount > (OBJECT_POOL_CAPACITY * 210 / 240)) {
numParticles = 0;
}
}*/
for (i = 0; i < numParticles; i++) {
scale = random_float() * (info->sizeRange * 0.1f) + info->sizeBase * 0.1f;

View file

@ -71,7 +71,7 @@ u32 gTimeStopState;
/**
* The pool that objects are allocated from.
*/
struct Object gObjectPool[OBJECT_POOL_CAPACITY];
struct ObjectPoolNode gObjectPool = { 0 };
/**
* A special object whose purpose is to act as a parent for macro objects.
@ -87,8 +87,9 @@ struct ObjectNode *gObjectLists;
/**
* A singly linked list of available slots in the object pool.
* Now stored in gObjectPool.
*/
struct ObjectNode gFreeObjectList;
//struct ObjectNode gFreeObjectList;
/**
* The object representing Mario.
@ -568,11 +569,20 @@ void spawn_objects_from_info(UNUSED s32 unused, struct SpawnInfo *spawnInfo) {
}
}
void free_pool_nodes(struct ObjectPoolNode* node) {
if (node->next == NULL) {
free(node);
return;
}
free_pool_nodes(node->next);
free(node);
}
/**
* Clear objects, dynamic surfaces, and some miscellaneous level data used by objects.
*/
void clear_objects(void) {
s32 i;
sync_objects_clear();
gTHIWaterDrained = 0;
gTimeStopState = 0;
@ -586,19 +596,24 @@ void clear_objects(void) {
gMarioStates[i].currentRoom = 0;
}
for (i = 0; i < 60; i++) {
for (s32 i = 0; i < 60; i++) {
gDoorAdjacentRooms[i][0] = 0;
gDoorAdjacentRooms[i][1] = 0;
}
debug_unknown_level_select_check();
init_free_object_list();
if (gObjectPool.next != NULL) {
free_pool_nodes(gObjectPool.next);
gObjectPool.next = NULL;
}
init_free_object_list(&gObjectPool);
clear_object_lists(gObjectListArray);
for (i = 0; i < OBJECT_POOL_CAPACITY; i++) {
gObjectPool[i].activeFlags = ACTIVE_FLAG_DEACTIVATED;
geo_reset_object_node(&gObjectPool[i].header.gfx);
for (u32 i = 0; i < OBJECT_POOL_NODE_CAPACITY; i++) {
gObjectPool.pool[i].activeFlags = ACTIVE_FLAG_DEACTIVATED;
geo_reset_object_node(&gObjectPool.pool[i].header.gfx);
}
gObjectLists = gObjectListArray;
@ -607,13 +622,26 @@ void clear_objects(void) {
geo_clear_interp_data();
}
void reinit_objects(struct ObjectPoolNode* node) {
init_free_object_list(node);
for (u32 i = 0; i < OBJECT_POOL_NODE_CAPACITY; i++) {
node->pool[i].activeFlags = ACTIVE_FLAG_DEACTIVATED;
geo_reset_object_node(&node->pool[i].header.gfx);
}
clear_dynamic_surfaces();
geo_clear_interp_data();
}
/**
* Update spawner and surface objects.
*/
void update_terrain_objects(void) {
gObjectCounter = update_objects_in_list(&gObjectLists[OBJ_LIST_SPAWNER]);
//! This was meant to be +=
gObjectCounter = update_objects_in_list(&gObjectLists[OBJ_LIST_SURFACE]);
// Since this counter does not affect gameplay at all, fix the bug
gObjectCounter += update_objects_in_list(&gObjectLists[OBJ_LIST_SURFACE]);
}
/**

View file

@ -22,8 +22,15 @@
/**
* The maximum number of objects that can be loaded at once.
* Kept for compatibility, but is unused.
*/
#define OBJECT_POOL_CAPACITY 1200
#define OBJECT_POOL_CAPACITY 0xFFFFFFFF
/**
* The maximum number of objects that can be in a single pool node.
* A higher number might be better for less fragmentation.
* ! Can't seem to go above 256 without crashing in geo_reset_object_node()...
*/
#define OBJECT_POOL_NODE_CAPACITY 256
/**
* Every object is categorized into an object list, which controls the order
@ -58,6 +65,18 @@ enum ObjectList
NUM_OBJ_LISTS
};
struct ObjectPoolNode {
struct Object pool[OBJECT_POOL_NODE_CAPACITY];
struct ObjectNode freeList;
struct ObjectPoolNode* next;
};
#define traverse_object_pools(statements) \
for (struct ObjectPoolNode* node = &gObjectPool; node != NULL; node = node->next) { \
for (u32 i = 0; i < OBJECT_POOL_NODE_CAPACITY; i++) { \
statements \
} \
} \
extern struct ObjectNode gObjectListArray[];
@ -79,10 +98,10 @@ extern s16 gDebugInfo[][8];
extern s16 gDebugInfoOverwrite[][8];
extern u32 gTimeStopState;
extern struct Object gObjectPool[];
extern struct ObjectPoolNode gObjectPool;
extern struct Object gMacroObjectDefaultParent;
extern struct ObjectNode *gObjectLists;
extern struct ObjectNode gFreeObjectList;
//extern struct ObjectNode gFreeObjectList;
extern struct Object *gMarioObject;
extern struct Object *gMarioObjects[];
@ -118,6 +137,7 @@ void set_object_respawn_info_bits(struct Object *obj, u8 bits);
void unload_objects_from_area(UNUSED s32 unused, s32 areaIndex);
void spawn_objects_from_info(UNUSED s32 unused, struct SpawnInfo *spawnInfo);
void clear_objects(void);
void reinit_objects(struct ObjectPoolNode* node);
void update_objects(UNUSED s32 unused);

View file

@ -81,17 +81,22 @@ struct LinkedList *unused_try_allocate(struct LinkedList *destList,
* to the end of destList (doubly linked). Return the object, or NULL if
* freeList is empty.
*/
struct Object *try_allocate_object(struct ObjectNode *destList, struct ObjectNode *freeList) {
struct Object* try_allocate_object(struct ObjectNode* destList, struct ObjectPoolNode* node) {
struct ObjectNode *nextObj = NULL;
if (destList == NULL || freeList == NULL) {
fprintf(stderr, "FATAL ERROR: Failed to try and allocate a object because either the destList %p or freeList %p was NULL!\n", destList, freeList);
if (node == NULL) {
fprintf(stderr, "FATAL ERROR: Failed to try and allocate an object because the pool %p was NULL!\n", node);
return NULL;
}
if ((nextObj = freeList->next) != NULL) {
if (destList == NULL) {
fprintf(stderr, "FATAL ERROR: Failed to try and allocate an object because the destList %p was NULL!\n", destList);
return NULL;
}
if ((nextObj = node->freeList.next) != NULL) {
// Remove from free list
freeList->next = nextObj->next;
node->freeList.next = nextObj->next;
// Insert at end of destination list
nextObj->prev = destList->prev;
@ -103,7 +108,13 @@ struct Object *try_allocate_object(struct ObjectNode *destList, struct ObjectNod
}
destList->prev = nextObj;
} else {
return NULL;
if (node->next != NULL) {
return try_allocate_object(destList, node->next);
}
node->next = (struct ObjectPoolNode*)calloc(1, sizeof(struct ObjectPoolNode));
reinit_objects(node->next);
return try_allocate_object(destList, node->next);
}
geo_remove_child(&nextObj->gfx.node);
@ -138,35 +149,40 @@ void unused_deallocate(struct LinkedList *freeList, struct LinkedList *node) {
* Remove the given object from the object list that it's currently in, and
* insert it at the beginning of the free list (singly linked).
*/
static void deallocate_object(struct ObjectNode *freeList, struct ObjectNode *obj) {
if (!obj || !freeList) { return; }
static void deallocate_object(struct ObjectNode *obj) {
if (obj == NULL) { return; }
// Remove from object list
if (obj->next) { obj->next->prev = obj->prev; }
if (obj->prev) { obj->prev->next = obj->next; }
// Insert at beginning of free list
obj->next = freeList->next;
freeList->next = obj;
for (struct ObjectPoolNode* node = &gObjectPool; node != NULL; node = node->next) {
if (node->freeList.next == NULL) { continue; }
obj->next = node->freeList.next;
node->freeList.next = obj;
}
}
/**
* Add every object in the pool to the free object list.
*/
void init_free_object_list(void) {
s32 poolLength = OBJECT_POOL_CAPACITY;
void init_free_object_list(struct ObjectPoolNode* node) {
if (node == NULL) { return; }
// Add the first object in the pool to the free list
struct Object *obj = &gObjectPool[0];
gFreeObjectList.next = (struct ObjectNode *) obj;
struct Object *obj = &node->pool[0];
node->freeList.next = (struct ObjectNode*)obj;
// Link each object in the pool to the following object
for (s32 i = 0; i < poolLength - 1; i++) {
for (s32 i = 0; i < OBJECT_POOL_NODE_CAPACITY - 1; i++) {
obj->header.next = &(obj + 1)->header;
obj++;
}
// End the list
obj->header.next = NULL;
// Attach pool
obj->header.pool = node;
}
/**
@ -247,7 +263,7 @@ void unload_object(struct Object *obj) {
smlua_call_event_hooks(HOOK_ON_OBJECT_UNLOAD, obj);
deallocate_object(&gFreeObjectList, &obj->header);
deallocate_object(&obj->header);
}
/**
@ -257,7 +273,7 @@ void unload_object(struct Object *obj) {
*/
struct Object *allocate_object(struct ObjectNode *objList) {
if (!objList) { return NULL; }
struct Object *obj = try_allocate_object(objList, &gFreeObjectList);
struct Object *obj = try_allocate_object(objList, &gObjectPool);
// The object list is full if the newly created pointer is NULL.
// If this happens, we first attempt to unload unimportant objects
@ -273,7 +289,7 @@ struct Object *allocate_object(struct ObjectNode *objList) {
} else {
// If an unimportant object does exist, unload it and take its slot.
unload_object(unimportantObj);
obj = try_allocate_object(objList, &gFreeObjectList);
obj = try_allocate_object(objList, &gObjectPool);
if (gCurrentObject == obj) {
//! Uh oh, the unimportant object was in the middle of
// updating! This could cause some interesting logic errors,

View file

@ -3,7 +3,7 @@
#include "types.h"
void init_free_object_list(void);
void init_free_object_list(struct ObjectPoolNode* node);
void clear_object_lists(struct ObjectNode *objLists);
void unload_object(struct Object *obj);
struct Object *create_object(const BehaviorScript *bhvScript);

View file

@ -29,6 +29,7 @@
#include "src/game/player_palette.h"
#include "src/engine/graph_node.h"
#include "include/PR/gbi.h"
#include "src/game/object_list_processor.h"
#include "include/object_fields.h"
@ -1580,6 +1581,13 @@ static struct LuaObjectField sNetworkPlayerFields[LUA_NETWORK_PLAYER_FIELD_COUNT
{ "type", LVT_U8, offsetof(struct NetworkPlayer, type), true, LOT_NONE, 1, sizeof(u8) },
};
#define LUA_NUM_TIMES_CALLED_FIELD_COUNT 3
static struct LuaObjectField sNumTimesCalledFields[LUA_NUM_TIMES_CALLED_FIELD_COUNT] = {
{ "ceil", LVT_S16, offsetof(struct NumTimesCalled, ceil), false, LOT_NONE, 1, sizeof(s16) },
{ "floor", LVT_S16, offsetof(struct NumTimesCalled, floor), false, LOT_NONE, 1, sizeof(s16) },
{ "wall", LVT_S16, offsetof(struct NumTimesCalled, wall), false, LOT_NONE, 1, sizeof(s16) },
};
#define LUA_OBJECT_FIELD_COUNT 763
static struct LuaObjectField sObjectFields[LUA_OBJECT_FIELD_COUNT] = {
{ "activeFlags", LVT_S16, offsetof(struct Object, activeFlags), false, LOT_NONE, 1, sizeof(s16) },
@ -2374,11 +2382,19 @@ static struct LuaObjectField sObjectHitboxFields[LUA_OBJECT_HITBOX_FIELD_COUNT]
{ "radius", LVT_S16, offsetof(struct ObjectHitbox, radius), false, LOT_NONE, 1, sizeof(s16) },
};
#define LUA_OBJECT_NODE_FIELD_COUNT 3
#define LUA_OBJECT_NODE_FIELD_COUNT 4
static struct LuaObjectField sObjectNodeFields[LUA_OBJECT_NODE_FIELD_COUNT] = {
{ "gfx", LVT_COBJECT, offsetof(struct ObjectNode, gfx), true, LOT_GRAPHNODEOBJECT, 1, sizeof(struct GraphNodeObject) },
{ "next", LVT_COBJECT_P, offsetof(struct ObjectNode, next), true, LOT_OBJECTNODE, 1, sizeof(struct ObjectNode*) },
{ "prev", LVT_COBJECT_P, offsetof(struct ObjectNode, prev), true, LOT_OBJECTNODE, 1, sizeof(struct ObjectNode*) },
{ "gfx", LVT_COBJECT, offsetof(struct ObjectNode, gfx), true, LOT_GRAPHNODEOBJECT, 1, sizeof(struct GraphNodeObject) },
{ "next", LVT_COBJECT_P, offsetof(struct ObjectNode, next), true, LOT_OBJECTNODE, 1, sizeof(struct ObjectNode*) },
{ "pool", LVT_COBJECT_P, offsetof(struct ObjectNode, pool), false, LOT_OBJECTPOOLNODE, 1, sizeof(struct ObjectPoolNode*) },
{ "prev", LVT_COBJECT_P, offsetof(struct ObjectNode, prev), true, LOT_OBJECTNODE, 1, sizeof(struct ObjectNode*) },
};
#define LUA_OBJECT_POOL_NODE_FIELD_COUNT 3
static struct LuaObjectField sObjectPoolNodeFields[LUA_OBJECT_POOL_NODE_FIELD_COUNT] = {
{ "freeList", LVT_COBJECT, offsetof(struct ObjectPoolNode, freeList), true, LOT_OBJECTNODE, 1, sizeof(struct ObjectNode) },
{ "next", LVT_COBJECT_P, offsetof(struct ObjectPoolNode, next), false, LOT_OBJECTPOOLNODE, 1, sizeof(struct ObjectPoolNode*) },
{ "pool", LVT_COBJECT, offsetof(struct ObjectPoolNode, pool), true, LOT_OBJECT, OBJECT_POOL_NODE_CAPACITY, sizeof(struct Object) },
};
#define LUA_OBJECT_WARP_NODE_FIELD_COUNT 3
@ -2736,9 +2752,11 @@ struct LuaObjectTable sLuaObjectAutogenTable[LOT_AUTOGEN_MAX - LOT_AUTOGEN_MIN]
{ LOT_MODFSFILE, sModFsFileFields, LUA_MOD_FS_FILE_FIELD_COUNT },
{ LOT_NAMETAGSSETTINGS, sNametagsSettingsFields, LUA_NAMETAGS_SETTINGS_FIELD_COUNT },
{ LOT_NETWORKPLAYER, sNetworkPlayerFields, LUA_NETWORK_PLAYER_FIELD_COUNT },
{ LOT_NUMTIMESCALLED, sNumTimesCalledFields, LUA_NUM_TIMES_CALLED_FIELD_COUNT },
{ LOT_OBJECT, sObjectFields, LUA_OBJECT_FIELD_COUNT },
{ LOT_OBJECTHITBOX, sObjectHitboxFields, LUA_OBJECT_HITBOX_FIELD_COUNT },
{ LOT_OBJECTNODE, sObjectNodeFields, LUA_OBJECT_NODE_FIELD_COUNT },
{ LOT_OBJECTPOOLNODE, sObjectPoolNodeFields, LUA_OBJECT_POOL_NODE_FIELD_COUNT },
{ LOT_OBJECTWARPNODE, sObjectWarpNodeFields, LUA_OBJECT_WARP_NODE_FIELD_COUNT },
{ LOT_PAINTING, sPaintingFields, LUA_PAINTING_FIELD_COUNT },
{ LOT_PAINTINGVALUES, sPaintingValuesFields, LUA_PAINTING_VALUES_FIELD_COUNT },
@ -2841,9 +2859,11 @@ const char *sLuaLotNames[] = {
[LOT_MODFSFILE] = "ModFsFile",
[LOT_NAMETAGSSETTINGS] = "NametagsSettings",
[LOT_NETWORKPLAYER] = "NetworkPlayer",
[LOT_NUMTIMESCALLED] = "NumTimesCalled",
[LOT_OBJECT] = "Object",
[LOT_OBJECTHITBOX] = "ObjectHitbox",
[LOT_OBJECTNODE] = "ObjectNode",
[LOT_OBJECTPOOLNODE] = "ObjectPoolNode",
[LOT_OBJECTWARPNODE] = "ObjectWarpNode",
[LOT_PAINTING] = "Painting",
[LOT_PAINTINGVALUES] = "PaintingValues",

View file

@ -86,9 +86,11 @@ enum LuaObjectAutogenType {
LOT_MODFSFILE,
LOT_NAMETAGSSETTINGS,
LOT_NETWORKPLAYER,
LOT_NUMTIMESCALLED,
LOT_OBJECT,
LOT_OBJECTHITBOX,
LOT_OBJECTNODE,
LOT_OBJECTPOOLNODE,
LOT_OBJECTWARPNODE,
LOT_PAINTING,
LOT_PAINTINGVALUES,

View file

@ -2976,7 +2976,8 @@ char gSmluaConstants[] = ""
"TIME_STOP_ALL_OBJECTS=(1 << 4)\n"
"TIME_STOP_MARIO_OPENED_DOOR=(1 << 5)\n"
"TIME_STOP_ACTIVE=(1 << 6)\n"
"OBJECT_POOL_CAPACITY=1200\n"
"OBJECT_POOL_CAPACITY=0xFFFFFFFF\n"
"OBJECT_POOL_NODE_CAPACITY=256\n"
"OBJ_LIST_PLAYER=0\n"
"OBJ_LIST_EXT=1\n"
"OBJ_LIST_DESTRUCTIVE=2\n"

View file

@ -35485,6 +35485,21 @@ int smlua_func_obj_anim_skip_interpolation(lua_State* L) {
return 1;
}
int smlua_func_obj_get_count(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", "obj_get_count", 0, top);
return 0;
}
lua_pushinteger(L, obj_get_count());
return 1;
}
////////////////////////
// smlua_text_utils.h //
////////////////////////
@ -38753,6 +38768,7 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "set_whirlpools", smlua_func_set_whirlpools);
smlua_bind_function(L, "obj_skip_interpolation", smlua_func_obj_skip_interpolation);
smlua_bind_function(L, "obj_anim_skip_interpolation", smlua_func_obj_anim_skip_interpolation);
smlua_bind_function(L, "obj_get_count", smlua_func_obj_get_count);
// smlua_text_utils.h
smlua_bind_function(L, "smlua_text_utils_reset_all", smlua_func_smlua_text_utils_reset_all);

View file

@ -530,6 +530,10 @@ void obj_anim_skip_interpolation(struct Object *o) {
if (o) { o->header.gfx.animInfo.prevAnimFrameTimestamp = 0; }
}
u32 obj_get_count(void) {
return gObjectCounter;
}
#ifdef DEVELOPMENT
void obj_randomize(struct Object* o) {
if (!o) { return; }

View file

@ -160,4 +160,7 @@ void obj_skip_interpolation(struct Object *o);
/* |description|Skips animation interpolation for a frame|descriptionEnd| */
void obj_anim_skip_interpolation(struct Object *o);
/* |description|Gets the amount of objects in this area|descriptionEnd| */
u32 obj_get_count(void);
#endif

View file

@ -18,10 +18,10 @@
// TODO: move to common utility location
static struct Object* get_object_matching_respawn_info(s16* respawnInfo) {
for (s32 i = 0; i < OBJECT_POOL_CAPACITY; i++) {
struct Object* o = &gObjectPool[i];
traverse_object_pools(
struct Object* o = &node->pool[i];
if (o->respawnInfo == respawnInfo) { return o; }
}
)
return NULL;
}
@ -196,19 +196,19 @@ void network_receive_level_macro(struct Packet* p) {
o->oCoinUnkF4 = (o->oBehParams >> 8) & 0xFF;
u8 childIndex = 0;
for (s32 i = 0; i < OBJECT_POOL_CAPACITY; i++) {
struct Object* o2 = &gObjectPool[i];
traverse_object_pools(
struct Object* o2 = &node->pool[i];
if (o2->parentObj != o) { continue; }
if (o2 == o) { continue; }
if (o2->behavior != smlua_override_behavior(bhvCoinFormationSpawn) && o2->behavior != smlua_override_behavior(bhvYellowCoin)) { continue; }
if (o->oCoinUnkF4 & (1 << childIndex++)) {
obj_mark_for_deletion(o2);
}
}
)
LOG_INFO("rx macro special: coin formation");
} else if (behavior == bhvGoombaTripletSpawner) {
for (s32 i = 0; i < OBJECT_POOL_CAPACITY; i++) {
struct Object* o2 = &gObjectPool[i];
traverse_object_pools(
struct Object* o2 = &node->pool[i];
if (o2->parentObj != o) { continue; }
if (o2 == o) { continue; }
if (o2->behavior != smlua_override_behavior(bhvGoomba)) { continue; }
@ -222,7 +222,7 @@ void network_receive_level_macro(struct Packet* p) {
obj_mark_for_deletion(o2);
gCurrentObject = prevObject;
}
}
)
LOG_INFO("rx macro special: goomba triplet");
} else {
o->oBehParams = (((*respawnInfo) & 0x00FF) << 16) + ((*respawnInfo) & 0xFF00);

View file

@ -16,10 +16,10 @@
// TODO: move to common utility location
static struct Object* get_object_matching_respawn_info(u32* respawnInfo) {
for (s32 i = 0; i < OBJECT_POOL_CAPACITY; i++) {
struct Object* o = &gObjectPool[i];
traverse_object_pools(
struct Object* o = &node->pool[i];
if (o->respawnInfo == respawnInfo) { return o; }
}
)
return NULL;
}