From: <geo...@us...> - 2011-10-25 20:12:57
|
Revision: 4440 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=4440&view=rev Author: geoffthemedio Date: 2011-10-25 20:12:50 +0000 (Tue, 25 Oct 2011) Log Message: ----------- -Modified Universe::JumpDistance and ShortestPath to catch out of range exception when looking up system indices or LinearDistance and log an error message about it before re-throwing, to help better localize problems calling these functions. -Wrapped calls to Universe::ShortestPath in Fleet.cpp in try/catch blocks to prevent crashes. -Added or modified try/catched calls to LinearDistance, JumpDistance, ShortestPath, LeastJumpsPath, and SystemsConnected in PythonUniverseWrapper.cpp, so AI tests using these functions shouldn't crash the AI client. -Grooming Modified Paths: -------------- trunk/FreeOrion/python/PythonUniverseWrapper.cpp trunk/FreeOrion/universe/Condition.cpp trunk/FreeOrion/universe/Fleet.cpp trunk/FreeOrion/universe/Universe.cpp trunk/FreeOrion/universe/Universe.h Modified: trunk/FreeOrion/python/PythonUniverseWrapper.cpp =================================================================== --- trunk/FreeOrion/python/PythonUniverseWrapper.cpp 2011-10-25 18:25:42 UTC (rev 4439) +++ trunk/FreeOrion/python/PythonUniverseWrapper.cpp 2011-10-25 20:12:50 UTC (rev 4440) @@ -76,22 +76,56 @@ void (Universe::*UpdateMeterEstimatesVoidFunc)(void) = &Universe::UpdateMeterEstimates; - std::vector<int> LeastJumpsPath(const Universe& universe, int start_sys, int end_sys, int empire_id) { - std::pair<std::list<int>, int> path = universe.LeastJumpsPath(start_sys, end_sys, empire_id); - std::vector<int> retval; - std::copy(path.first.begin(), path.first.end(), std::back_inserter(retval)); - return retval; + double LinearDistance(const Universe& universe, int system1_id, int system2_id) { + double retval = 9999999.9; // arbitrary large value + try { + retval = universe.LinearDistance(system1_id, system2_id); + } catch (...) { + } + return retval; + } + boost::function<double(const Universe&, int, int)> LinearDistanceFunc = &LinearDistance; + + int JumpDistance(const Universe& universe, int system1_id, int system2_id) { + try { + return universe.JumpDistance(system1_id, system2_id); + } catch (...) { + } + return -1; } - boost::function<std::vector<int>(const Universe&, int, int, int)> LeastJumpsFunc = &LeastJumpsPath; + boost::function<int(const Universe&, int, int)> JumpDistanceFunc = &JumpDistance; std::vector<int> ShortestPath(const Universe& universe, int start_sys, int end_sys, int empire_id) { - std::pair<std::list<int>, int> path = universe.ShortestPath(start_sys, end_sys, empire_id); std::vector<int> retval; - std::copy(path.first.begin(), path.first.end(), std::back_inserter(retval)); + try { + std::pair<std::list<int>, int> path = universe.ShortestPath(start_sys, end_sys, empire_id); + std::copy(path.first.begin(), path.first.end(), std::back_inserter(retval)); + } catch (...) { + } return retval; } boost::function<std::vector<int>(const Universe&, int, int, int)> ShortestPathFunc = &ShortestPath; + std::vector<int> LeastJumpsPath(const Universe& universe, int start_sys, int end_sys, int empire_id) { + std::vector<int> retval; + try { + std::pair<std::list<int>, int> path = universe.LeastJumpsPath(start_sys, end_sys, empire_id); + std::copy(path.first.begin(), path.first.end(), std::back_inserter(retval)); + } catch (...) { + } + return retval; + } + boost::function<std::vector<int>(const Universe&, int, int, int)> LeastJumpsFunc = &LeastJumpsPath; + + bool SystemsConnected(const Universe& universe, int system1_id, int system2_id) { + try { + return universe.SystemsConnected(system1_id, system2_id); + } catch (...) { + } + return false; + } + boost::function<bool(const Universe&, int, int)> SystemsConnectedFunc = &SystemsConnected; + const Meter* (UniverseObject::*ObjectGetMeter)(MeterType) const = &UniverseObject::GetMeter; boost::function<double(const UniverseObject*, MeterType)> InitialCurrentMeterValueFromObject = Modified: trunk/FreeOrion/universe/Condition.cpp =================================================================== --- trunk/FreeOrion/universe/Condition.cpp 2011-10-25 18:25:42 UTC (rev 4439) +++ trunk/FreeOrion/universe/Condition.cpp 2011-10-25 20:12:50 UTC (rev 4440) @@ -4794,7 +4794,6 @@ // test graph. for (std::set<const System*>::const_iterator it = destination_systems.begin(); it != destination_systems.end(); ++it) {} - //SystemsConnected(graph_impl return true; } Modified: trunk/FreeOrion/universe/Fleet.cpp =================================================================== --- trunk/FreeOrion/universe/Fleet.cpp 2011-10-25 18:25:42 UTC (rev 4439) +++ trunk/FreeOrion/universe/Fleet.cpp 2011-10-25 20:12:50 UTC (rev 4440) @@ -104,7 +104,14 @@ if (!travel_route.empty() && travel_route.front() != 0 && travel_route.size() != copied_fleet_route.size()) { if (moving_to == copied_fleet->m_moving_to) moving_to = travel_route.back(); - travel_distance -= GetUniverse().ShortestPath(travel_route.back(), copied_fleet_route.back()).second; + try { + travel_distance -= GetUniverse().ShortestPath(travel_route.back(), + copied_fleet_route.back()).second; + } catch (...) { + Logger().debugStream() << "Fleet::Copy couldn't find route to system(s):" + << " travel route back: " << travel_route.back() + << " or copied fleet route back: " << copied_fleet_route.back(); + } } this->m_moving_to = moving_to; @@ -956,7 +963,13 @@ if (!objects.Object<System>(m_moving_to)) return; // destination system doesn't exist or doesn't exist in known universe, so can't move to it. leave route empty. - std::pair<std::list<int>, double> path = universe.ShortestPath(m_prev_system, m_moving_to, this->Owner()); + std::pair<std::list<int>, double> path; + try { + path = universe.ShortestPath(m_prev_system, m_moving_to, this->Owner()); + } catch (...) { + Logger().debugStream() << "Fleet::CalculateRoute couldn't find route to system(s):" + << " fleet's previous: " << m_prev_system << " or moving to: " << m_moving_to; + } m_travel_route = path.first; m_travel_distance = path.second; @@ -966,19 +979,26 @@ int dest_system_id = m_moving_to; + // Geoff: commenting out the early exit code of the owner of a fleet doesn't + // have visibility of the destination system, since this was preventing the + // human client's attempts to find routes for enemy fleets, for which the + // player's client doesn't know which systems are visible, and since + // visibility of a system on the current turn isn't necessary to plot + // route to it now that empire's can remember systems they've seen on + // previous turns. //if (universe.GetObjectVisibilityByEmpire(dest_system_id, this->Owner()) <= VIS_NO_VISIBILITY) { // // destination system isn't visible to this fleet's owner, so the fleet can't move to it - + // // // check if system to which fleet is moving is visible to the fleet's owner. this should always be true, but just in case... // if (universe.GetObjectVisibilityByEmpire(m_next_system, this->Owner()) <= VIS_NO_VISIBILITY) // return; // next system also isn't visible; leave route empty. - + // // // safety check: ensure supposedly visible object actually exists in known universe. // if (!GetObject<System>(m_next_system)) { // Logger().errorStream() << "Fleet::CalculateRoute found system with id " << m_next_system << " should be visible to this fleet's owner, but the system doesn't exist in the known universe!"; // return; // abort if object doesn't exist in known universe... can't path to it if it's not there, even if it's considered visible for some reason... // } - + // // // next system is visible, so move to that instead of ordered destination (m_moving_to) // dest_system_id = m_next_system; //} @@ -986,7 +1006,13 @@ // if we're between systems, the shortest route may be through either one if (this->CanChangeDirectionEnRoute()) { - std::pair<std::list<int>, double> path1 = universe.ShortestPath(m_next_system, dest_system_id, this->Owner()); + std::pair<std::list<int>, double> path1; + try { + path1 = universe.ShortestPath(m_next_system, dest_system_id, this->Owner()); + } catch (...) { + Logger().debugStream() << "Fleet::CalculateRoute couldn't find route to system(s):" + << " fleet's next: " << m_next_system << " or destination: " << dest_system_id; + } const std::list<int>& sys_list1 = path1.first; if (sys_list1.empty()) { Logger().errorStream() << "Fleet::CalculateRoute got empty route from ShortestPath"; @@ -1001,7 +1027,13 @@ double dist_y = obj->Y() - this->Y(); double dist1 = std::sqrt(dist_x*dist_x + dist_y*dist_y); - std::pair<std::list<int>, double> path2 = universe.ShortestPath(m_prev_system, dest_system_id, this->Owner()); + std::pair<std::list<int>, double> path2; + try { + path2 = universe.ShortestPath(m_prev_system, dest_system_id, this->Owner()); + } catch (...) { + Logger().debugStream() << "Fleet::CalculateRoute couldn't find route to system(s):" + << " fleet's previous: " << m_prev_system << " or destination: " << dest_system_id; + } const std::list<int>& sys_list2 = path2.first; if (sys_list2.empty()) { Logger().errorStream() << "Fleet::CalculateRoute got empty route from ShortestPath"; @@ -1027,7 +1059,13 @@ } else { - std::pair<std::list<int>, double> route = universe.ShortestPath(m_next_system, dest_system_id, this->Owner()); + std::pair<std::list<int>, double> route; + try { + route = universe.ShortestPath(m_next_system, dest_system_id, this->Owner()); + } catch (...) { + Logger().debugStream() << "Fleet::CalculateRoute couldn't find route to system(s):" + << " fleet's next: " << m_next_system << " or destination: " << dest_system_id; + } const std::list<int>& sys_list = route.first; if (sys_list.empty()) { Logger().errorStream() << "Fleet::CalculateRoute got empty route from ShortestPath"; Modified: trunk/FreeOrion/universe/Universe.cpp =================================================================== --- trunk/FreeOrion/universe/Universe.cpp 2011-10-25 18:25:42 UTC (rev 4439) +++ trunk/FreeOrion/universe/Universe.cpp 2011-10-25 20:12:50 UTC (rev 4440) @@ -220,15 +220,19 @@ typedef typename boost::property_map<Graph, boost::vertex_index_t>::const_type ConstIndexPropertyMap; typedef typename boost::property_map<Graph, boost::edge_weight_t>::const_type ConstEdgeWeightPropertyMap; - std::pair<std::list<int>, double> retval; + std::pair<std::list<int>, double> retval(std::list<int>(), -1.0); ConstSystemIDPropertyMap sys_id_property_map = boost::get(vertex_system_id_t(), graph); + // convert system IDs to graph indices. try/catch for invalid input system ids. + int system1_index, system2_index; + try { + system1_index = id_to_graph_index.at(system1_id); + system2_index = id_to_graph_index.at(system2_id); + } catch (...) { + return retval; + } - int system1_index = id_to_graph_index.at(system1_id); - int system2_index = id_to_graph_index.at(system2_id); - - // early exit if systems are the same if (system1_id == system2_id) { retval.first.push_back(system2_id); @@ -617,50 +621,96 @@ } double Universe::LinearDistance(int system1_id, int system2_id) const -{ return m_system_distances[m_system_id_to_graph_index.at(system1_id)][m_system_id_to_graph_index.at(system2_id)]; } +{ + try { + int system1_index = m_system_id_to_graph_index.at(system1_id); + int system2_index = m_system_id_to_graph_index.at(system2_id); + return m_system_distances[system1_index][system2_index]; + } catch (const std::out_of_range&) { + Logger().errorStream() << "Universe::LinearDistance passed invalid system id(s): " + << system1_id << " & " << system2_id; + throw; + } +} short Universe::JumpDistance(int system1_id, int system2_id) const { - //Logger().debugStream() << "JumpDistance(" << system1_id << ": " << GetObject(system1_id)->Name() << ", " - // << system2_id << ": " << GetObject(system2_id)->Name() << "): " - // << m_system_jumps[m_system_id_to_graph_index.at(system1_id)][m_system_id_to_graph_index.at(system2_id)]; - if (system1_id == UniverseObject::INVALID_OBJECT_ID || system2_id == UniverseObject::INVALID_OBJECT_ID) - return -1; - short jumps = -1; try { - jumps = m_system_jumps[m_system_id_to_graph_index.at(system1_id)][m_system_id_to_graph_index.at(system2_id)]; + int system1_index = m_system_id_to_graph_index.at(system1_id); + int system2_index = m_system_id_to_graph_index.at(system2_id); + short jumps = m_system_jumps[system1_index][system2_index]; + if (jumps == SHRT_MAX) // value returned for no valid path + return -1; + return jumps; } catch (const std::out_of_range&) { - Logger().errorStream() << "Universe::JumpsDistance passed invalid system id"; - return -1; + Logger().errorStream() << "Universe::JumpDistance passed invalid system id(s): " + << system1_id << " & " << system2_id; + throw; } - if (jumps == SHRT_MAX) // value returned for no valid path - return -1; - return jumps; } std::pair<std::list<int>, double> Universe::ShortestPath(int system1_id, int system2_id, int empire_id/* = ALL_EMPIRES*/) const { - double linear_distance = LinearDistance(system1_id, system2_id); if (empire_id == ALL_EMPIRES) { - return ShortestPathImpl(m_graph_impl->system_graph, system1_id, system2_id, linear_distance, m_system_id_to_graph_index); - } else { - GraphImpl::EmpireViewSystemGraphMap::const_iterator graph_it = m_graph_impl->empire_system_graph_views.find(empire_id); - if (graph_it != m_graph_impl->empire_system_graph_views.end()) - return ShortestPathImpl(*graph_it->second, system1_id, system2_id, linear_distance, m_system_id_to_graph_index); + // find path on full / complete system graph + try { + double linear_distance = LinearDistance(system1_id, system2_id); + return ShortestPathImpl(m_graph_impl->system_graph, system1_id, system2_id, + linear_distance, m_system_id_to_graph_index); + } catch (const std::out_of_range&) { + Logger().errorStream() << "Universe::ShortestPath passed invalid system id(s): " + << system1_id << " & " << system2_id; + throw; + } } - return std::pair<std::list<int>, double>(); + + // find path on single empire's view of system graph + GraphImpl::EmpireViewSystemGraphMap::const_iterator graph_it = + m_graph_impl->empire_system_graph_views.find(empire_id); + if (graph_it == m_graph_impl->empire_system_graph_views.end()) { + Logger().errorStream() << "Universe::ShortestPath passed unknown empire id: " << empire_id; + throw std::out_of_range("Universe::ShortestPath passed unknown empire id"); + } + try { + double linear_distance = LinearDistance(system1_id, system2_id); + return ShortestPathImpl(*graph_it->second, system1_id, system2_id, + linear_distance, m_system_id_to_graph_index); + } catch (const std::out_of_range&) { + Logger().errorStream() << "Universe::ShortestPath passed invalid system id(s): " + << system1_id << " & " << system2_id; + throw; + } } std::pair<std::list<int>, int> Universe::LeastJumpsPath(int system1_id, int system2_id, int empire_id/* = ALL_EMPIRES*/, int max_jumps/* = INT_MAX*/) const { if (empire_id == ALL_EMPIRES) { - return LeastJumpsPathImpl(m_graph_impl->system_graph, system1_id, system2_id, m_system_id_to_graph_index, max_jumps); - } else { - GraphImpl::EmpireViewSystemGraphMap::const_iterator graph_it = m_graph_impl->empire_system_graph_views.find(empire_id); - if (graph_it != m_graph_impl->empire_system_graph_views.end()) - return LeastJumpsPathImpl(*graph_it->second, system1_id, system2_id, m_system_id_to_graph_index, max_jumps); + // find path on full / complete system graph + try { + return LeastJumpsPathImpl(m_graph_impl->system_graph, system1_id, system2_id, + m_system_id_to_graph_index, max_jumps); + } catch (const std::out_of_range&) { + Logger().errorStream() << "Universe::LeastJumpsPath passed invalid system id(s): " + << system1_id << " & " << system2_id; + throw; + } } - return std::pair<std::list<int>, int>(); + + // find path on single empire's view of system graph + GraphImpl::EmpireViewSystemGraphMap::const_iterator graph_it = + m_graph_impl->empire_system_graph_views.find(empire_id); + if (graph_it == m_graph_impl->empire_system_graph_views.end()) { + Logger().errorStream() << "Universe::LeastJumpsPath passed unknown empire id: " << empire_id; + throw std::out_of_range("Universe::LeastJumpsPath passed unknown empire id"); + } + try { + return LeastJumpsPathImpl(*graph_it->second, system1_id, system2_id, + m_system_id_to_graph_index, max_jumps); + } catch (const std::out_of_range&) { + Logger().errorStream() << "Universe::LeastJumpsPath passed invalid system id(s): " + << system1_id << " & " << system2_id; + throw; + } } bool Universe::SystemsConnected(int system1_id, int system2_id, int empire_id) const Modified: trunk/FreeOrion/universe/Universe.h =================================================================== --- trunk/FreeOrion/universe/Universe.h 2011-10-25 18:25:42 UTC (rev 4439) +++ trunk/FreeOrion/universe/Universe.h 2011-10-25 20:12:50 UTC (rev 4440) @@ -118,11 +118,23 @@ * ids is returned */ const std::set<int>& EmpireKnownShipDesignIDs(int empire_id) const; - Visibility GetObjectVisibilityByEmpire(int object_id, int empire_id) const;///< returns the Visibility level of empire with id \a empire_id of UniverseObject with id \a object_id as determined by calling UpdateEmpireObjectVisibilities - const VisibilityTurnMap&GetObjectVisibilityTurnMapByEmpire(int object_id, int empire_id) const; ///< returns the map from Visibility level to turn number on which the empire with id \a empire_id last had the various Visibility levels of the UniverseObject with id \a object_id . The returned map may be empty or not have entries for all visibility levels, if the empire has not seen the object at that visibility level yet. + /** Returns the Visibility level of empire with id \a empire_id of + * UniverseObject with id \a object_id as determined by calling + * UpdateEmpireObjectVisibilities. */ + Visibility GetObjectVisibilityByEmpire(int object_id, int empire_id) const; - double LinearDistance(int system1_id, int system2_id) const; ///< returns the straight-line distance between the systems with the given IDs. \throw std::out_of_range This function will throw if either system ID is out of range. + /** Returns the map from Visibility level to turn number on which the empire + * with id \a empire_id last had the various Visibility levels of the + * UniverseObject with id \a object_id . The returned map may be empty or + * not have entries for all visibility levels, if the empire has not seen + * the object at that visibility level yet. */ + const VisibilityTurnMap&GetObjectVisibilityTurnMapByEmpire(int object_id, int empire_id) const; + /** Returns the straight-line distance between the systems with the given + * IDs. \throw std::out_of_range This function will throw if either system + * ID is out of range. */ + double LinearDistance(int system1_id, int system2_id) const; + /** Returns the number of starlane jumps between the systems with the given * IDs. If there is no path between the systems, -1 is returned. * \throw std::out_of_range This function will throw if either system @@ -137,7 +149,7 @@ * using the visibility for empire \a empire_id, or without regard to * visibility if \a empire_id == ALL_EMPIRES. * \throw std::out_of_range This function will throw if either system ID - * is out of range. */ + * is out of range, or if the empire ID is not known. */ std::pair<std::list<int>, double> ShortestPath(int system1_id, int system2_id, int empire_id = ALL_EMPIRES) const; @@ -147,15 +159,18 @@ * exists, the list will be empty. The path is calculated using the * visibility for empire \a empire_id, or without regard to visibility if * \a empire_id == ALL_EMPIRES. \throw std::out_of_range This function - * will throw if either system ID is out of range. */ + * will throw if either system ID is out of range or if the empire ID is + * not known. */ std::pair<std::list<int>, int> - LeastJumpsPath(int system1_id, int system2_id, int empire_id = ALL_EMPIRES, int max_jumps = INT_MAX) const; - + LeastJumpsPath(int system1_id, int system2_id, int empire_id = ALL_EMPIRES, + int max_jumps = INT_MAX) const; + /** Returns whether there is a path known to empire \a empire_id between * system \a system1 and system \a system2. The path is calculated using * the visibility for empire \a empire_id, or without regard to visibility * if \a empire_id == ALL_EMPIRES. \throw std::out_of_range This function - * will throw if either system ID is out of range. */ + * will throw if either system ID is out of range or if the empire ID is + * not known. */ bool SystemsConnected(int system1_id, int system2_id, int empire_id = ALL_EMPIRES) const; /** Returns true iff \a system is reachable from another system (i.e. it @@ -164,9 +179,7 @@ * groups of locally but not globally interconnected systems may exist. * The starlanes considered depend on their visibility for empire * \a empire_id, or without regard to visibility if - * \a empire_id == ALL_EMPIRES. - * \throw std::out_of_range This function will throw if the system ID is - * out of range. */ + * \a empire_id == ALL_EMPIRES. */ bool SystemHasVisibleStarlanes(int system_id, int empire_id = ALL_EMPIRES) const; /** Returns the systems that are one starlane hop away from system @@ -438,7 +451,6 @@ * relevant effect accounting for those objects and meters. */ void UpdateMeterEstimatesImpl(const std::vector<int>& objects_vec); - /** Generates planets for all systems that have empty object maps (ie those * that aren't homeworld systems).*/ void PopulateSystems(GalaxySetupOption density); |