Skip to content

Commit 9ce7748

Browse files
authored
Merge pull request #5039 from Goober5000/object_iteration_fixes
more robust object iteration
2 parents f2fa235 + c2b9354 commit 9ce7748

File tree

3 files changed

+126
-87
lines changed

3 files changed

+126
-87
lines changed

code/object/object.h

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "globalincs/globals.h"
1616
#include "globalincs/pstypes.h"
1717
#include "math/vecmat.h"
18+
#include "object/object.h"
1819
#include "object/object_flags.h"
1920
#include "physics/physics.h"
2021
#include "utils/event.h"
@@ -159,13 +160,30 @@ class object
159160
object& operator= (const object & other); // no implementation
160161
};
161162

163+
extern int Num_objects;
164+
extern object Objects[];
165+
162166
struct object_h {
163167
object *objp;
164168
int sig;
165169

166170
bool IsValid() const {return (objp != NULL && objp->signature == sig && sig > 0);}
167-
object_h(object *in){objp=in; if(objp!=NULL){sig=in->signature;}}
171+
object_h(object *in){objp=in; sig = (in == nullptr) ? -1 : in->signature;}
168172
object_h(){objp=NULL;sig=-1;}
173+
174+
object_h(int objnum)
175+
{
176+
if (objnum >= 0 && objnum < MAX_OBJECTS)
177+
{
178+
objp = &Objects[objnum];
179+
sig = objp->signature;
180+
}
181+
else
182+
{
183+
objp = nullptr;
184+
sig = -1;
185+
}
186+
}
169187
};
170188

171189
// object backup struct used by Fred.
@@ -194,13 +212,10 @@ class checkobject
194212
extern int Object_inited;
195213
extern int Show_waypoints;
196214

197-
// The next signature for the next newly created object. Zero is bogus
198-
extern int Object_next_signature;
199-
extern int Num_objects;
200-
201-
extern object Objects[];
215+
extern int Object_next_signature; // The next signature for the next newly created object. Zero is bogus
202216
extern int Highest_object_index; //highest objnum
203217
extern int Highest_ever_object_index;
218+
204219
extern object obj_free_list;
205220
extern object obj_used_list;
206221
extern object obj_create_list;

code/scripting/api/libs/mission.cpp

Lines changed: 93 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,47 @@ extern TIMESTAMP Game_shudder_time;
8383
extern int Game_shudder_total;
8484
extern float Game_shudder_intensity;
8585

