From 4b6c3b1d67be6d0ac09ab3504bee1344e488a120 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 | 64 ++++++++++++++---------- code/ai/aigoals.cpp | 14 +++--- code/ai/aigoals.h | 2 +- code/autopilot/autopilot.cpp | 32 ++++++------ code/autopilot/autopilot.h | 4 +- code/mission/missiontraining.cpp | 4 +- code/mission/missiontraining.h | 2 +- code/network/multi_obj.cpp | 17 ++++--- code/object/waypoint.cpp | 61 +++++++++++++--------- code/object/waypoint.h | 2 + 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 | 75 ++++++++++++++-------------- code/scripting/api/objs/waypoint.h | 7 +-- code/ship/ship.cpp | 5 +- freespace2/freespace.cpp | 2 +- 18 files changed, 176 insertions(+), 140 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..6a026116968 100644 --- a/code/ai/aicode.cpp +++ b/code/ai/aicode.cpp @@ -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) { @@ -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; @@ -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; @@ -4918,7 +4927,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 +4935,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 +4953,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 +4964,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 +12674,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 +12682,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 != 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(wp_list->get_waypoints().size())) --aip->wp_index; } } @@ -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; 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..4cd14ac6b53 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,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; } } @@ -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] ); } } @@ -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++) @@ -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 ); } } @@ -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 @@ -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; @@ -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; @@ -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; } } @@ -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 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..139bea759e8 100644 --- a/code/network/multi_obj.cpp +++ b/code/network/multi_obj.cpp @@ -1493,8 +1493,9 @@ 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* wp; + if ((wp = find_waypoint_at_indexes(aip->wp_list_index, 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 +2125,14 @@ 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); + if (find_waypoint_at_indexes(wp_list_index, 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..e4f8bfe2bb4 100644 --- a/code/object/waypoint.cpp +++ b/code/object/waypoint.cpp @@ -153,13 +153,17 @@ void calc_waypoint_indexes(int waypoint_instance, int &waypoint_list_index, int int calc_waypoint_list_index(int waypoint_instance) { - Assert(waypoint_instance >= 0); + if (waypoint_instance < 0) + return -1; + return waypoint_instance / 0x10000; } int calc_waypoint_index(int waypoint_instance) { - Assert(waypoint_instance >= 0); + if (waypoint_instance < 0) + return -1; + return waypoint_instance & 0xffff; } @@ -198,7 +202,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 +210,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 @@ -309,34 +328,30 @@ waypoint_list *find_waypoint_list_with_instance(int waypoint_instance, int *wayp waypoint *find_waypoint_with_instance(int waypoint_instance) { if (waypoint_instance < 0) - return NULL; - - waypoint_list *wp_list = find_waypoint_list_at_index(calc_waypoint_list_index(waypoint_instance)); - if (wp_list == NULL) - return NULL; + return nullptr; - return find_waypoint_at_index(wp_list, calc_waypoint_index(waypoint_instance)); + return find_waypoint_at_indexes(calc_waypoint_list_index(waypoint_instance), calc_waypoint_index(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; +} + +waypoint *find_waypoint_at_indexes(int list_index, int index) +{ + return find_waypoint_at_index(find_waypoint_list_at_index(list_index), index); } int find_index_of_waypoint_list(const waypoint_list *wp_list) @@ -417,7 +432,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 +440,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 +454,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..5d225e71cef 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); @@ -84,6 +85,7 @@ waypoint *find_waypoint_with_instance(int waypoint_instance); // Find something at the specified index waypoint_list *find_waypoint_list_at_index(int index); waypoint *find_waypoint_at_index(waypoint_list *list, int index); +waypoint *find_waypoint_at_indexes(int list_index, int index); int find_index_of_waypoint_list(const waypoint_list *wp_list); int find_index_of_waypoint(const waypoint_list *wp_list, const waypoint *wpt); 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..ed7a4a214c6 100644 --- a/code/scripting/api/objs/waypoint.cpp +++ b/code/scripting/api/objs/waypoint.cpp @@ -13,43 +13,41 @@ ADE_OBJ_DERIV(l_Waypoint, object_h, "waypoint", "waypoint handle", l_Object); ADE_FUNC(getList, l_Waypoint, NULL, "Returns the waypoint list", "waypointlist", "waypointlist handle or invalid handle if waypoint was invalid") { object_h *oh = NULL; - waypointlist_h wpl; waypoint_list *wp_list = NULL; if(!ade_get_args(L, "o", l_Waypoint.GetPtr(&oh))) return ade_set_error(L, "o", l_WaypointList.Set(waypointlist_h())); if(oh->isValid() && oh->objp()->type == OBJ_WAYPOINT) { wp_list = find_waypoint_list_with_instance(oh->objp()->instance); - if(wp_list != NULL) - wpl = waypointlist_h(wp_list); - } - - if (wpl.isValid()) { - return ade_set_args(L, "o", l_WaypointList.Set(wpl)); + return ade_set_args(L, "o", l_WaypointList.Set(waypointlist_h(wp_list))); } 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) { - strcpy_s(name, wlp->get_name()); - } else { - memset(name, 0, sizeof(name)); - } +waypointlist_h::waypointlist_h() + : wl_index(-1) +{} +waypointlist_h::waypointlist_h(int _wl_index) +{ + if (SCP_vector_inbounds(Waypoint_lists, _wl_index)) + wl_index = _wl_index; + else + wl_index = -1; } +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(wlname)) +{} +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,23 +56,20 @@ 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() ) ); - if(!wlh->isValid()) + if(!wlh || !wlh->isValid()) return ade_set_error( L, "o", l_Waypoint.Set( object_h() ) ); //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 +81,15 @@ 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_error(L, "i", 0); + } + if (!wlh || !wlh->isValid()) { + return ade_set_error(L, "i", 0); } - 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") @@ -100,13 +99,15 @@ ADE_VIRTVAR(Name, l_WaypointList, "string", "Name of WaypointList", "string", "W if ( !ade_get_args(L, "o|s", l_WaypointList.GetPtr(&wlh), &s) ) { return ade_set_error(L, "s", ""); } + if (!wlh || !wlh->isValid()) { + return ade_set_error(L, "s", ""); + } if(ADE_SETTING_VAR && s != NULL) { - wlh->wlp->set_name(s); - strcpy_s(wlh->name,s); + wlh->getList()->set_name(s); } - return ade_set_args( L, "s", wlh->name); + return ade_set_args( L, "s", wlh->getList()->get_name()); } ADE_FUNC(isValid, l_WaypointList, NULL, "Return if this waypointlist handle is valid", "boolean", "true if valid false otherwise") diff --git a/code/scripting/api/objs/waypoint.h b/code/scripting/api/objs/waypoint.h index b05cdae4b1b..19ece7f28ea 100644 --- a/code/scripting/api/objs/waypoint.h +++ b/code/scripting/api/objs/waypoint.h @@ -12,12 +12,13 @@ DECLARE_ADE_OBJ(l_Waypoint, object_h); struct waypointlist_h { - waypoint_list *wlp; - char name[NAME_LENGTH]; + int wl_index; 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 {