WaypointPtr Path::nextLocation() { if(path.size()==0) return WaypointPtr(); if(currentNode!= path.begin()) currentNode--; else { scripting->executeString(onComplete); return WaypointPtr(); } return *currentNode; }
WaypointPtr WaypointManager::nearestVisibleWaypoint(D3DXVECTOR3 target) { WaypointPtr wp; float minDist = 65535; WaypointList seen = visibleWaypoints(target); if(seen.size()==0) return WaypointPtr(); for(int i=0; i<seen.size(); i++) { float d = D3DXVec3Length(&(waypoints[seen[i]]->_position - target)); if(d<minDist) { wp = waypoints[seen[i]]; minDist = d; } } return wp; }
bool IOMap::loadMap(Map* map, const std::string& identifier) { FileLoader f; if(!f.openFile(identifier.c_str(), false, true)) { std::stringstream ss; ss << "Could not open the file " << identifier << "."; setLastErrorString(ss.str()); return false; } uint32_t type = 0; NODE root = f.getChildNode((NODE)NULL, type); PropStream propStream; if(!f.getProps(root, propStream)) { setLastErrorString("Could not read root property."); return false; } OTBM_root_header* rootHeader; if(!propStream.GET_STRUCT(rootHeader)) { setLastErrorString("Could not read header."); return false; } uint32_t headerVersion = rootHeader->version; if(headerVersion <= 0) { //In otbm version 1 the count variable after splashes/fluidcontainers and stackables //are saved as attributes instead, this solves alot of problems with items //that is changed (stackable/charges/fluidcontainer/splash) during an update. setLastErrorString("This map needs to be upgraded by using the latest map editor version to be able to load correctly."); return false; } if(headerVersion > 2) { setLastErrorString("Unknown OTBM version detected."); return false; } uint32_t headerMajorItems = rootHeader->majorVersionItems; if(headerMajorItems < 3) { setLastErrorString("This map needs to be upgraded by using the latest map editor version to be able to load correctly."); return false; } if(headerMajorItems > (uint32_t)Items::dwMajorVersion) { setLastErrorString("The map was saved with a different items.otb version, an upgraded items.otb is required."); return false; } uint32_t headerMinorItems = rootHeader->minorVersionItems; if(headerMinorItems < CLIENT_VERSION_810) { setLastErrorString("This map needs an updated items.otb."); return false; } if(headerMinorItems > (uint32_t)Items::dwMinorVersion) setLastErrorString("This map needs an updated items.otb."); std::cout << "> Map size: " << rootHeader->width << "x" << rootHeader->height << "." << std::endl; map->mapWidth = rootHeader->width; map->mapHeight = rootHeader->height; NODE nodeMap = f.getChildNode(root, type); if(type != OTBM_MAP_DATA) { setLastErrorString("Could not read data node."); return false; } if(!f.getProps(nodeMap, propStream)) { setLastErrorString("Could not read map data attributes."); return false; } std::string tmp; uint8_t attribute; while(propStream.GET_UCHAR(attribute)) { switch(attribute) { case OTBM_ATTR_DESCRIPTION: { if(!propStream.GET_STRING(tmp)) { setLastErrorString("Invalid description tag."); return false; } map->descriptions.push_back(tmp); break; } case OTBM_ATTR_EXT_SPAWN_FILE: { if(!propStream.GET_STRING(tmp)) { setLastErrorString("Invalid spawnfile tag."); return false; } map->spawnfile = identifier.substr(0, identifier.rfind('/') + 1); map->spawnfile += tmp; break; } case OTBM_ATTR_EXT_HOUSE_FILE: { if(!propStream.GET_STRING(tmp)) { setLastErrorString("Invalid housefile tag."); return false; } map->housefile = identifier.substr(0, identifier.rfind('/') + 1); map->housefile += tmp; break; } default: { setLastErrorString("Unknown header node."); return false; } } } std::cout << "> Map descriptions: " << std::endl; for(StringVec::iterator it = map->descriptions.begin(); it != map->descriptions.end(); ++it) std::cout << (*it) << std::endl; NODE nodeMapData = f.getChildNode(nodeMap, type); while(nodeMapData != NO_NODE) { if(f.getError() != ERROR_NONE) { setLastErrorString("Invalid map node."); return false; } if(type == OTBM_TILE_AREA) { if(!f.getProps(nodeMapData, propStream)) { setLastErrorString("Invalid map node."); return false; } OTBM_Destination_coords* area_coord; if(!propStream.GET_STRUCT(area_coord)) { setLastErrorString("Invalid map node."); return false; } int32_t base_x = area_coord->_x, base_y = area_coord->_y, base_z = area_coord->_z; NODE nodeTile = f.getChildNode(nodeMapData, type); while(nodeTile != NO_NODE) { if(f.getError() != ERROR_NONE) { setLastErrorString("Could not read node data."); return false; } if(type == OTBM_TILE || type == OTBM_HOUSETILE) { if(!f.getProps(nodeTile, propStream)) { setLastErrorString("Could not read node data."); return false; } OTBM_Tile_coords* tileCoord; if(!propStream.GET_STRUCT(tileCoord)) { setLastErrorString("Could not read tile position."); return false; } Tile* tile = NULL; Item* groundItem = NULL; uint32_t tileflags = 0; uint16_t px = base_x + tileCoord->_x, py = base_y + tileCoord->_y, pz = base_z; House* house = NULL; if(type == OTBM_HOUSETILE) { uint32_t _houseid; if(!propStream.GET_ULONG(_houseid)) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Could not read house id."; setLastErrorString(ss.str()); return false; } house = Houses::getInstance().getHouse(_houseid, true); if(!house) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Could not create house id: " << _houseid; setLastErrorString(ss.str()); return false; } tile = new HouseTile(px, py, pz, house); house->addTile(static_cast<HouseTile*>(tile)); } //read tile attributes uint8_t attribute; while(propStream.GET_UCHAR(attribute)) { switch(attribute) { case OTBM_ATTR_TILE_FLAGS: { uint32_t flags; if(!propStream.GET_ULONG(flags)) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to read tile flags."; setLastErrorString(ss.str()); return false; } if((flags & TILESTATE_PROTECTIONZONE) == TILESTATE_PROTECTIONZONE) tileflags |= TILESTATE_PROTECTIONZONE; else if((flags & TILESTATE_NOPVPZONE) == TILESTATE_NOPVPZONE) tileflags |= TILESTATE_NOPVPZONE; else if((flags & TILESTATE_PVPZONE) == TILESTATE_PVPZONE) tileflags |= TILESTATE_PVPZONE; if((flags & TILESTATE_NOLOGOUT) == TILESTATE_NOLOGOUT) tileflags |= TILESTATE_NOLOGOUT; if((flags & TILESTATE_REFRESH) == TILESTATE_REFRESH) { if(house) std::cout << "[x:" << px << ", y:" << py << ", z:" << pz << "] House tile flagged as refreshing!"; tileflags |= TILESTATE_REFRESH; } break; } case OTBM_ATTR_ITEM: { Item* item = Item::CreateItem(propStream); if(!item) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to create item."; setLastErrorString(ss.str()); return false; } if(house && item->isMoveable()) { std::cout << "[Warning - IOMap::loadMap] Movable item in house: " << house->getHouseId(); std::cout << ", item type: " << item->getID() << ", at position " << px << "/" << py << "/"; std::cout << pz << std::endl; delete item; item = NULL; } else if(tile) { tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } else if(item->isGroundTile()) { if(groundItem) delete groundItem; groundItem = item; } else { tile = createTile(groundItem, item, px, py, pz); tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } break; } default: { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Unknown tile attribute."; setLastErrorString(ss.str()); return false; } } } NODE nodeItem = f.getChildNode(nodeTile, type); while(nodeItem) { if(type == OTBM_ITEM) { PropStream propStream; f.getProps(nodeItem, propStream); Item* item = Item::CreateItem(propStream); if(!item) { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to create item."; setLastErrorString(ss.str()); return false; } if(item->unserializeItemNode(f, nodeItem, propStream)) { if(house && item->isMoveable()) { std::cout << "[Warning - IOMap::loadMap] Movable item in house: "; std::cout << house->getHouseId() << ", item type: " << item->getID(); std::cout << ", pos " << px << "/" << py << "/" << pz << std::endl; delete item; item = NULL; } else if(tile) { tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } else if(item->isGroundTile()) { if(groundItem) delete groundItem; groundItem = item; } else { tile = createTile(groundItem, item, px, py, pz); tile->__internalAddThing(item); item->__startDecaying(); item->setLoadedFromMap(true); } } else { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Failed to load item " << item->getID() << "."; setLastErrorString(ss.str()); delete item; item = NULL; return false; } } else { std::stringstream ss; ss << "[x:" << px << ", y:" << py << ", z:" << pz << "] Unknown node type."; setLastErrorString(ss.str()); } nodeItem = f.getNextNode(nodeItem, type); } if(!tile) tile = createTile(groundItem, NULL, px, py, pz); tile->setFlag((tileflags_t)tileflags); map->setTile(px, py, pz, tile); } else { setLastErrorString("Unknown tile node."); return false; } nodeTile = f.getNextNode(nodeTile, type); } } else if(type == OTBM_TOWNS) { NODE nodeTown = f.getChildNode(nodeMapData, type); while(nodeTown != NO_NODE) { if(type == OTBM_TOWN) { if(!f.getProps(nodeTown, propStream)) { setLastErrorString("Could not read town data."); return false; } uint32_t townId = 0; if(!propStream.GET_ULONG(townId)) { setLastErrorString("Could not read town id."); return false; } Town* town = Towns::getInstance().getTown(townId); if(!town) { town = new Town(townId); Towns::getInstance().addTown(townId, town); } std::string townName = ""; if(!propStream.GET_STRING(townName)) { setLastErrorString("Could not read town name."); return false; } town->setName(townName); OTBM_Destination_coords *town_coords; if(!propStream.GET_STRUCT(town_coords)) { setLastErrorString("Could not read town coordinates."); return false; } town->setTemplePos(Position(town_coords->_x, town_coords->_y, town_coords->_z)); } else { setLastErrorString("Unknown town node."); return false; } nodeTown = f.getNextNode(nodeTown, type); } } else if(type == OTBM_WAYPOINTS && headerVersion > 1) { NODE nodeWaypoint = f.getChildNode(nodeMapData, type); while(nodeWaypoint != NO_NODE) { if(type == OTBM_WAYPOINT) { if(!f.getProps(nodeWaypoint, propStream)) { setLastErrorString("Could not read waypoint data."); return false; } std::string name; if(!propStream.GET_STRING(name)) { setLastErrorString("Could not read waypoint name."); return false; } OTBM_Destination_coords* waypoint_coords; if(!propStream.GET_STRUCT(waypoint_coords)) { setLastErrorString("Could not read waypoint coordinates."); return false; } map->waypoints.addWaypoint(WaypointPtr(new Waypoint(name, Position(waypoint_coords->_x, waypoint_coords->_y, waypoint_coords->_z)))); } else { setLastErrorString("Unknown waypoint node."); return false; } nodeWaypoint = f.getNextNode(nodeWaypoint, type); } } else { setLastErrorString("Unknown map node."); return false; } nodeMapData = f.getNextNode(nodeMapData, type); } return true; }
WaypointManager::Node::Node() :cost(0),wp(WaypointPtr()) { }
bool DoGoto(const WaypointPtr &wp) { return DoGoto(WaypointPtr(wp)); }
static void TestAATPoint() { OrderedTask task(task_behaviour); task.Append(StartPoint(new CylinderZone(wp1->location, 500), WaypointPtr(wp1), task_behaviour, ordered_task_settings.start_constraints)); task.Append(AATPoint(new CylinderZone(wp2->location, 10000), WaypointPtr(wp2), task_behaviour)); task.Append(FinishPoint(new CylinderZone(wp3->location, 500), WaypointPtr(wp3), task_behaviour, ordered_task_settings.finish_constraints)); task.SetActiveTaskPoint(1); task.UpdateGeometry(); ok1(task.CheckTask()); AATPoint &ap = (AATPoint &)task.GetPoint(1); ok1(!ap.IsTargetLocked()); ok1(equals(ap.GetTargetLocation(), wp2->location)); ap.LockTarget(true); ok1(ap.IsTargetLocked()); ok1(equals(ap.GetTargetLocation(), wp2->location)); GeoPoint target = MakeGeoPoint(0, 45.31); ap.SetTarget(target); ok1(ap.IsTargetLocked()); ok1(equals(ap.GetTargetLocation(), wp2->location)); ap.SetTarget(target, true); ok1(ap.IsTargetLocked()); ok1(equals(ap.GetTargetLocation(), target)); RangeAndRadial rar = ap.GetTargetRangeRadial(); ok1(equals(rar.range, 0.1112, 1000)); ok1(equals(rar.radial.Degrees(), 0, 200)); target = MakeGeoPoint(0, 45.29); ap.SetTarget(target, true); rar = ap.GetTargetRangeRadial(); ok1(equals(rar.range, -0.1112, 1000)); ok1(equals(rar.radial.Degrees(), 180, 200) || equals(rar.radial.Degrees(), -180, 200)); target = MakeGeoPoint(-0.05, 45.3); ap.SetTarget(target, true); rar = ap.GetTargetRangeRadial(); ok1(equals(rar.range, 0.39217)); ok1(equals(rar.radial.Degrees(), -89.98)); target = MakeGeoPoint(0.05, 45.3); ap.SetTarget(target, true); rar = ap.GetTargetRangeRadial(); ok1(equals(rar.range, 0.39217)); ok1(equals(rar.radial.Degrees(), 89.98)); for (int radial = -170; radial <= 170; radial += 10) { const Angle radial2 = Angle::Degrees(radial); for (int range = 10; range <= 100; range += 10) { const double range2((radial >= -90 && radial <= 90 ? range : -range) / 100.); ap.SetTarget(RangeAndRadial{range2, radial2}, task.GetTaskProjection()); rar = ap.GetTargetRangeRadial(); ok1(equals(rar.range, range2, 100)); ok1(equals(rar.radial.Degrees(), radial2.Degrees(), 100)); } } }
static WaypointPtr MakeWaypointPtr(Args&&... args) { return WaypointPtr(new Waypoint(MakeWaypoint(std::forward<Args>(args)...))); }
OrderedTask* TaskFileSeeYou::GetTask(const TaskBehaviour &task_behaviour, const Waypoints *waypoints, unsigned index) const { // Create FileReader for reading the task FileLineReader reader(path, IgnoreError(), Charset::AUTO); if (reader.error()) return nullptr; // Read waypoints from the CUP file Waypoints file_waypoints; { const WaypointFactory factory(WaypointOrigin::NONE); WaypointReaderSeeYou waypoint_file(factory); NullOperationEnvironment operation; waypoint_file.Parse(file_waypoints, reader, operation); } file_waypoints.Optimise(); if (!reader.Rewind()) return nullptr; TCHAR *line = AdvanceReaderToTask(reader, index); if (line == nullptr) return nullptr; // Read waypoint list // e.g. "Club day 4 Racing task","085PRI","083BOJ","170D_K","065SKY","0844YY", "0844YY" // TASK NAME , TAKEOFF, START , TP1 , TP2 , FINISH , LANDING TCHAR waypoints_buffer[1024]; const TCHAR *wps[30]; size_t n_waypoints = ExtractParameters(line, waypoints_buffer, wps, 30, true, _T('"')); // Some versions of StrePla append a trailing ',' without a following // WP name resulting an empty last entry. Remove it from the results if (n_waypoints > 0 && wps[n_waypoints - 1][0] == _T('\0')) n_waypoints --; // At least taskname and takeoff, start, finish and landing points are needed if (n_waypoints < 5) return nullptr; // Remove taskname, start point and landing point from count n_waypoints -= 3; SeeYouTaskInformation task_info; SeeYouTurnpointInformation turnpoint_infos[30]; WaypointPtr waypoints_in_task[30]; ParseCUTaskDetails(reader, &task_info, turnpoint_infos); OrderedTask *task = new OrderedTask(task_behaviour); task->SetFactory(task_info.wp_dis ? TaskFactoryType::RACING : TaskFactoryType::AAT); AbstractTaskFactory& fact = task->GetFactory(); const TaskFactoryType factType = task->GetFactoryType(); OrderedTaskSettings beh = task->GetOrderedTaskSettings(); if (factType == TaskFactoryType::AAT) { beh.aat_min_time = task_info.task_time; } if (factType == TaskFactoryType::AAT || factType == TaskFactoryType::RACING) { beh.start_constraints.max_height = (unsigned)task_info.max_start_altitude; beh.start_constraints.max_height_ref = AltitudeReference::MSL; } task->SetOrderedTaskSettings(beh); // mark task waypoints. Skip takeoff and landing point for (unsigned i = 0; i < n_waypoints; i++) { auto file_wp = file_waypoints.LookupName(wps[i + 2]); if (file_wp == nullptr) return nullptr; // Try to find waypoint by name auto wp = waypoints->LookupName(file_wp->name); // If waypoint by name found and closer than 10m to the original if (wp != nullptr && wp->location.DistanceS(file_wp->location) <= fixed(10)) { // Use this waypoint for the task waypoints_in_task[i] = wp; continue; } // Try finding the closest waypoint to the original one wp = waypoints->GetNearest(file_wp->location, fixed(10)); // If closest waypoint found and closer than 10m to the original if (wp != nullptr && wp->location.DistanceS(file_wp->location) <= fixed(10)) { // Use this waypoint for the task waypoints_in_task[i] = wp; continue; } // Use the original waypoint waypoints_in_task[i] = file_wp; } //now create TPs and OZs for (unsigned i = 0; i < n_waypoints; i++) { ObservationZonePoint* oz = CreateOZ(turnpoint_infos[i], i, n_waypoints, waypoints_in_task, factType); assert(waypoints_in_task[i]); OrderedTaskPoint *pt = CreatePoint(i, n_waypoints, WaypointPtr(waypoints_in_task[i]), fact, oz, factType); if (pt != nullptr) fact.Append(*pt, false); delete pt; } return task; }