/* Request a new multipath, store the result and return a handle-id to it. */ unsigned int CPathManager::RequestPath( CSolidObject* caller, const MoveDef* moveDef, float3 startPos, float3 goalPos, float goalRadius, bool synced ) { if (!IsFinalized()) return 0; // in misc since it is called from many points SCOPED_TIMER("Misc::Path::RequestPath"); startPos.ClampInBounds(); goalPos.ClampInBounds(); // Create an estimator definition. goalRadius = std::max<float>(goalRadius, PATH_NODE_SPACING * SQUARE_SIZE); //FIXME do on a per PE & PF level? assert(moveDef == moveDefHandler->GetMoveDefByPathType(moveDef->pathType)); MultiPath newPath = MultiPath(moveDef, startPos, goalPos, goalRadius); newPath.finalGoal = goalPos; newPath.caller = caller; newPath.peDef.synced = synced; if (caller != nullptr) caller->UnBlock(); const IPath::SearchResult result = ArrangePath(&newPath, moveDef, startPos, goalPos, caller); unsigned int pathID = 0; if (result != IPath::Error) { if (newPath.maxResPath.path.empty()) { if (result != IPath::CantGetCloser) { LowRes2MedRes(newPath, startPos, caller, synced); MedRes2MaxRes(newPath, startPos, caller, synced); } else { // add one dummy waypoint so that the calling MoveType // does not consider this request a failure, which can // happen when startPos is very close to goalPos // // otherwise, code relying on MoveType::progressState // (eg. BuilderCAI::MoveInBuildRange) would misbehave // (eg. reject build orders) newPath.maxResPath.path.push_back(startPos); newPath.maxResPath.squares.push_back(int2(startPos.x / SQUARE_SIZE, startPos.z / SQUARE_SIZE)); } } FinalizePath(&newPath, startPos, goalPos, result == IPath::CantGetCloser); newPath.searchResult = result; pathID = Store(newPath); } if (caller != nullptr) caller->Block(); return pathID; }
unsigned int CQuadField::GetQuads(float3 pos, float radius, int*& begQuad, int*& endQuad) const { pos.ClampInBounds(); pos.AssertNaNs(); assert(begQuad == &tempQuads[0]); assert(endQuad == &tempQuads[0]); const int maxx = std::min((int(pos.x + radius)) / quadSizeX + 1, numQuadsX - 1); const int maxz = std::min((int(pos.z + radius)) / quadSizeZ + 1, numQuadsZ - 1); const int minx = std::max((int(pos.x - radius)) / quadSizeX, 0); const int minz = std::max((int(pos.z - radius)) / quadSizeZ, 0); if (maxz < minz || maxx < minx) { return 0; } // qsx and qsz are always equal const float maxSqLength = (radius + quadSizeX * 0.72f) * (radius + quadSizeZ * 0.72f); for (int z = minz; z <= maxz; ++z) { for (int x = minx; x <= maxx; ++x) { const float3 quadCenterPos = float3(x * quadSizeX + quadSizeX * 0.5f, 0, z * quadSizeZ + quadSizeZ * 0.5f); if ((pos - quadCenterPos).SqLength2D() < maxSqLength) { *endQuad = z * numQuadsX + x; ++endQuad; } } } return (endQuad - begQuad); }
std::vector<int> CQuadField::GetQuads(float3 pos, float radius) const { pos.ClampInBounds(); pos.AssertNaNs(); std::vector<int> ret; // qsx and qsz are always equal const float maxSqLength = (radius + quadSizeX * 0.72f) * (radius + quadSizeZ * 0.72f); const int maxx = std::min((int(pos.x + radius)) / quadSizeX + 1, numQuadsX - 1); const int maxz = std::min((int(pos.z + radius)) / quadSizeZ + 1, numQuadsZ - 1); const int minx = std::max((int(pos.x - radius)) / quadSizeX, 0); const int minz = std::max((int(pos.z - radius)) / quadSizeZ, 0); if (maxz < minz || maxx < minx) { return ret; } ret.reserve((maxz - minz) * (maxx - minx)); for (int z = minz; z <= maxz; ++z) { for (int x = minx; x <= maxx; ++x) { if ((pos - float3(x * quadSizeX + quadSizeX * 0.5f, 0, z * quadSizeZ + quadSizeZ * 0.5f)).SqLength2D() < maxSqLength) { ret.push_back(z * numQuadsX + x); } } } return ret; }
IPath::SearchResult IPathFinder::GetPath( const MoveDef& moveDef, const CPathFinderDef& pfDef, const CSolidObject* owner, float3 startPos, IPath::Path& path, const unsigned int maxNodes ) { startPos.ClampInBounds(); // Clear the path path.path.clear(); path.squares.clear(); path.pathCost = PATHCOST_INFINITY; // initial calculations if (isEstimator) { maxBlocksToBeSearched = std::min(MAX_SEARCHED_NODES_PE - 8U, maxNodes); } else { maxBlocksToBeSearched = std::min(MAX_SEARCHED_NODES_PF - 8U, maxNodes); } mStartBlock.x = startPos.x / BLOCK_PIXEL_SIZE; mStartBlock.y = startPos.z / BLOCK_PIXEL_SIZE; mStartBlockIdx = BlockPosToIdx(mStartBlock); assert((unsigned)mStartBlock.x < nbrOfBlocks.x && (unsigned)mStartBlock.y < nbrOfBlocks.y); // Check cache (when there is one) int2 goalBlock; goalBlock.x = pfDef.goalSquareX / BLOCK_SIZE; goalBlock.y = pfDef.goalSquareZ / BLOCK_SIZE; const CPathCache::CacheItem* ci = GetCache(mStartBlock, goalBlock, pfDef.sqGoalRadius, moveDef.pathType, pfDef.synced); if (ci != nullptr) { path = ci->path; return ci->result; } // Start up a new search IPath::SearchResult result = InitSearch(moveDef, pfDef, owner); // If search was successful, generate new path if (result == IPath::Ok || result == IPath::GoalOutOfRange) { FinishSearch(moveDef, pfDef, path); // Save to cache AddCache(&path, result, mStartBlock, goalBlock, pfDef.sqGoalRadius, moveDef.pathType, pfDef.synced); if (LOG_IS_ENABLED(L_DEBUG)) { LOG_L(L_DEBUG, "==== %s: Search completed ====", (isEstimator) ? "PE" : "PF"); LOG_L(L_DEBUG, "Tested blocks: %u", testedBlocks); LOG_L(L_DEBUG, "Open blocks: %u", openBlockBuffer.GetSize()); LOG_L(L_DEBUG, "Path length: " _STPF_, path.path.size()); LOG_L(L_DEBUG, "Path cost: %f", path.pathCost); LOG_L(L_DEBUG, "=============================="); } } else { if (LOG_IS_ENABLED(L_DEBUG)) { LOG_L(L_DEBUG, "==== %s: Search failed! ====", (isEstimator) ? "PE" : "PF"); LOG_L(L_DEBUG, "Tested blocks: %u", testedBlocks); LOG_L(L_DEBUG, "Open blocks: %u", openBlockBuffer.GetSize()); LOG_L(L_DEBUG, "============================"); } } return result; }
void CFeature::Initialize(const float3& _pos, const FeatureDef* _def, short int _heading, int facing, int _team, int _allyteam, const UnitDef* _udef, const float3& speed, int _smokeTime) { def = _def; udef = _udef; defName = def->myName; heading = _heading; buildFacing = facing; team = _team; allyteam = _allyteam; emitSmokeTime = _smokeTime; mass = def->mass; crushResistance = def->crushResistance; health = def->maxHealth; blocking = def->blocking; xsize = ((facing & 1) == 0) ? def->xsize : def->zsize; zsize = ((facing & 1) == 1) ? def->xsize : def->zsize; noSelect = def->noSelect; float fRadius = 1.0f; float fHeight = 0.0f; if (def->drawType == DRAWTYPE_MODEL) { model = def->LoadModel(); if (!model) { LOG_L(L_ERROR, "Features: Couldn't load model for %s", defName.c_str()); } else { relMidPos = model->relMidPos; fRadius = model->radius; fHeight = model->height; // note: gets deleted in ~CSolidObject collisionVolume = new CollisionVolume(def->collisionVolume, fRadius); } } else if (def->drawType >= DRAWTYPE_TREE) { relMidPos = UpVector * TREE_RADIUS; fRadius = TREE_RADIUS; fHeight = fRadius * 2.0f; // LoadFeaturesFromMap() doesn't set a scale for trees // note: gets deleted in ~CSolidObject collisionVolume = new CollisionVolume(def->collisionVolume, fRadius); } Move3D(_pos.ClampInBounds(), false); SetRadiusAndHeight(fRadius, fHeight); UpdateMidPos(); CalculateTransform(); featureHandler->AddFeature(this); qf->AddFeature(this); // maybe should not be here, but it prevents crashes caused by team = -1 ChangeTeam(team); if (blocking) { Block(); } if (def->floating) { finalHeight = ground->GetHeightAboveWater(pos.x, pos.z); } else { finalHeight = ground->GetHeightReal(pos.x, pos.z); } if (speed != ZeroVector) { deathSpeed = speed; } reachedFinalPos = (speed == ZeroVector && pos.y == finalHeight); }