86+
constexpr int COUNT_OBJECTS = -1000;
87+
88+
// Returns the indexth object subclass
89+
template <typename A>
90+
int object_subclass_at_index(A& object_subclass_array, size_t array_size, int index)
91+
{
92+
int count = 0;
93+
94+
for (size_t i = 0; i < array_size; ++i)
95+
{
96+
int objnum = object_subclass_array[i].objnum;
97+
if (objnum < 0 || objnum >= MAX_OBJECTS)
98+
continue;
99+
if (Objects[objnum].flags[Object::Object_Flags::Should_be_dead])
100+
continue;
101+
102+
++count;
103+
104+
if (count == index)
105+
{
106+
return object_subclass_array[i].objnum;
107+
}
108+
}
109+
110+
if (index == COUNT_OBJECTS)
111+
return count;
112+
else
113+
return -1;
114+
}
115+
116+
// Counts the number of indexable objects
117+
template <typename A>
118+
int object_subclass_count(A& object_subclass_array, size_t array_size)
119+
{
120+
return object_subclass_at_index(object_subclass_array, array_size, COUNT_OBJECTS);
121+
}
122+
123+
86124
namespace scripting {
87125
namespace api {
88126

89-
90127
//**********LIBRARY: Mission
91128
ADE_LIB(l_Mission, "Mission", "mn", "Mission library");
92129

@@ -185,12 +222,12 @@ ADE_INDEXER(l_Mission_Asteroids, "number Index", "Gets asteroid", "asteroid", "A
185222
if( !ade_get_args(L, "*i", &idx) ) {
186223
return ade_set_error( L, "o", l_Asteroid.Set( object_h() ) );
187224
}
188-
if( idx > -1 && idx < asteroid_count() ) {
189-
idx--; //Convert from Lua to C, as lua indices start from 1, not 0
190-
return ade_set_args(L, "o", l_Asteroid.Set(object_h(&Objects[Asteroids[idx].objnum])));
191-
}
192225

193-
return ade_set_error(L, "o", l_Asteroid.Set( object_h() ) );
226+
int objnum = -1;
227+
if (idx > 0)
228+
objnum = object_subclass_at_index(Asteroids, MAX_ASTEROIDS, idx);
229+
230+
return ade_set_args(L, "o", l_Asteroid.Set( object_h(objnum) ) );
194231
}
195232

196233
ADE_FUNC(__len, l_Mission_Asteroids, NULL,
@@ -199,7 +236,7 @@ ADE_FUNC(__len, l_Mission_Asteroids, NULL,
199236
"Number of asteroids in the mission, or 0 if asteroids are not enabled")
200237
{
201238
if(Asteroids_enabled) {
202-
return ade_set_args(L, "i", asteroid_count());
239+
return ade_set_args(L, "i", object_subclass_count(Asteroids, MAX_ASTEROIDS));
203240
}
204241
return ade_set_args(L, "i", 0);
205242
}
@@ -383,32 +420,20 @@ ADE_INDEXER(l_Mission_Ships, "number/string IndexOrName", "Gets ship", "ship", "
383420

384421
int idx = ship_name_lookup(name);
385422

386-
if(idx > -1)
423+
if (idx >= 0)
387424
{
388425
return ade_set_args(L, "o", l_Ship.Set(object_h(&Objects[Ships[idx].objnum])));
389426
}
390427
else
391428
{
392429
idx = atoi(name);
393-
if(idx > 0)
394-
{
395-
int count=1;
396430

397-
for(int i = 0; i < MAX_SHIPS; i++)
398-
{
399-
if (Ships[i].objnum < 0 || Objects[Ships[i].objnum].type != OBJ_SHIP)
400-
continue;
401-
402-
if(count == idx) {
403-
return ade_set_args(L, "o", l_Ship.Set(object_h(&Objects[Ships[i].objnum])));
404-
}
431+
int objnum = -1;
432+
if (idx > 0)
433+
objnum = object_subclass_at_index(Ships, MAX_SHIPS, idx);
405434

406-
count++;
407-
}
408-
}
435+
return ade_set_args(L, "o", l_Ship.Set(object_h(objnum)));
409436
}
410-
411-
return ade_set_error(L, "o", l_Ship.Set(object_h()));
412437
}
413438

414439
ADE_FUNC(__len, l_Mission_Ships, NULL,
@@ -418,10 +443,7 @@ ADE_FUNC(__len, l_Mission_Ships, NULL,
418443
"number",
419444
"Number of ships in the mission, or 0 if ships haven't been initialized yet")
420445
{
421-
if(Ships_inited)
422-
return ade_set_args(L, "i", ship_get_num_ships());
423-
else
424-
return ade_set_args(L, "i", 0);
446+
return ade_set_args(L, "i", object_subclass_count(Ships, MAX_SHIPS));
425447
}
426448

427449
//****SUBLIBRARY: Mission/ParsedShips
@@ -479,7 +501,7 @@ ADE_INDEXER(l_Mission_Waypoints, "number Index", "Array of waypoints in the curr
479501
object *ptr = GET_FIRST(&obj_used_list);
480502
while (ptr != END_OF_LIST(&obj_used_list))
481503
{
482-
if (ptr->type == OBJ_WAYPOINT)
504+
if (ptr->type == OBJ_WAYPOINT && !ptr->flags[Object::Object_Flags::Should_be_dead])
483505
count++;
484506

485507
if(count == idx) {
@@ -494,11 +516,15 @@ ADE_INDEXER(l_Mission_Waypoints, "number Index", "Array of waypoints in the curr
494516

495517
ADE_FUNC(__len, l_Mission_Waypoints, NULL, "Gets number of waypoints in mission. Note that this is only accurate for one frame.", "number", "Number of waypoints in the mission")
496518
{
497-
uint count=0;
498-
for(uint i = 0; i < MAX_OBJECTS; i++)
519+
int count=0;
520+
521+
object *ptr = GET_FIRST(&obj_used_list);
522+
while (ptr != END_OF_LIST(&obj_used_list))
499523
{
500-
if (Objects[i].type == OBJ_WAYPOINT)
524+
if (ptr->type == OBJ_WAYPOINT && !ptr->flags[Object::Object_Flags::Should_be_dead])
501525
count++;
526+
527+
ptr = GET_NEXT(ptr);
502528
}
503529

504530
return ade_set_args(L, "i", count);
@@ -546,26 +572,15 @@ ADE_INDEXER(l_Mission_Weapons, "number Index", "Gets handle to a weapon object i
546572
if(!ade_get_args(L, "*i", &idx))
547573
return ade_set_error(L, "o", l_Weapon.Set(object_h()));
548574

549-
//Remember, Lua indices start at 0.
550-
int count=1;
551-
552-
for(int i = 0; i < MAX_WEAPONS; i++)
553-
{
554-
if (Weapons[i].weapon_info_index < 0 || Weapons[i].objnum < 0 || Objects[Weapons[i].objnum].type != OBJ_WEAPON)
555-
continue;
556-
557-
if(count == idx) {
558-
return ade_set_args(L, "o", l_Weapon.Set(object_h(&Objects[Weapons[i].objnum])));
559-
}
560-
561-
count++;
562-
}
575+
int objnum = -1;
576+
if (idx > 0)
577+
objnum = object_subclass_at_index(Weapons, MAX_WEAPONS, idx);
563578

564-
return ade_set_error(L, "o", l_Weapon.Set(object_h()));
579+
return ade_set_args(L, "o", l_Weapon.Set(object_h(objnum)));
565580
}
566581
ADE_FUNC(__len, l_Mission_Weapons, NULL, "Number of weapon objects in mission. Note that this is only accurate for one frame.", "number", "Number of weapon objects in mission")
567582
{
568-
return ade_set_args(L, "i", Num_weapons);
583+
return ade_set_args(L, "i", object_subclass_count(Weapons, MAX_WEAPONS));
569584
}
570585

571586
//****SUBLIBRARY: Mission/Beams
@@ -577,26 +592,15 @@ ADE_INDEXER(l_Mission_Beams, "number Index", "Gets handle to a beam object in th
577592
if(!ade_get_args(L, "*i", &idx))
578593
return ade_set_error(L, "o", l_Beam.Set(object_h()));
579594

580-
//Remember, Lua indices start at 0.
581-
int count=1;
582-
583-
for(int i = 0; i < MAX_BEAMS; i++)
584-
{
585-
if (Beams[i].weapon_info_index < 0 || Beams[i].objnum < 0 || Objects[Beams[i].objnum].type != OBJ_BEAM)
586-
continue;
587-
588-
if(count == idx) {
589-
return ade_set_args(L, "o", l_Beam.Set(object_h(&Objects[Beams[i].objnum])));
590-
}
591-
592-
count++;
593-
}
595+
int objnum = -1;
596+
if (idx > 0)
597+
objnum = object_subclass_at_index(Beams, MAX_BEAMS, idx);
594598

595-
return ade_set_error(L, "o", l_Beam.Set(object_h()));
599+
return ade_set_args(L, "o", l_Beam.Set(object_h(objnum)));
596600
}
597601
ADE_FUNC(__len, l_Mission_Beams, NULL, "Number of beam objects in mission. Note that this is only accurate for one frame.", "number", "Number of beam objects in mission")
598602
{
599-
return ade_set_args(L, "i", Beam_count);
603+
return ade_set_args(L, "i", object_subclass_count(Beams, MAX_BEAMS));
600604
}
601605

602606
//****SUBLIBRARY: Mission/Wings
@@ -796,27 +800,15 @@ ADE_INDEXER(l_Mission_Fireballs, "number Index", "Gets handle to a fireball obje
796800
if (!ade_get_args(L, "*i", &idx))
797801
return ade_set_error(L, "o", l_Fireball.Set(object_h()));
798802

799-
//Remember, Lua indices start at 1.
800-
int count = 1;
801-
802-
for (auto& current_fireball : Fireballs) {
803-
if (current_fireball.fireball_info_index < 0 || current_fireball.objnum < 0 || Objects[current_fireball.objnum].type != OBJ_FIREBALL)
804-
continue;
805-
806-
if (count == idx) {
807-
return ade_set_args(L, "o", l_Fireball.Set(object_h(&Objects[current_fireball.objnum])));
808-
}
809-
810-
count++;
811-
812-
}
803+
int objnum = -1;
804+
if (idx > 0)
805+
objnum = object_subclass_at_index(Fireballs, MAX_FIREBALLS, idx);
813806

814-
return ade_set_error(L, "o", l_Fireball.Set(object_h()));
807+
return ade_set_args(L, "o", l_Fireball.Set(object_h(objnum)));
815808
}
816809
ADE_FUNC(__len, l_Mission_Fireballs, NULL, "Number of fireball objects in mission. Note that this is only accurate for one frame.", "number", "Number of fireball objects in mission")
817810
{
818-
int count = fireball_get_count();
819-
return ade_set_args(L, "i", count);
811+
return ade_set_args(L, "i", object_subclass_count(Fireballs, MAX_FIREBALLS));
820812
}
821813

822814
ADE_FUNC(addMessage, l_Mission, "string name, string text, [persona persona]", "Adds a message", "message", "The new message or invalid handle on error")
@@ -2223,6 +2215,16 @@ ADE_FUNC(getShipList,
22232215
//Similarly, an empty list is defined by the head's next element being itself, hence an empty list will immediately return nil just fine
22242216
so = GET_NEXT(so);
22252217

2218+
// skip should-be-dead ships
2219+
if (so != nullptr) {
2220+
while (so != END_OF_LIST(&Ship_obj_list)) {
2221+
if (!Objects[so->objnum].flags[Object::Object_Flags::Should_be_dead]) {
2222+
break;
2223+
}
2224+
so = GET_NEXT(so);
2225+
}
2226+
}
2227+
22262228
if (so == END_OF_LIST(&Ship_obj_list) || so == nullptr) {
22272229
return luacpp::LuaValueList{ luacpp::LuaValue::createNil(LInner) };
22282230
}
@@ -2245,6 +2247,16 @@ ADE_FUNC(getMissileList,
22452247
//Similarly, an empty list is defined by the head's next element being itself, hence an empty list will immediately return nil just fine
22462248
mo = GET_NEXT(mo);
22472249

2250+
// skip should-be-dead missiles
2251+
if (mo != nullptr) {
2252+
while (mo != END_OF_LIST(&Missile_obj_list)) {
2253+
if (!Objects[mo->objnum].flags[Object::Object_Flags::Should_be_dead]) {
2254+
break;
2255+
}
2256+
mo = GET_NEXT(mo);
2257+
}
2258+
}
2259+
22482260
if (mo == END_OF_LIST(&Missile_obj_list) || mo == nullptr) {
22492261
return luacpp::LuaValueList{ luacpp::LuaValue::createNil(LInner) };
22502262
}

code/scripting/api/objs/object.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,18 @@ ADE_FUNC(isValid, l_Object, NULL, "Detects whether handle is valid", "boolean",
300300
return ade_set_args(L, "b", oh->IsValid());
301301
}
302302

303+
ADE_FUNC(isExpiring, l_Object, nullptr, "Checks whether the object has the should-be-dead flag set, which will cause it to be deleted within one frame", "boolean", "true or false according to the flag, or nil if a syntax/type error occurs")
304+
{
305+
object_h* oh;
306+
if (!ade_get_args(L, "o", l_Object.GetPtr(&oh)))
307+
return ADE_RETURN_NIL;
308+
309+
if (!oh->IsValid())
310+
return ADE_RETURN_NIL;
311+
312+
return ade_set_args(L, "b", oh->objp->flags[Object::Object_Flags::Should_be_dead]);
313+
}
314+
303315
ADE_FUNC(getBreedName, l_Object, NULL, "Gets object type", "string", "Object type name, or empty string if handle is invalid")
304316
{
305317
object_h *objh;

0 commit comments

Comments
 (0)