From 0f07bb9d2d0bebf6de9bbd63f6be039992c9f458 Mon Sep 17 00:00:00 2001 From: Sunketchupm Date: Fri, 13 Mar 2026 03:31:50 -0400 Subject: [PATCH] Add dynamic object limit --- autogen/convert_structs.py | 1 + autogen/lua_definitions/constants.lua | 5 +- autogen/lua_definitions/functions.lua | 6 +++ autogen/lua_definitions/structs.lua | 11 ++++ docs/lua/constants.md | 1 + docs/lua/functions-7.md | 21 ++++++++ docs/lua/functions.md | 1 + docs/lua/structs.md | 27 ++++++++++ include/types.h | 1 + src/engine/surface_load.c | 6 +-- src/game/behaviors/bubble.inc.c | 16 +++--- src/game/behaviors/tree_particles.inc.c | 4 +- src/game/behaviors/water_objs.inc.c | 7 ++- src/game/object_helpers.c | 18 ++++--- src/game/object_list_processor.c | 46 ++++++++++++---- src/game/object_list_processor.h | 26 ++++++++-- src/game/spawn_object.c | 52 ++++++++++++------- src/game/spawn_object.h | 2 +- src/pc/lua/smlua_cobject_autogen.c | 28 ++++++++-- src/pc/lua/smlua_cobject_autogen.h | 2 + src/pc/lua/smlua_constants_autogen.c | 3 +- src/pc/lua/smlua_functions_autogen.c | 16 ++++++ src/pc/lua/utils/smlua_obj_utils.c | 4 ++ src/pc/lua/utils/smlua_obj_utils.h | 3 ++ src/pc/network/packets/packet_level_macro.c | 18 +++---- .../network/packets/packet_level_spawn_info.c | 6 +-- 26 files changed, 260 insertions(+), 71 deletions(-) diff --git a/autogen/convert_structs.py b/autogen/convert_structs.py index 3a88390ec..657f23d74 100644 --- a/autogen/convert_structs.py +++ b/autogen/convert_structs.py @@ -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' diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua index 8e160c5d4..adde37875 100644 --- a/autogen/lua_definitions/constants.lua +++ b/autogen/lua_definitions/constants.lua @@ -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 diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 746a8f4c4..0778f6e73 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -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() -- ... diff --git a/autogen/lua_definitions/structs.lua b/autogen/lua_definitions/structs.lua index 5441e7424..5728a924e 100644 --- a/autogen/lua_definitions/structs.lua +++ b/autogen/lua_definitions/structs.lua @@ -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 diff --git a/docs/lua/constants.md b/docs/lua/constants.md index 0c92edac9..d10c012f7 100644 --- a/docs/lua/constants.md +++ b/docs/lua/constants.md @@ -2907,6 +2907,7 @@ - TIME_STOP_MARIO_OPENED_DOOR - TIME_STOP_ACTIVE - OBJECT_POOL_CAPACITY +- OBJECT_POOL_NODE_CAPACITY ### [enum ObjectList](#ObjectList) | Identifier | Value | diff --git a/docs/lua/functions-7.md b/docs/lua/functions-7.md index 207edbb6f..d85dadc6f 100644 --- a/docs/lua/functions-7.md +++ b/docs/lua/functions-7.md @@ -3622,6 +3622,27 @@ Skips animation interpolation for a frame
+## [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:](#) + +
+ --- # functions from smlua_text_utils.h diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 4076375df..5357a0d72 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -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)
diff --git a/docs/lua/structs.md b/docs/lua/structs.md index 79c6d19ff..4e229277e 100644 --- a/docs/lua/structs.md +++ b/docs/lua/structs.md @@ -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 @@
+## [NumTimesCalled](#NumTimesCalled) + +| Field | Type | Access | +| ----- | ---- | ------ | +| floor | `integer` | | +| ceil | `integer` | | +| wall | `integer` | | + +[:arrow_up_small:](#) + +
+ ## [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:](#) + +
+ +## [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:](#) diff --git a/include/types.h b/include/types.h index ea64ff19b..6335f6b57 100644 --- a/include/types.h +++ b/include/types.h @@ -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 diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c index 345a73202..58d0b573f 100644 --- a/src/engine/surface_load.c +++ b/src/engine/surface_load.c @@ -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; - } + ) } } diff --git a/src/game/behaviors/bubble.inc.c b/src/game/behaviors/bubble.inc.c index 626aefd0a..550859d8f 100644 --- a/src/game/behaviors/bubble.inc.c +++ b/src/game/behaviors/bubble.inc.c @@ -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; } diff --git a/src/game/behaviors/tree_particles.inc.c b/src/game/behaviors/tree_particles.inc.c index aecdb1a45..3628e2c0a 100644 --- a/src/game/behaviors/tree_particles.inc.c +++ b/src/game/behaviors/tree_particles.inc.c @@ -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; diff --git a/src/game/behaviors/water_objs.inc.c b/src/game/behaviors/water_objs.inc.c index e829ebf20..336919845 100644 --- a/src/game/behaviors/water_objs.inc.c +++ b/src/game/behaviors/water_objs.inc.c @@ -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); diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index f0bf4d162..364657d76 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -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; diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index 1752ae7b4..de095c329 100644 --- a/src/game/object_list_processor.c +++ b/src/game/object_list_processor.c @@ -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]); } /** diff --git a/src/game/object_list_processor.h b/src/game/object_list_processor.h index 98cb25a95..07f33ee23 100644 --- a/src/game/object_list_processor.h +++ b/src/game/object_list_processor.h @@ -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); diff --git a/src/game/spawn_object.c b/src/game/spawn_object.c index 9972d5535..99e43b2e8 100644 --- a/src/game/spawn_object.c +++ b/src/game/spawn_object.c @@ -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, diff --git a/src/game/spawn_object.h b/src/game/spawn_object.h index acb9cd038..145609332 100644 --- a/src/game/spawn_object.h +++ b/src/game/spawn_object.h @@ -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); diff --git a/src/pc/lua/smlua_cobject_autogen.c b/src/pc/lua/smlua_cobject_autogen.c index 35a3ce52d..fa625c65a 100644 --- a/src/pc/lua/smlua_cobject_autogen.c +++ b/src/pc/lua/smlua_cobject_autogen.c @@ -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", diff --git a/src/pc/lua/smlua_cobject_autogen.h b/src/pc/lua/smlua_cobject_autogen.h index d034ce9f7..11ea10ab6 100644 --- a/src/pc/lua/smlua_cobject_autogen.h +++ b/src/pc/lua/smlua_cobject_autogen.h @@ -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, diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c index d7ca5a882..4179649f3 100644 --- a/src/pc/lua/smlua_constants_autogen.c +++ b/src/pc/lua/smlua_constants_autogen.c @@ -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" diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index e227a54aa..54e57063a 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -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); diff --git a/src/pc/lua/utils/smlua_obj_utils.c b/src/pc/lua/utils/smlua_obj_utils.c index aa71c422d..e945c8e31 100644 --- a/src/pc/lua/utils/smlua_obj_utils.c +++ b/src/pc/lua/utils/smlua_obj_utils.c @@ -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; } diff --git a/src/pc/lua/utils/smlua_obj_utils.h b/src/pc/lua/utils/smlua_obj_utils.h index 518e3b193..4017fdf1d 100644 --- a/src/pc/lua/utils/smlua_obj_utils.h +++ b/src/pc/lua/utils/smlua_obj_utils.h @@ -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 diff --git a/src/pc/network/packets/packet_level_macro.c b/src/pc/network/packets/packet_level_macro.c index 3cae16a7a..be7e71897 100644 --- a/src/pc/network/packets/packet_level_macro.c +++ b/src/pc/network/packets/packet_level_macro.c @@ -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); diff --git a/src/pc/network/packets/packet_level_spawn_info.c b/src/pc/network/packets/packet_level_spawn_info.c index 816be414b..b6603ded8 100644 --- a/src/pc/network/packets/packet_level_spawn_info.c +++ b/src/pc/network/packets/packet_level_spawn_info.c @@ -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; }