Skip to content

Commit

Permalink
replace waypoint pointers with waypoint indexes
Browse files Browse the repository at this point in the history
Several locations in the code (notably `ai_info` and `waypoint_h`) previously stored pointers for waypoints and waypoint lists that need to be valid for more than one frame.  Since both waypoint lists and waypoint paths may change size, resulting in vector reallocation, the information should be stored as indexes instead.

Fixes #6353.
  • Loading branch information
Goober5000 committed Sep 19, 2024
1 parent 56fc5b4 commit 4b6c3b1
Show file tree
Hide file tree
Showing 18 changed files with 176 additions and 140 deletions.
6 changes: 3 additions & 3 deletions code/ai/ai.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,8 @@ typedef struct ai_info {
int ai_class; // Class. Might be override of default.

// Probably become obsolete, to be replaced by path_start, path_cur, etc.
waypoint_list *wp_list; // waypoint list being followed
int wp_index; // waypoint index in list
int wp_list_index; // index of waypoint list being followed
int wp_index; // index of waypoint in list
int wp_flags; // waypoint flags, see WPF_xxxx
int waypoint_speed_cap; // -1 no cap, otherwise cap - changed to int by Goober5000

Expand Down Expand Up @@ -533,7 +533,7 @@ extern void ai_ignore_wing(object *ignorer, int wingnum);
extern void ai_dock_with_object(object *docker, int docker_index, object *dockee, int dockee_index, int dock_type);
extern void ai_stay_still(object *still_objp, vec3d *view_pos);
extern void ai_do_default_behavior(object *obj);
extern void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags, int start_index);
extern void ai_start_waypoints(object *objp, int wl_index, int wp_flags, int start_index);
extern void ai_ship_hit(object *objp_ship, object *hit_objp, vec3d *hit_normal);
extern void ai_ship_destroy(int shipnum);
extern vec3d ai_get_acc_limit(vec3d* vel_limit, const object* objp);
Expand Down
64 changes: 37 additions & 27 deletions code/ai/aicode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3515,20 +3515,33 @@ void ai_dock_with_object(object *docker, int docker_index, object *dockee, int d
// flags tells:
// WPF_REPEAT Set -> repeat waypoints.
// WPF_BACKTRACK Go in reverse.
void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags, int start_index)
void ai_start_waypoints(object *objp, int wp_list_index, int wp_flags, int start_index)
{
ai_info *aip;
Assert(wp_list != NULL);
auto aip = &Ai_info[Ships[objp->instance].ai_index];

if (start_index < 0 || start_index >= (int)wp_list->get_waypoints().size())
if (Waypoint_lists.empty())
{
Warning(LOCATION, "No waypoint lists in mission!");
aip->mode = AIM_NONE;
return;
}

auto wp_list = find_waypoint_list_at_index(wp_list_index);
if (!wp_list)
{
Warning(LOCATION, "wp_list_index %d must be a valid waypoint list index!", wp_list_index);
wp_list_index = 0;
wp_list = find_waypoint_list_at_index(wp_list_index);
}

auto wp = find_waypoint_at_index(wp_list, start_index);
if (!wp)
{
Warning(LOCATION, "Starting index for %s on '%s' is out of range!", Ships[objp->instance].ship_name, wp_list->get_name());
start_index = (wp_flags & WPF_BACKTRACK) ? (int)wp_list->get_waypoints().size() - 1 : 0;
}

aip = &Ai_info[Ships[objp->instance].ai_index];

if ( (aip->mode == AIM_WAYPOINTS) && (aip->wp_list == wp_list) )
if ( (aip->mode == AIM_WAYPOINTS) && (aip->wp_list_index == wp_list_index) )
{
if (aip->wp_index == INVALID_WAYPOINT_POSITION)
{
Expand All @@ -3548,7 +3561,7 @@ void ai_start_waypoints(object *objp, waypoint_list *wp_list, int wp_flags, int
}
aip->ai_flags.remove(AI::AI_Flags::Formation_object);

aip->wp_list = wp_list;
aip->wp_list_index = wp_list_index;
aip->wp_index = start_index;
aip->wp_flags = wp_flags;
aip->mode = AIM_WAYPOINTS;
Expand Down Expand Up @@ -4896,19 +4909,15 @@ void ai_waypoints()

// sanity checking for stuff that should never happen
if (aip->wp_index == INVALID_WAYPOINT_POSITION) {
if (aip->wp_list == NULL) {
UNREACHABLE("Waypoints should have been assigned already!");
ai_start_waypoints(Pl_objp, &Waypoint_lists.front(), WPF_REPEAT, 0);
} else {
UNREACHABLE("Waypoints should have been started already!");
ai_start_waypoints(Pl_objp, aip->wp_list, WPF_REPEAT, 0);
}
UNREACHABLE("Waypoints should have been started already!");
ai_start_waypoints(Pl_objp, (aip->wp_list_index < 0) ? 0 : aip->wp_list_index, WPF_REPEAT, 0);
}

Assert(!aip->wp_list->get_waypoints().empty()); // What? Is this zero? Probably never got initialized!
auto wp_list = find_waypoint_list_at_index(aip->wp_list_index);
Assert(wp_list && !wp_list->get_waypoints().empty()); // What? Is this zero? Probably never got initialized!

bool done, treat_as_ship;
ai_fly_to_target_position(aip->wp_list->get_waypoints()[aip->wp_index].get_pos(), &done, &treat_as_ship);
ai_fly_to_target_position(wp_list->get_waypoints()[aip->wp_index].get_pos(), &done, &treat_as_ship);

if ( done ) {
bool reached_end;
Expand All @@ -4918,15 +4927,15 @@ void ai_waypoints()
reached_end = (aip->wp_index == -1);
} else {
++aip->wp_index;
reached_end = (aip->wp_index == (int)aip->wp_list->get_waypoints().size());
reached_end = (aip->wp_index == static_cast<int>(wp_list->get_waypoints().size()));
}

if (reached_end) {
// have reached the last waypoint. Do I repeat?
if ( aip->wp_flags & WPF_REPEAT ) {
// go back to the start.
if (aip->wp_flags & WPF_BACKTRACK) {
aip->wp_index = (int)aip->wp_list->get_waypoints().size() - 1;
aip->wp_index = static_cast<int>(wp_list->get_waypoints().size()) - 1;
} else {
aip->wp_index = 0;
}
Expand All @@ -4944,18 +4953,18 @@ void ai_waypoints()
// ai_fly_to_target_position when it marks the AI directive as complete
if ( treat_as_ship ) {
ai_mission_goal_complete( aip ); // this call should reset the AI mode
mission_log_add_entry( LOG_WAYPOINTS_DONE, Ships[Pl_objp->instance].ship_name, aip->wp_list->get_name(), -1 );
mission_log_add_entry( LOG_WAYPOINTS_DONE, Ships[Pl_objp->instance].ship_name, wp_list->get_name(), -1 );
} else {
ai_mission_wing_goal_complete( Ships[Pl_objp->instance].wingnum, &(aip->goals[aip->active_goal]) );
mission_log_add_entry( LOG_WAYPOINTS_DONE, Wings[Ships[Pl_objp->instance].wingnum].name, aip->wp_list->get_name(), -1 );
mission_log_add_entry( LOG_WAYPOINTS_DONE, Wings[Ships[Pl_objp->instance].wingnum].name, wp_list->get_name(), -1 );
}
// adds scripting hook for 'On Waypoints Done' --wookieejedi
if (scripting::hooks::OnWaypointsDone->isActive()) {
scripting::hooks::OnWaypointsDone->run(scripting::hooks::ShipSourceConditions{ &Ships[Pl_objp->instance] },
scripting::hook_param_list(
scripting::hook_param("Ship", 'o', Pl_objp),
scripting::hook_param("Wing", 'o', scripting::api::l_Wing.Set(Ships[Pl_objp->instance].wingnum)),
scripting::hook_param("Waypointlist", 'o', scripting::api::l_WaypointList.Set(scripting::api::waypointlist_h(aip->wp_list)))
scripting::hook_param("Waypointlist", 'o', scripting::api::l_WaypointList.Set(scripting::api::waypointlist_h(wp_list)))
));
}
}
Expand Down Expand Up @@ -12665,24 +12674,25 @@ int ai_formation()
// skip if wing leader has no waypoint order or a different waypoint list
// ...or if it's a different start index or direction
if ( (laip->mode != AIM_WAYPOINTS)
|| (laip->wp_list != aip->wp_list)
|| (laip->wp_list_index != aip->wp_list_index)
|| (laip->submode_parm0 != aip->submode_parm0)
|| ((laip->wp_flags & WPF_BACKTRACK) != (aip->wp_flags & WPF_BACKTRACK))
) {
return 1;
}
}

aip->wp_list = laip->wp_list;
aip->wp_list_index = laip->wp_list_index;
aip->wp_index = laip->wp_index;
aip->wp_flags = laip->wp_flags;

if (aip->wp_list != nullptr) {
auto wp_list = find_waypoint_list_at_index(aip->wp_list_index);
if (wp_list != nullptr) {
if (aip->wp_flags & WPF_BACKTRACK) {
if (aip->wp_index == -1)
++aip->wp_index;
} else {
if (aip->wp_index == (int)aip->wp_list->get_waypoints().size())
if (aip->wp_index == static_cast<int>(wp_list->get_waypoints().size()))
--aip->wp_index;
}
}
Expand Down Expand Up @@ -15455,7 +15465,7 @@ void init_ai_object(int objnum)
//Init stuff from AI class and AI profiles
init_aip_from_class_and_profile(aip, &Ai_classes[Ship_info[ship_type].ai_class], The_mission.ai_profile);

aip->wp_list = NULL;
aip->wp_list_index = -1;
aip->wp_index = INVALID_WAYPOINT_POSITION;

aip->attacker_objnum = -1;
Expand Down
14 changes: 7 additions & 7 deletions code/ai/aigoals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ void ai_goal_reset(ai_goal *aigp, bool adding_goal, int ai_mode, int ai_submode,
aigp->target_name = nullptr;
aigp->target_name_index = -1;

aigp->wp_list = nullptr;
aigp->wp_list_index = -1;

aigp->target_instance = -1;
aigp->target_signature = -1;
Expand Down Expand Up @@ -738,8 +738,8 @@ void ai_add_goal_sub_player(int type, int mode, int submode, const char *target_

if ( mode == AI_GOAL_WARP ) {
if (submode >= 0) {
aigp->wp_list = find_waypoint_list_at_index(submode);
Assert(aigp->wp_list != NULL);
aigp->wp_list_index = submode;
Assert(find_waypoint_list_at_index(aigp->wp_list_index) != nullptr);
}
}

Expand Down Expand Up @@ -1605,10 +1605,10 @@ ai_achievability ai_mission_goal_achievable( int objnum, ai_goal *aigp )
// check to see if we have a valid list. If not, then try to set one up. If that
// fails, then we must pitch this order
if ( (aigp->ai_mode == AI_GOAL_WAYPOINTS_ONCE) || (aigp->ai_mode == AI_GOAL_WAYPOINTS) ) {
if ( aigp->wp_list == NULL ) {
aigp->wp_list = find_matching_waypoint_list(aigp->target_name);
if ( aigp->wp_list_index < 0 ) {
aigp->wp_list_index = find_matching_waypoint_list_index(aigp->target_name);

if ( aigp->wp_list == NULL ) {
if ( aigp->wp_list_index < 0 ) {
Warning(LOCATION, "Unknown waypoint list %s - not found in mission file. Killing ai goal", aigp->target_name );
return ai_achievability::NOT_ACHIEVABLE;
}
Expand Down Expand Up @@ -2344,7 +2344,7 @@ void ai_process_mission_orders( int objnum, ai_info *aip )
flags |= WPF_REPEAT;
if (current_goal->flags[AI::Goal_Flags::Waypoints_in_reverse])
flags |= WPF_BACKTRACK;
ai_start_waypoints(objp, current_goal->wp_list, flags, current_goal->int_data);
ai_start_waypoints(objp, current_goal->wp_list_index, flags, current_goal->int_data);
break;
}

Expand Down
2 changes: 1 addition & 1 deletion code/ai/aigoals.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ typedef struct ai_goal {

const char *target_name; // name of the thing that this goal acts upon
int target_name_index; // index of goal_target_name in Goal_target_names[][]
waypoint_list *wp_list; // waypoints that this ship might fly.
int wp_list_index; // waypoints that this ship might fly.
int target_instance; // instance of thing this ship might be chasing (currently only used for weapons; note, not the same as objnum!)
int target_signature; // signature of object this ship might be chasing (currently only used for weapons; paired with above value to confirm target)

Expand Down
32 changes: 17 additions & 15 deletions code/autopilot/autopilot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ int start_dist;
void autopilot_ai_waypoint_goal_fixup(ai_goal* aigp)
{
// this function sets wp_index properly;
aigp->wp_list = find_matching_waypoint_list(aigp->target_name);
aigp->wp_list_index = find_matching_waypoint_list_index(aigp->target_name);
}


Expand Down Expand Up @@ -111,13 +111,15 @@ const vec3d *NavPoint::GetPosition()
{
if (flags & NP_WAYPOINT)
{
waypoint *wpt = find_waypoint_at_index((waypoint_list*) target_obj, waypoint_num-1);
Assert(wpt != NULL);
auto wpt = find_waypoint_at_indexes(target_index, waypoint_num-1);
Assert(wpt != nullptr);
if (wpt == nullptr)
return &vmd_zero_vector;
return wpt->get_pos();
}
else
{
return &Objects[((ship*) target_obj)->objnum].pos;
return &Objects[target_index].pos;
}
}

Expand Down Expand Up @@ -462,12 +464,12 @@ bool StartAutopilot()
{
if (Navs[CurrentNav].flags & NP_WAYPOINT)
{
ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WAYPOINTS_ONCE, 0, ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name(), &Ai_info[Ships[i].ai_index] );
ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WAYPOINTS_ONCE, 0, Waypoint_lists[Navs[CurrentNav].target_index].get_name(), &Ai_info[Ships[i].ai_index] );
//fixup has to wait until after wing goals
}
else
{
ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, &Ai_info[Ships[i].ai_index] );
ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_FLY_TO_SHIP, 0, Ships[Objects[Navs[CurrentNav].target_index].instance].ship_name, &Ai_info[Ships[i].ai_index] );
}

}
Expand All @@ -491,7 +493,7 @@ bool StartAutopilot()
if (Navs[CurrentNav].flags & NP_WAYPOINT)
{

ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name(), i );
ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, Waypoint_lists[Navs[CurrentNav].target_index].get_name(), i );

// "fix up" the goal
for (j = 0; j < MAX_AI_GOALS; j++)
Expand All @@ -505,7 +507,7 @@ bool StartAutopilot()
}
else
{
ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, i );
ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_FLY_TO_SHIP, 0, Ships[Objects[Navs[CurrentNav].target_index].instance].ship_name, i );

}
}
Expand Down Expand Up @@ -874,12 +876,12 @@ void EndAutoPilot()
if (Navs[CurrentNav].flags & NP_WAYPOINT)
{
goal = AI_GOAL_WAYPOINTS_ONCE;
goal_name = ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name();
goal_name = Waypoint_lists[Navs[CurrentNav].target_index].get_name();
}
else
{
goal = AI_GOAL_FLY_TO_SHIP;
goal_name = ((ship*)Navs[CurrentNav].target_obj)->ship_name;
goal_name = Ships[Objects[Navs[CurrentNav].target_index].instance].ship_name;
}

// assign ship goals
Expand Down Expand Up @@ -1094,9 +1096,9 @@ void NavSystem_Do()

for (i = 0; i < MAX_NAVPOINTS; i++)
{
if ((Navs[i].flags & NP_SHIP) && (Navs[i].target_obj != NULL))
if ((Navs[i].flags & NP_SHIP) && (Navs[i].target_index >= 0))
{
if (((ship*)Navs[i].target_obj)->objnum == -1)
if (Objects[Navs[i].target_index].flags[Object::Object_Flags::Should_be_dead])
{
if (CurrentNav == i)
CurrentNav = -1;
Expand All @@ -1108,7 +1110,7 @@ void NavSystem_Do()
// check if we're reached a Node
for (i = 0; i < MAX_NAVPOINTS; i++)
{
if (Navs[i].target_obj != NULL)
if (Navs[i].target_index >= 0)
{
if (Navs[i].flags & NP_VALIDTYPE && DistanceTo(i) < 1000)
Navs[i].flags |= NP_VISITED;
Expand Down Expand Up @@ -1392,7 +1394,7 @@ bool AddNav_Ship(const char *Nav, const char *TargetName, int flags)
{
if (Ships[i].objnum != -1 && !stricmp(TargetName, Ships[i].ship_name))
{
tnav.target_obj = (void *)&Ships[i];
tnav.target_index = Ships[i].objnum;
}
}

Expand Down Expand Up @@ -1433,7 +1435,7 @@ bool AddNav_Waypoint(const char *Nav, const char *WP_Path, int node, int flags)

Assert(!(tnav.flags & NP_SHIP));

tnav.target_obj = find_matching_waypoint_list(WP_Path);
tnav.target_index = find_matching_waypoint_list_index(WP_Path);
tnav.waypoint_num = node;

// copy it into it's location
Expand Down
4 changes: 2 additions & 2 deletions code/autopilot/autopilot.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class NavPoint
ubyte normal_color[3] = { 0x80, 0x80, 0xFF };
ubyte visited_color[3] = { 0xFF, 0xFF, 0x00 };

const void *target_obj = nullptr;
int target_index = -1; //waypoint list index if NP_WAYPOINT, otherwise object index
int waypoint_num = -1; //only used when flags & NP_WAYPOINT

const vec3d *GetPosition();
Expand All @@ -53,7 +53,7 @@ class NavPoint
visited_color[1] = 0xFF;
visited_color[2] = 0x00;

target_obj = nullptr;
target_index = -1;
waypoint_num = -1;
}
};
Expand Down
4 changes: 2 additions & 2 deletions code/mission/missiontraining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ int Training_context_speed_set;
int Training_context_speed_min;
int Training_context_speed_max;
TIMESTAMP Training_context_speed_timestamp;
waypoint_list *Training_context_path;
int Training_context_waypoint_path;
int Training_context_goal_waypoint;
int Training_context_at_waypoint;
float Training_context_distance;
Expand Down Expand Up @@ -398,7 +398,7 @@ void training_mission_init()
Training_context = 0;
Training_context_speed_set = 0;
Training_context_speed_timestamp = TIMESTAMP::invalid();
Training_context_path = nullptr;
Training_context_waypoint_path = -1;

Players_target = UNINITIALIZED;
Players_mlocked = UNINITIALIZED;
Expand Down
2 changes: 1 addition & 1 deletion code/mission/missiontraining.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extern int Training_context_speed_min;
extern int Training_context_speed_max;
extern int Training_context_speed_set;
extern TIMESTAMP Training_context_speed_timestamp;
extern waypoint_list *Training_context_path;
extern int Training_context_waypoint_path;
extern int Training_context_goal_waypoint;
extern int Training_context_at_waypoint;
extern float Training_context_distance;
Expand Down
Loading

0 comments on commit 4b6c3b1

Please sign in to comment.