From a94f07bf027a60756b1b91458176b88257e1ae47 Mon Sep 17 00:00:00 2001 From: Goober5000 Date: Mon, 16 Sep 2024 21:04:43 -0400 Subject: [PATCH] replace waypoint pointers with waypoint indexes 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. --- code/ai/ai.h | 6 +-- code/ai/aicode.cpp | 57 ++++++++++++++++----------- code/ai/aigoals.cpp | 14 +++---- code/ai/aigoals.h | 2 +- code/autopilot/autopilot.cpp | 33 +++++++++------- code/autopilot/autopilot.h | 4 +- code/mission/missiontraining.cpp | 4 +- code/mission/missiontraining.h | 2 +- code/network/multi_obj.cpp | 19 +++++---- code/object/waypoint.cpp | 40 ++++++++++++------- code/object/waypoint.h | 1 + code/parse/sexp.cpp | 7 ++-- code/scripting/api/libs/mission.cpp | 4 +- code/scripting/api/objs/order.cpp | 8 ++-- code/scripting/api/objs/waypoint.cpp | 58 ++++++++++++++++------------ code/scripting/api/objs/waypoint.h | 6 ++- code/ship/ship.cpp | 5 ++- freespace2/freespace.cpp | 2 +- 18 files changed, 159 insertions(+), 113 deletions(-) diff --git a/code/ai/ai.h b/code/ai/ai.h index f5fc94b8a75..090204cc50f 100644 --- a/code/ai/ai.h +++ b/code/ai/ai.h @@ -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 @@ -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); diff --git a/code/ai/aicode.cpp b/code/ai/aicode.cpp index 70161e5d503..6606cd7844a 100644 --- a/code/ai/aicode.cpp +++ b/code/ai/aicode.cpp @@ -3515,20 +3515,31 @@ 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); + if (Waypoint_lists.empty()) + { + Warning(LOCATION, "No waypoint lists in mission!"); + return; + } - if (start_index < 0 || start_index >= (int)wp_list->get_waypoints().size()) + 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; + } + + 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]; + auto 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) { @@ -3548,7 +3559,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; @@ -4896,19 +4907,20 @@ void ai_waypoints() // sanity checking for stuff that should never happen if (aip->wp_index == INVALID_WAYPOINT_POSITION) { - if (aip->wp_list == NULL) { + if (aip->wp_list_index < 0) { UNREACHABLE("Waypoints should have been assigned already!"); - ai_start_waypoints(Pl_objp, &Waypoint_lists.front(), WPF_REPEAT, 0); + ai_start_waypoints(Pl_objp, 0, WPF_REPEAT, 0); } else { UNREACHABLE("Waypoints should have been started already!"); - ai_start_waypoints(Pl_objp, aip->wp_list, WPF_REPEAT, 0); + ai_start_waypoints(Pl_objp, 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->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; @@ -4918,7 +4930,7 @@ 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(wp_list->get_waypoints().size())); } if (reached_end) { @@ -4926,7 +4938,7 @@ void ai_waypoints() 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(wp_list->get_waypoints().size() - 1); } else { aip->wp_index = 0; } @@ -4944,10 +4956,10 @@ 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()) { @@ -4955,7 +4967,7 @@ void ai_waypoints() 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))) )); } } @@ -12665,7 +12677,7 @@ 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)) ) { @@ -12673,16 +12685,17 @@ int ai_formation() } } - 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) { 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(wp_list->get_waypoints().size())) --aip->wp_index; } } @@ -15455,7 +15468,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 = INVALID_WAYPOINT_POSITION; aip->wp_index = INVALID_WAYPOINT_POSITION; aip->attacker_objnum = -1; diff --git a/code/ai/aigoals.cpp b/code/ai/aigoals.cpp index d81076df70d..4953b42fc82 100644 --- a/code/ai/aigoals.cpp +++ b/code/ai/aigoals.cpp @@ -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; @@ -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); } } @@ -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; } @@ -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; } diff --git a/code/ai/aigoals.h b/code/ai/aigoals.h index 79868e0135c..9d8cd5475f3 100644 --- a/code/ai/aigoals.h +++ b/code/ai/aigoals.h @@ -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) diff --git a/code/autopilot/autopilot.cpp b/code/autopilot/autopilot.cpp index 42399eaaac8..9d89a629142 100644 --- a/code/autopilot/autopilot.cpp +++ b/code/autopilot/autopilot.cpp @@ -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); } @@ -111,13 +111,16 @@ 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 wp_list = find_waypoint_list_at_index(target_index); + auto wpt = find_waypoint_at_index(wp_list, 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; } } @@ -462,12 +465,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] ); } } @@ -491,7 +494,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++) @@ -505,7 +508,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 ); } } @@ -874,12 +877,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 @@ -1094,9 +1097,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; @@ -1108,7 +1111,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; @@ -1392,7 +1395,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; } } @@ -1433,7 +1436,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 diff --git a/code/autopilot/autopilot.h b/code/autopilot/autopilot.h index 9695ade8b1b..86646b88b41 100644 --- a/code/autopilot/autopilot.h +++ b/code/autopilot/autopilot.h @@ -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(); @@ -53,7 +53,7 @@ class NavPoint visited_color[1] = 0xFF; visited_color[2] = 0x00; - target_obj = nullptr; + target_index = -1; waypoint_num = -1; } }; diff --git a/code/mission/missiontraining.cpp b/code/mission/missiontraining.cpp index 036f219ccb4..8b68c91d44f 100644 --- a/code/mission/missiontraining.cpp +++ b/code/mission/missiontraining.cpp @@ -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; @@ -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; diff --git a/code/mission/missiontraining.h b/code/mission/missiontraining.h index f039b6b959f..4e3a298043f 100644 --- a/code/mission/missiontraining.h +++ b/code/mission/missiontraining.h @@ -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; diff --git a/code/network/multi_obj.cpp b/code/network/multi_obj.cpp index b842e2e8105..3902f495a4e 100644 --- a/code/network/multi_obj.cpp +++ b/code/network/multi_obj.cpp @@ -1493,8 +1493,10 @@ int multi_oo_pack_data(net_player *pl, object *objp, ushort oo_flags, ubyte *dat // either send out the waypoint they are trying to get to *or* their current target if (umode == AIM_WAYPOINTS) { // if it's already started pointing to a waypoint, grab its net_signature and send that instead - if ((aip->wp_list != nullptr) && (aip->wp_index >= 0 && aip->wp_index < static_cast(aip->wp_list->get_waypoints().size()))) { - target_signature = Objects[aip->wp_list->get_waypoints().at(aip->wp_index).get_objnum()].net_signature; + waypoint_list* wpl; + waypoint* wp; + if (((wpl = find_waypoint_list_at_index(aip->wp_list_index)) != nullptr) && ((wp = find_waypoint_at_index(wpl, aip->wp_index)) != nullptr)) { + target_signature = Objects[wp->get_objnum()].net_signature; } } // send the target signature. 2021 Version! else if ((aip->goals[0].target_name != nullptr) && strlen(aip->goals[0].target_name) != 0) { @@ -2124,12 +2126,15 @@ int multi_oo_unpack_data(net_player* pl, ubyte* data, int seq_num, int time_delt Ai_info[shipp->ai_index].goals[0].target_name = nullptr; // set their waypoints if in waypoint mode. } else if (umode == AIM_WAYPOINTS) { - waypoint* destination = find_waypoint_with_instance(target_objp->instance); - if (destination != nullptr) { - Ai_info[shipp->ai_index].wp_list = destination->get_parent_list(); - Ai_info[shipp->ai_index].wp_index = find_index_of_waypoint(Ai_info[shipp->ai_index].wp_list, destination); + int wp_list_index = calc_waypoint_list_index(target_objp->instance); + int wp_index = calc_waypoint_index(target_objp->instance); + waypoint_list* wpl; + if (((wpl = find_waypoint_list_at_index(wp_list_index)) != nullptr) && (find_waypoint_at_index(wpl, wp_index) != nullptr)) { + Ai_info[shipp->ai_index].wp_list_index = wp_list_index; + Ai_info[shipp->ai_index].wp_index = wp_index; } else { - Ai_info[shipp->ai_index].wp_list = nullptr; + Ai_info[shipp->ai_index].wp_list_index = -1; + Ai_info[shipp->ai_index].wp_index = INVALID_WAYPOINT_POSITION; } } else { Ai_info[shipp->ai_index].target_objnum = OBJ_INDEX(target_objp); diff --git a/code/object/waypoint.cpp b/code/object/waypoint.cpp index f02f1fcc370..4c5940430f9 100644 --- a/code/object/waypoint.cpp +++ b/code/object/waypoint.cpp @@ -198,7 +198,7 @@ void waypoint_create_game_objects() waypoint_list *find_matching_waypoint_list(const char *name) { - Assert(name != NULL); + Assert(name != nullptr); for (auto &ii: Waypoint_lists) { @@ -206,7 +206,22 @@ waypoint_list *find_matching_waypoint_list(const char *name) return ⅈ } - return NULL; + return nullptr; +} + +int find_matching_waypoint_list_index(const char *name) +{ + Assert(name != nullptr); + + int i = 0; + for (auto &ii: Waypoint_lists) + { + if (!stricmp(ii.get_name(), name)) + return i; + i++; + } + + return -1; } // NOTE: waypoint names are always in the format Name:index @@ -320,23 +335,18 @@ waypoint *find_waypoint_with_instance(int waypoint_instance) waypoint_list *find_waypoint_list_at_index(int index) { - Assert(index >= 0); - - if (index >= 0 && index < (int)Waypoint_lists.size()) + if (SCP_vector_inbounds(Waypoint_lists, index)) return &Waypoint_lists[index]; - return NULL; + return nullptr; } waypoint *find_waypoint_at_index(waypoint_list *list, int index) { - Assert(list != NULL); - Assert(index >= 0); - - if (index >= 0 && index < (int)list->get_waypoints().size()) + if (list && SCP_vector_inbounds(list->get_waypoints(), index)) return &list->get_waypoints()[index]; - return NULL; + return nullptr; } int find_index_of_waypoint_list(const waypoint_list *wp_list) @@ -417,7 +427,7 @@ int waypoint_add(const vec3d *pos, int waypoint_instance) { // get a name for it char buf[NAME_LENGTH]; - waypoint_find_unique_name(buf, (int)(Waypoint_lists.size() + 1)); + waypoint_find_unique_name(buf, static_cast(Waypoint_lists.size()) + 1); // add new list with that name waypoint_list new_list(buf); @@ -425,8 +435,8 @@ int waypoint_add(const vec3d *pos, int waypoint_instance) wp_list = &Waypoint_lists.back(); // set up references - wp_list_index = (int)(Waypoint_lists.size() - 1); - wp_index = (int) wp_list->get_waypoints().size(); + wp_list_index = static_cast(Waypoint_lists.size()) - 1; + wp_index = static_cast(wp_list->get_waypoints().size()); } // create the waypoint on the same list as, and immediately after, waypoint_instance else @@ -439,7 +449,7 @@ int waypoint_add(const vec3d *pos, int waypoint_instance) // it has to be on, or at the end of, an existing list Assert(wp_list != NULL); - Assert((uint) wp_index <= wp_list->get_waypoints().size()); + Assert(wp_index <= static_cast(wp_list->get_waypoints().size())); // iterate through all waypoints that are at this index or later, // and edit their instances so that they point to a waypoint one place higher diff --git a/code/object/waypoint.h b/code/object/waypoint.h index f59332b6bfa..06cb04862bb 100644 --- a/code/object/waypoint.h +++ b/code/object/waypoint.h @@ -72,6 +72,7 @@ void waypoint_create_game_objects(); // Find a waypoint list with the specified name waypoint_list *find_matching_waypoint_list(const char *name); +int find_matching_waypoint_list_index(const char *name); // Find a waypoint with the specified name (e.g. Path:1) waypoint *find_matching_waypoint(const char *name); diff --git a/code/parse/sexp.cpp b/code/parse/sexp.cpp index 5644a779f8c..084adf976ab 100644 --- a/code/parse/sexp.cpp +++ b/code/parse/sexp.cpp @@ -20215,7 +20215,8 @@ int sexp_waypoint_twice() int sexp_path_flown() { if (Training_context & TRAINING_CONTEXT_FLY_PATH) { - if ((uint) Training_context_goal_waypoint == Training_context_path->get_waypoints().size()){ + auto wp_list = find_waypoint_list_at_index(Training_context_waypoint_path); + if (wp_list && (Training_context_goal_waypoint == static_cast(wp_list->get_waypoints().size()))) { return SEXP_TRUE; } } @@ -24990,8 +24991,8 @@ void sexp_set_training_context_fly_path(int node) return; Training_context |= TRAINING_CONTEXT_FLY_PATH; - Training_context_path = wp_list; - Training_context_distance = (float)distance; + Training_context_waypoint_path = find_index_of_waypoint_list(wp_list); + Training_context_distance = static_cast(distance); Training_context_goal_waypoint = 0; Training_context_at_waypoint = -1; } diff --git a/code/scripting/api/libs/mission.cpp b/code/scripting/api/libs/mission.cpp index 7273f1626c6..0b00d52fbb4 100644 --- a/code/scripting/api/libs/mission.cpp +++ b/code/scripting/api/libs/mission.cpp @@ -1269,8 +1269,8 @@ ADE_FUNC(createWaypoint, l_Mission, "[vector Position, waypointlist List]", int waypoint_instance = -1; if (wlh && wlh->isValid()) { - int wp_list_index = find_index_of_waypoint_list(wlh->wlp); - int wp_index = (int) wlh->wlp->get_waypoints().size() - 1; + int wp_list_index = find_index_of_waypoint_list(wlh->getList()); + int wp_index = static_cast(wlh->getList()->get_waypoints().size()) - 1; waypoint_instance = calc_waypoint_instance(wp_list_index, wp_index); } int obj_idx = waypoint_add(v3 != NULL ? v3 : &vmd_zero_vector, waypoint_instance); diff --git a/code/scripting/api/objs/order.cpp b/code/scripting/api/objs/order.cpp index 3c2017aeebc..df78c346850 100644 --- a/code/scripting/api/objs/order.cpp +++ b/code/scripting/api/objs/order.cpp @@ -243,7 +243,7 @@ ADE_VIRTVAR(Target, l_Order, "object", "Target of the order. Value may also be a flags |= WPF_REPEAT; if (ohp->aigp->flags[AI::Goal_Flags::Waypoints_in_reverse]) flags |= WPF_BACKTRACK; - ai_start_waypoints(ohp->objh.objp(), wpl, flags, ohp->aigp->int_data); + ai_start_waypoints(ohp->objh.objp(), find_index_of_waypoint_list(wpl), flags, ohp->aigp->int_data); } } } @@ -303,9 +303,9 @@ ADE_VIRTVAR(Target, l_Order, "object", "Target of the order. Value may also be a case AI_GOAL_WAYPOINTS: case AI_GOAL_WAYPOINTS_ONCE: // check if waypoint order is the current goal (ohp->odx == 0) and if it is valid - if ( (ohp->odx == 0) && (aip->wp_index != INVALID_WAYPOINT_POSITION) && - (aip->wp_index >= 0 && aip->wp_index < static_cast(aip->wp_list->get_waypoints().size())) ) { - objnum = aip->wp_list->get_waypoints()[aip->wp_index].get_objnum(); + waypoint* wp; + if ( (ohp->odx == 0) && (aip->wp_index != INVALID_WAYPOINT_POSITION) && ((wpl = find_waypoint_list_at_index(aip->wp_list_index)) != nullptr) && ((wp = find_waypoint_at_index(wpl, aip->wp_index)) != nullptr) ) { + objnum = wp->get_objnum(); } else { wpl = find_matching_waypoint_list(ohp->aigp->target_name); if (wpl != nullptr) { diff --git a/code/scripting/api/objs/waypoint.cpp b/code/scripting/api/objs/waypoint.cpp index 49bd22cca31..846bc35faee 100644 --- a/code/scripting/api/objs/waypoint.cpp +++ b/code/scripting/api/objs/waypoint.cpp @@ -31,25 +31,38 @@ ADE_FUNC(getList, l_Waypoint, NULL, "Returns the waypoint list", "waypointlist", return ade_set_error(L, "o", l_WaypointList.Set(waypointlist_h())); } -waypointlist_h::waypointlist_h() {wlp=NULL;name[0]='\0';} -waypointlist_h::waypointlist_h(waypoint_list* n_wlp) { - wlp = n_wlp; - if(n_wlp != NULL) { +waypointlist_h::waypointlist_h() + : wl_index(-1) +{ + name[0] = '\0'; +} +waypointlist_h::waypointlist_h(int _wl_index) +{ + if (SCP_vector_inbounds(Waypoint_lists, _wl_index)) + { + wl_index = _wl_index; + auto wlp = &Waypoint_lists[wl_index]; strcpy_s(name, wlp->get_name()); - } else { - memset(name, 0, sizeof(name)); + } + else + { + wl_index = -1; + name[0] = '\0'; } } +waypointlist_h::waypointlist_h(waypoint_list* _wlp) + : waypointlist_h((_wlp == nullptr) ? -1 : find_index_of_waypoint_list(_wlp)) +{} waypointlist_h::waypointlist_h(const char* wlname) + : waypointlist_h((wlname == nullptr) ? nullptr : find_matching_waypoint_list(name)) +{} +bool waypointlist_h::isValid() const { - wlp = NULL; - if ( wlname != NULL ) { - strcpy_s(name, wlname); - wlp = find_matching_waypoint_list(wlname); - } + return SCP_vector_inbounds(Waypoint_lists, wl_index); } -bool waypointlist_h::isValid() const { - return (wlp != NULL && !strcmp(wlp->get_name(), name)); +waypoint_list* waypointlist_h::getList() const +{ + return isValid() ? &Waypoint_lists[wl_index] : nullptr; } //**********HANDLE: WaypointList @@ -58,8 +71,7 @@ ADE_OBJ(l_WaypointList, waypointlist_h, "waypointlist", "waypointlist handle"); ADE_INDEXER(l_WaypointList, "number Index", "Array of waypoints that are part of the waypoint list", "waypoint", "Waypoint, or invalid handle if the index or waypointlist handle is invalid") { int idx = -1; - waypointlist_h* wlh = NULL; - char wpname[128]; + waypointlist_h* wlh = nullptr; if( !ade_get_args(L, "oi", l_WaypointList.GetPtr( &wlh ), &idx)) return ade_set_error( L, "o", l_Waypoint.Set( object_h() ) ); @@ -69,12 +81,10 @@ ADE_INDEXER(l_WaypointList, "number Index", "Array of waypoints that are part of //Lua-->FS2 idx--; - //Get waypoint name - sprintf(wpname, "%s:%d", wlh->wlp->get_name(), calc_waypoint_index(idx) + 1); - waypoint *wpt = find_matching_waypoint( wpname ); - if( (idx >= 0) && ((uint) idx < wlh->wlp->get_waypoints().size()) && (wpt != NULL) && (wpt->get_objnum() >= 0) ) { - return ade_set_args(L, "o", l_Waypoint.Set(object_h(&Objects[wpt->get_objnum()]))); - } + //Get waypoint + auto wp = find_waypoint_at_index(wlh->getList(), idx); + if (wp) + return ade_set_args(L, "o", l_Waypoint.Set(object_h(wp->get_objnum()))); return ade_set_error(L, "o", l_Waypoint.Set( object_h() ) ); } @@ -86,11 +96,11 @@ ADE_FUNC(__len, l_WaypointList, "number", "Number of waypoints in the list, or 0 if handle is invalid") { - waypointlist_h* wlh = NULL; + waypointlist_h* wlh = nullptr; if ( !ade_get_args(L, "o", l_WaypointList.GetPtr(&wlh)) ) { return ade_set_error( L, "o", l_Waypoint.Set( object_h() ) ); } - return ade_set_args(L, "i", wlh->wlp->get_waypoints().size()); + return ade_set_args(L, "i", wlh->getList()->get_waypoints().size()); } ADE_VIRTVAR(Name, l_WaypointList, "string", "Name of WaypointList", "string", "Waypointlist name, or empty string if handle is invalid") @@ -102,7 +112,7 @@ ADE_VIRTVAR(Name, l_WaypointList, "string", "Name of WaypointList", "string", "W } if(ADE_SETTING_VAR && s != NULL) { - wlh->wlp->set_name(s); + wlh->getList()->set_name(s); strcpy_s(wlh->name,s); } diff --git a/code/scripting/api/objs/waypoint.h b/code/scripting/api/objs/waypoint.h index b05cdae4b1b..e03a4e5f9aa 100644 --- a/code/scripting/api/objs/waypoint.h +++ b/code/scripting/api/objs/waypoint.h @@ -12,12 +12,14 @@ DECLARE_ADE_OBJ(l_Waypoint, object_h); struct waypointlist_h { - waypoint_list *wlp; + int wl_index; char name[NAME_LENGTH]; waypointlist_h(); - explicit waypointlist_h(waypoint_list *n_wlp); + explicit waypointlist_h(int _wl_index); + explicit waypointlist_h(waypoint_list* _wlp); explicit waypointlist_h(const char* wlname); bool isValid() const; + waypoint_list* getList() const; }; DECLARE_ADE_OBJ(l_WaypointList, waypointlist_h); diff --git a/code/ship/ship.cpp b/code/ship/ship.cpp index 1bda9545226..fe89d92a40e 100644 --- a/code/ship/ship.cpp +++ b/code/ship/ship.cpp @@ -17140,9 +17140,10 @@ int ship_return_seconds_to_goal(ship *sp) if ( aip->mode == AIM_WAYPOINTS ) { // Is traveling a waypoint path min_speed = 0.9f * max_speed; - if (aip->wp_list != NULL) { + auto wp_list = find_waypoint_list_at_index(aip->wp_list_index); + if (wp_list != nullptr) { Assert(aip->wp_index != INVALID_WAYPOINT_POSITION); - auto& waypoints = aip->wp_list->get_waypoints(); + auto& waypoints = wp_list->get_waypoints(); // distance to current waypoint dist += vm_vec_dist_quick(&objp->pos, waypoints[aip->wp_index].get_pos()); diff --git a/freespace2/freespace.cpp b/freespace2/freespace.cpp index 3ed6035a101..cd35a6bd2de 100644 --- a/freespace2/freespace.cpp +++ b/freespace2/freespace.cpp @@ -7042,7 +7042,7 @@ void game_do_training_checks() } if (Training_context & TRAINING_CONTEXT_FLY_PATH) { - wplp = Training_context_path; + wplp = find_waypoint_list_at_index(Training_context_waypoint_path); if (wplp->get_waypoints().size() > (uint) Training_context_goal_waypoint) { i = Training_context_goal_waypoint; do {