Skip to content

Commit 6139d60

Browse files
committed
use std::optional so the object->instance id is always valid
1 parent 2d7e47f commit 6139d60

File tree

19 files changed

+204
-128
lines changed

19 files changed

+204
-128
lines changed

code/lab/renderer/lab_renderer.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -114,17 +114,18 @@ void LabRenderer::renderModel(float frametime) {
114114
}
115115

116116
if (obj->type == OBJ_PROP) {
117-
Props[obj->instance].flags.set(Prop::Prop_Flags::Draw_as_wireframe, renderFlags[LabRenderFlag::ShowWireframe]);
118-
Props[obj->instance].flags.set(Prop::Prop_Flags::Render_full_detail, renderFlags[LabRenderFlag::ShowFullDetail]);
119-
Props[obj->instance].flags.set(Prop::Prop_Flags::Render_without_light,
117+
prop* propp = prop_id_lookup(obj->instance);
118+
propp->flags.set(Prop::Prop_Flags::Draw_as_wireframe, renderFlags[LabRenderFlag::ShowWireframe]);
119+
propp->flags.set(Prop::Prop_Flags::Render_full_detail, renderFlags[LabRenderFlag::ShowFullDetail]);
120+
propp->flags.set(Prop::Prop_Flags::Render_without_light,
120121
renderFlags[LabRenderFlag::NoLighting] || currentMissionBackground == LAB_MISSION_NONE_STRING);
121-
Props[obj->instance].flags.set(Prop::Prop_Flags::Render_without_diffuse, renderFlags[LabRenderFlag::NoDiffuseMap]);
122-
Props[obj->instance].flags.set(Prop::Prop_Flags::Render_without_glowmap, renderFlags[LabRenderFlag::NoGlowMap]);
123-
Props[obj->instance].flags.set(Prop::Prop_Flags::Render_without_normalmap, renderFlags[LabRenderFlag::NoNormalMap]);
124-
Props[obj->instance].flags.set(Prop::Prop_Flags::Render_without_specmap, renderFlags[LabRenderFlag::NoSpecularMap]);
125-
Props[obj->instance].flags.set(Prop::Prop_Flags::Render_without_reflectmap, renderFlags[LabRenderFlag::NoReflectMap]);
126-
Props[obj->instance].flags.set(Prop::Prop_Flags::Render_without_heightmap, renderFlags[LabRenderFlag::NoHeightMap]);
127-
Props[obj->instance].flags.set(Prop::Prop_Flags::Render_without_ambientmap, renderFlags[LabRenderFlag::NoAOMap]);
122+
propp->flags.set(Prop::Prop_Flags::Render_without_diffuse, renderFlags[LabRenderFlag::NoDiffuseMap]);
123+
propp->flags.set(Prop::Prop_Flags::Render_without_glowmap, renderFlags[LabRenderFlag::NoGlowMap]);
124+
propp->flags.set(Prop::Prop_Flags::Render_without_normalmap, renderFlags[LabRenderFlag::NoNormalMap]);
125+
propp->flags.set(Prop::Prop_Flags::Render_without_specmap, renderFlags[LabRenderFlag::NoSpecularMap]);
126+
propp->flags.set(Prop::Prop_Flags::Render_without_reflectmap, renderFlags[LabRenderFlag::NoReflectMap]);
127+
propp->flags.set(Prop::Prop_Flags::Render_without_heightmap, renderFlags[LabRenderFlag::NoHeightMap]);
128+
propp->flags.set(Prop::Prop_Flags::Render_without_ambientmap, renderFlags[LabRenderFlag::NoAOMap]);
128129
}
129130

130131
if (obj->type == OBJ_WEAPON) {

code/object/collideshipship.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,8 +587,9 @@ void calculate_ship_ship_collision_physics(collision_info_struct *ship_ship_hit_
587587
} else if (heavy->type == OBJ_DEBRIS) {
588588
pm = model_get(Debris[heavy->instance].model_num);
589589
} else if (heavy->type == OBJ_PROP) {
590-
pm = model_get(Prop_info[Props[heavy->instance].prop_info_index].model_num);
591-
model_instance_num = Props[heavy->instance].model_instance_num;
590+
prop* propp = prop_id_lookup(heavy->instance);
591+
pm = model_get(Prop_info[propp->prop_info_index].model_num);
592+
model_instance_num = propp->model_instance_num;
592593
pmi = model_get_instance(model_instance_num);
593594
} else {
594595
// we should have caught this already

code/object/collideshipweapon.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ static int prop_weapon_check_collision(object* prop_objp, object* weapon_objp, f
629629
Assert(prop_objp->type == OBJ_PROP);
630630
Assert(prop_objp->instance >= 0);
631631

632-
prop* propp = &Props[prop_objp->instance];
632+
prop* propp = prop_id_lookup(prop_objp->instance);
633633
prop_info* prinfo = &Prop_info[propp->prop_info_index];
634634

635635
Assert(weapon_objp != nullptr);

code/object/object.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2277,7 +2277,7 @@ int object_get_model_instance_num(const object *objp)
22772277
case OBJ_RAW_POF:
22782278
return Pof_objects[objp->instance].model_instance;
22792279
case OBJ_PROP:
2280-
return Props[objp->instance].model_instance_num;
2280+
return prop_id_lookup(objp->instance)->model_instance_num;
22812281
default:
22822282
break;
22832283
}

code/object/objectsort.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ inline bool sorted_obj::operator < (const sorted_obj &other) const
7777
} else if (obj->type == OBJ_RAW_POF) {
7878
model_num_a = Pof_objects[obj->instance].model_num;
7979
} else if (obj->type == OBJ_PROP) {
80-
model_num_a = Props[obj->instance].model_instance_num;
80+
model_num_a = prop_id_lookup(obj->instance)->model_instance_num;
8181
}
8282

8383
if ( other.obj->type == OBJ_SHIP ) {
@@ -105,7 +105,7 @@ inline bool sorted_obj::operator < (const sorted_obj &other) const
105105
} else if (other.obj->type == OBJ_RAW_POF) {
106106
model_num_b = Pof_objects[other.obj->instance].model_num;
107107
} else if (other.obj->type == OBJ_PROP) {
108-
model_num_b = Props[other.obj->instance].model_instance_num;
108+
model_num_b = prop_id_lookup(other.obj->instance)->model_instance_num;
109109
}
110110

111111
if ( model_num_a == model_num_b ) {

code/parse/sexp.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5783,7 +5783,7 @@ const prop *eval_prop(int node)
57835783
if (Sexp_nodes[node].cache->sexp_node_data_type != OPF_PROP)
57845784
return nullptr;
57855785

5786-
return &Props[Sexp_nodes[node].cache->ship_registry_index];
5786+
return prop_id_lookup(Sexp_nodes[node].cache->ship_registry_index);
57875787
}
57885788

57895789
// maybe forward to a special-arg node
@@ -5803,7 +5803,7 @@ const prop *eval_prop(int node)
58035803
if (!is_node_value_dynamic(node))
58045804
Sexp_nodes[node].cache = new sexp_cached_data(OPF_PROP, -1, prop_idx);
58055805

5806-
return &Props[prop_idx];
5806+
return prop_id_lookup(prop_idx);
58075807
}
58085808

58095809
// we know nothing about this prop, apparently

code/prop/prop.cpp

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ bool Props_inited = false;
1717

1818
SCP_vector<prop_info> Prop_info;
1919

20-
SCP_vector<prop> Props;
20+
SCP_vector<std::optional<prop>> Props;
2121

2222
static SCP_vector<SCP_string> Removed_props;
2323

@@ -40,9 +40,13 @@ int prop_name_lookup(const char *name)
4040
Assertion(name != nullptr, "NULL name passed to prop_name_lookup");
4141

4242
for (int i=0; i<static_cast<int>(Props.size()); i++){
43-
if (Props[i].objnum >= 0){
44-
if (Objects[Props[i].objnum].type == OBJ_PROP){
45-
if (!stricmp(name, Props[i].prop_name)){
43+
auto prop = Props[i] ? &Props[i].value() : nullptr;
44+
if (prop == nullptr) {
45+
continue;
46+
}
47+
if (prop->objnum >= 0){
48+
if (Objects[prop->objnum].type == OBJ_PROP) {
49+
if (!stricmp(name, prop->prop_name)) {
4650
return i;
4751
}
4852
}
@@ -53,6 +57,15 @@ int prop_name_lookup(const char *name)
5357
return -1;
5458
}
5559

60+
prop* prop_id_lookup(int id)
61+
{
62+
if (id < 0 || id >= static_cast<int>(Props.size()) || !Props[id].has_value()) {
63+
Assertion(false, "Could not find prop for id %d", id);
64+
return nullptr;
65+
}
66+
return &Props[id].value();
67+
}
68+
5669
void parse_prop_table(const char* filename)
5770
{
5871
read_file_text(filename, CF_TYPE_TABLES);
@@ -257,7 +270,10 @@ int prop_create(matrix* orient, vec3d* pos, int prop_type, const char* name)
257270
pip = &(Prop_info[prop_type]);
258271

259272
Props.emplace_back(prop());
260-
propp = &Props.back();
273+
int new_id = static_cast<int>(Props.size()) - 1;
274+
propp = prop_id_lookup(new_id);
275+
Assertion(propp != nullptr, "Could not create prop!");
276+
261277
propp->prop_info_index = prop_type;
262278

263279
if ((name == nullptr) || (prop_name_lookup(name) >= 0)) {
@@ -321,7 +337,7 @@ int prop_create(matrix* orient, vec3d* pos, int prop_type, const char* name)
321337

322338
int objnum = obj_create(OBJ_PROP,
323339
-1,
324-
static_cast<int>(Props.size() - 1),
340+
new_id,
325341
orient,
326342
pos,
327343
model_get_radius(pip->model_num),
@@ -389,23 +405,25 @@ int prop_create(matrix* orient, vec3d* pos, int prop_type, const char* name)
389405
void prop_delete(object* obj)
390406
{
391407
int num = obj->instance;
392-
Assert(num >= 0 && num <= static_cast<int>(Props.size()));
393408

394409
int objnum = OBJ_INDEX(obj);
395-
Assert(Props[num].objnum == objnum);
410+
Assertion(Props[num].has_value(), "Props[%d] is already nullopt!", num);
396411

397-
prop* propp = &Props[num];
412+
prop& propp = *Props[num];
413+
Assertion(propp.objnum == objnum, "Prop object id does not match passed object!");
398414

399-
propp->objnum = -1;
415+
propp.objnum = -1;
400416

401417
//animation::ModelAnimationSet::stopAnimations(model_get_instance(propp->model_instance_num));
402418

403419
// glow point banks
404-
propp->glow_point_bank_active.clear();
420+
propp.glow_point_bank_active.clear();
405421

406-
model_delete_instance(propp->model_instance_num);
422+
model_delete_instance(propp.model_instance_num);
407423

408-
Props.erase(Props.begin() + num);
424+
// Leave the slot empty for the duration of the scene
425+
// The Props array will be compacted at the end of the level
426+
Props[num] = std::nullopt;
409427
}
410428

411429
/**
@@ -416,8 +434,7 @@ void prop_delete(object* obj)
416434
*/
417435
static void prop_model_change(int n, int prop_type)
418436
{
419-
Assert( n >= 0 && n < MAX_PROPS );
420-
prop* sp = &Props[n];
437+
prop* sp = prop_id_lookup(n);
421438
prop_info* sip = &(Prop_info[prop_type]);
422439
object* objp = &Objects[sp->objnum];
423440
polymodel_instance* pmi = model_get_instance(sp->model_instance_num);
@@ -497,8 +514,7 @@ static void prop_model_change(int n, int prop_type)
497514
*/
498515
void change_prop_type(int n, int prop_type)
499516
{
500-
Assert( n >= 0 && n < MAX_PROPS );
501-
prop* sp = &Props[n];
517+
prop* sp = prop_id_lookup(n);
502518

503519
// do a quick out if we're already using the new ship class
504520
if (sp->prop_info_index == prop_type)
@@ -515,10 +531,6 @@ void change_prop_type(int n, int prop_type)
515531
prop_model_change(n, prop_type);
516532
sp->prop_info_index = prop_type;
517533

518-
// get the before and after models (the new model may have only been loaded in ship_model_change)
519-
auto pm = model_get(sip->model_num);
520-
auto pm_orig = model_get(sip_orig->model_num);
521-
522534
// check class-specific flags
523535

524536
if (sip->flags[Prop::Info_Flags::No_collide]) // changing TO a no-collision ship class
@@ -530,10 +542,10 @@ void change_prop_type(int n, int prop_type)
530542
void prop_render(object* obj, model_draw_list* scene)
531543
{
532544
int num = obj->instance;
533-
Assert(num >= 0 && num <= static_cast<int>(Props.size()));
534545

535-
prop* propp = &Props[num];
536-
prop_info* pip = &Prop_info[Props[num].prop_info_index];
546+
prop* propp = prop_id_lookup(num);
547+
548+
prop_info* pip = &Prop_info[propp->prop_info_index];
537549

538550
MONITOR_INC(NumPropsRend, 1);
539551

@@ -637,9 +649,14 @@ void spawn_test_prop()
637649

638650
void props_level_close()
639651
{
640-
while (!Props.empty()) {
641-
prop_delete(&Objects[Props.back().objnum]);
652+
for (auto& opt_prop : Props) {
653+
if (opt_prop.has_value()) {
654+
prop_delete(&Objects[opt_prop->objnum]);
655+
}
642656
}
657+
658+
// Clear all props and empty prop slots
659+
Props.clear();
643660
}
644661

645662

@@ -648,14 +665,13 @@ int prop_check_collision(object* prop_obj, object* other_obj, vec3d* hitpos, col
648665
{
649666
mc_info mc;
650667

651-
Assert(prop_obj->type == OBJ_PROP);
668+
Assertion(prop_obj->type == OBJ_PROP, "Object is not a prop!");
652669

653670
int num = prop_obj->instance;
654671

655-
Assert(num >= 0 && num < (int)Props.size());
656-
Assert(Props[num].objnum == OBJ_INDEX(prop_obj));
657-
658-
prop* propp = &Props[num];
672+
prop* propp = prop_id_lookup(num);
673+
Assertion(propp->objnum == OBJ_INDEX(prop_obj), "Prop object id does not match passed object!");
674+
659675
prop_info* prinfo = &Prop_info[propp->prop_info_index];
660676

661677
// debris_hit_info NULL - so debris-weapon collision
@@ -839,7 +855,7 @@ int prop_check_collision(object* prop_obj, object* other_obj, vec3d* hitpos, col
839855
asteroid* astp = &Asteroids[instance];
840856
mc.model_instance_num = astp->model_instance_num;
841857
mc.model_num = Asteroid_info[astp->asteroid_type].subtypes[astp->asteroid_subtype].model_number;
842-
mc.submodel_num - 1;
858+
mc.submodel_num - 1; // Typo from asteroth?
843859
}
844860

845861
mc.orient = &heavy_obj->orient; // The object's orient
@@ -862,7 +878,7 @@ int prop_check_collision(object* prop_obj, object* other_obj, vec3d* hitpos, col
862878
}
863879
} else { // prop is the heavy object
864880
mc.flags = (MC_CHECK_MODEL | MC_CHECK_SPHERELINE);
865-
int instance = heavy_obj->instance;
881+
//int instance = heavy_obj->instance;
866882

867883
// fill the appropriate model data
868884
mc.model_instance_num = propp->model_instance_num;

code/prop/prop.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ extern bool Props_inited;
5050
// Global prop info array
5151
extern SCP_vector<prop_info> Prop_info;
5252

53-
extern SCP_vector<prop> Props;
53+
extern SCP_vector<std::optional<prop>> Props;
5454

5555
inline int prop_info_size()
5656
{
@@ -69,6 +69,7 @@ void props_level_close();
6969

7070
int prop_info_lookup(const char* token);
7171
int prop_name_lookup(const char* name);
72+
prop* prop_id_lookup(int id);
7273

7374
void change_prop_type(int n, int prop_type);
7475

code/scripting/api/libs/mission.cpp

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,45 @@ int object_subclass_count(A& object_subclass_array, size_t array_size)
129129
return object_subclass_at_index(object_subclass_array, array_size, COUNT_OBJECTS);
130130
}
131131

132+
// Overload for a vector of std::optional objects
133+
template <typename T>
134+
int object_subclass_at_index(const SCP_vector<std::optional<T>>& vec, int index)
135+
{
136+
int count = 0;
137+
138+
for (const auto& opt_obj : vec) {
139+
140+
if (!opt_obj.has_value()) {
141+
continue;
142+
}
143+
144+
145+
const T& obj = *opt_obj;
146+
147+
int objnum = obj.objnum;
148+
if (objnum < 0 || objnum >= MAX_OBJECTS)
149+
continue;
150+
if (Objects[objnum].flags[Object::Object_Flags::Should_be_dead])
151+
continue;
152+
153+
++count;
154+
155+
if (count == index) {
156+
return obj.objnum;
157+
}
158+
}
159+
160+
if (index == COUNT_OBJECTS)
161+
return count;
162+
else
163+
return -1;
164+
}
165+
166+
template <typename A>
167+
int object_subclass_count(A& object_subclass_array)
168+
{
169+
return object_subclass_at_index(object_subclass_array, COUNT_OBJECTS);
170+
}
132171

133172
namespace scripting {
134173
namespace api {
@@ -565,15 +604,15 @@ ADE_INDEXER(l_Mission_Props, "number/string IndexOrName", "Gets prop", "prop", "
565604

566605
if (idx >= 0)
567606
{
568-
return ade_set_args(L, "o", l_Prop.Set(object_h(&Objects[Props[idx].objnum])));
607+
return ade_set_args(L, "o", l_Prop.Set(object_h(&Objects[prop_id_lookup(idx)->objnum])));
569608
}
570609
else
571610
{
572611
idx = atoi(name);
573612

574613
int objnum = -1;
575614
if (idx > 0)
576-
objnum = object_subclass_at_index(Props, MAX_PROPS, idx);
615+
objnum = object_subclass_at_index(Props, idx);
577616

578617
return ade_set_args(L, "o", l_Prop.Set(object_h(objnum)));
579618
}
@@ -586,7 +625,7 @@ ADE_FUNC(__len, l_Mission_Props, NULL,
586625
"number",
587626
"Number of props in the mission, or 0 if props haven't been initialized yet")
588627
{
589-
return ade_set_args(L, "i", object_subclass_count(Props, MAX_PROPS));
628+
return ade_set_args(L, "i", object_subclass_count(Props));
590629
}
591630

592631
//****SUBLIBRARY: Mission/Waypoints
@@ -1410,8 +1449,6 @@ ADE_FUNC(createProp,
14101449
int obj_idx = prop_create(real_orient, &pos, pclass, name);
14111450

14121451
if(obj_idx >= 0) {
1413-
auto propp = &Props[Objects[obj_idx].instance];
1414-
14151452
prop_info* pip = &Prop_info[pclass];
14161453

14171454
model_page_in_textures(pip->model_num, pclass);

0 commit comments

Comments
 (0)