#pragma once #include "Reflection/Reflection.h" #include "V8Tree/Instance.h" #include "V8Tree/Service.h" #include "v8world/ContactManagerSpatialHash.h" #include "util/DoubleEndedVector.h" #include "voxel/ChunkMap.h" #include "voxel/Voxelizer.h" #include "voxel2/GridListener.h" #include namespace RBX { class PathfindingJob; class Path; extern const char* const sPathfindingService; class PathfindingService :public DescribedCreatable , public Service , public ContactManagerSpatialHash::CoarseMovementCallback , public Voxel::CellChangeListener , public Voxel2::GridListener { public: PathfindingService(); float emptyCutoff; void computePathAsync(Vector3 start, Vector3 finish, float maxDistance, bool isSmooth, boost::function) > resumeFunction, boost::function errorFunction); void computeRawPathAsync(Vector3 start, Vector3 finish, float maxDistance, boost::function) > resumeFunction, boost::function errorFunction); void computeSmoothPathAsync(Vector3 start, Vector3 finish, float maxDistance, boost::function) > resumeFunction, boost::function errorFunction); enum SolidState { EMPTY, SOLID, OUTSIDE }; int checkPoints(int startPoint, const std::vector& points, unsigned char emptyCutoff); void markChunksDirty(const ExtentsInt32& chunkExtents); void coarsePrimitiveMovement(Primitive* p, const UpdateInfo& info) override; void terrainCellChanged(const Voxel::CellChangeInfo& info) override; void onTerrainRegionChanged(const Voxel2::Region& region) override; void executeThrottledRequests(); float getEmptyCutoff() const { return emptyCutoff; }; void setEmptyCutoff(float value); int countOrComputeDirtyChunks(const Vector3int16& startCell, const Vector3int16& finishCell, float maxDistance, bool compute); struct PathfindingRequest { Vector3int16 startCell, finishCell; int maxDistance; boost::function errorFunction; virtual void execute(PathfindingService* service) = 0; virtual ~PathfindingRequest(){}; }; void scheduleRequest(const shared_ptr& request); void smoothPath(std::vector& points, unsigned char emptyCutoff, int smoothWindow); protected: void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider) override; private: shared_ptr job; DoubleEndedVector > throttledRequests; Voxel::ChunkMap chunkMap; Voxel::Voxelizer voxelizer; enum SideState { BLOCKED, NOTBLOCKED, NOTBLOCKEDABOVE }; struct CreatePathRequest : public PathfindingRequest { Vector3 start, finish; unsigned char emptyCutoff; bool isSmooth; boost::function) > resumeFunction; void execute(PathfindingService* service); }; struct Node { Node(const Vector3int16& pos, const Vector3int16& parent, float totalPath) : pos(pos), parent(parent), totalPath(totalPath), closed(false) { } std::multimap ,std::equal_to ,boost::fast_pool_allocator >::iterator>::iterator itWeight; Vector3int16 pos, parent; float totalPath; bool closed; }; bool adjustCell(Vector3int16& cellVoxel, Vector3& cellWorld, const Vector3int16& start, unsigned char emptyCutoff); bool adjustCellSideways(Vector3int16& cellVoxel, Vector3& cellWorld, const Vector3int16& start, unsigned char emptyCutoff); typedef boost::unordered_map< Vector3int16 ,Node ,boost::hash ,std::equal_to ,boost::fast_pool_allocator > NodesByPos; typedef std::multimap< float ,NodesByPos::iterator ,std::less ,boost::fast_pool_allocator > OpenNodesByWeight; struct PathfindingState { Vector3int16 start, finish; Vector3int16 closestCell; float closestDistance; int closestCost; OpenNodesByWeight openNodesByWeight; NodesByPos nodesByPos; int maxDistance; PathfindingState(); void addOpenNode(const Node& node); Node popTopOpenNode(); bool checkOpenNodesCounts(); }; SolidState isSolid(const Vector3int16& pos, unsigned char emptyCutoff); void computePath(CreatePathRequest& request); void collectOldChunks(); unsigned currentFrameNum; Voxel::OccupancyChunk* getChunkById(const SpatialRegion::Id& id); Voxel::OccupancyChunk* lastChunk; SpatialRegion::Id lastChunkId; }; extern const char* const sPath; class Path :public DescribedNonCreatable { std::vector points; weak_ptr service; public: typedef enum { Success = 0, ClosestNoPath = 1, ClosestOutOfRange = 2, FailStartNotEmpty = 3, FailFinishNotEmpty = 4, } PathStatus; Path(weak_ptr service, PathStatus status); void addPoint(const Vector3& point); shared_ptr getPointCoordinates(); void checkOcclusionAsync(int startPoint, boost::function resumeFunction, boost::function errorFunction); const std::vector& getPoints() { return points; }; void reverse(); PathStatus getStatus() const { return status; }; private: struct OcclusionRequest : public PathfindingService::PathfindingRequest { shared_ptr path; int startPoint; boost::function resumeFunction; unsigned char emptyCutoff; virtual void execute(PathfindingService* service); }; PathStatus status; }; };