local a=game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")local C=require(a:WaitForChild("\078\101\118\101\114\109\111\114\101",2))local P=(C("\083\116\100")).rquery local B=game:GetService("\080\097\116\104\102\105\110\100\105\110\103\083\101\114\118\105\099\101")B.EmptyCutoff=.3 local Z={CurrentTargetPos=nil,LastTargetPos=nil;Waypoints={};Path=nil,CurrentWaypointIndex=1;PathBlockedEventConnection=nil;WaypointReachedEventConnection=nil,PathCalculationAttempts=0;MAX_PATH_CALCULATION_ATTEMPTS=20}local L={__index=Z}local y={DefaultPersonageMovementParams={TargetOffsetMax=10,JumpThreshold=1.5,NextPointThreshold=4};DefaultPathParams={AgentRadius=2;AgentHeight=5}}function y.GetPathForPersonage(a,C,P)if P==nil then P=y.DefaultPathParams end local Z=setmetatable({},L)Z.Path=B:CreatePath(P)local G=a:FindFirstChild("\072\117\109\097\110\111\105\100\082\111\111\116\080\097\114\116")if G==nil then G=a.PrimaryPart or a.FindFirstChild("\084\111\114\115\111")end Z.Path:ComputeAsync(G.Position,C.Position)Z.PathCalculationAttempts=Z.PathCalculationAttempts+1 if Z.Path.Status==Enum.PathStatus.Success then return Z else warn("\085\110\097\098\108\101 \116\111 \102\105\110\100 \112\097\116\104 \102\111\114 "..(a.Name..(" \116\111 "..C.Name)))local P=a:FindFirstChild("\072\117\109\097\110\111\105\100")P:MoveTo(G.Position)return nil end end function y.ClearPathWaypointMarkers()local a=P.GetOrAddItem("\080\111\105\110\116\115","\070\111\108\100\101\114",game.Workspace)a:ClearAllChildren()end function y.DisplayPathWaypoints(a)local C=P.GetOrAddItem("\080\111\105\110\116\115","\070\111\108\100\101\114",game.Workspace)local B=a.Path:GetWaypoints()for a,P in pairs(B)do local B=Instance.new("\080\097\114\116")B.Shape="\066\097\108\108"B.Material="\078\101\111\110"B.Size=Vector3.new(.6,.6,.6)B.Position=P.Position B.Anchored=true B.CanCollide=false B.Parent=C end end function y.MovePersonageOnPath(a,C,B,Z)if C==nil or C.Path.Status~=Enum.PathStatus.Success then error("\080\065\084\072 \078\079\084 \070\079\085\078\068\033\033\033")end if Z==nil then Z=P.DeepCopyTable(y.DefaultPersonageMovementParams)end local L=a:FindFirstChild("\072\117\109\097\110\111\105\100")C.Waypoints=C.Path:GetWaypoints()local G=P.PersonageTorsoOrEquivalent(a)if C.CurrentWaypointIndex<#C.Waypoints then local a=C.Waypoints[C.CurrentWaypointIndex]local P=(G.Position-a.Position).magnitude if P<Z.NextPointThreshold then C.CurrentWaypointIndex=C.CurrentWaypointIndex+1 end L:MoveTo(C.Waypoints[C.CurrentWaypointIndex].Position)if C.Waypoints[C.CurrentWaypointIndex].Position.Y-G.Position.Y>Z.JumpThreshold then L.Jump=true end end L:MoveTo(C.Waypoints[C.CurrentWaypointIndex].Position)C.WaypointReachedEventConnection=L.MoveToFinished:Connect(B)return C end return y
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local require = require(ReplicatedStorage:WaitForChild("Nevermore", 2))
local rq = require("Std").rquery
local PathfindingService = game:GetService("PathfindingService")
PathfindingService.EmptyCutoff = .3

local pathProgressProto = {
	CurrentTargetPos = nil,
	LastTargetPos = nil,
	Waypoints = {},
	Path = nil,
	CurrentWaypointIndex = 1,
	PathBlockedEventConnection = nil,
	WaypointReachedEventConnection = nil,
	PathCalculationAttempts = 0,
	MAX_PATH_CALCULATION_ATTEMPTS = 20
}

local pathProgressMeta = { __index = pathProgressProto }

local module = {
	DefaultPersonageMovementParams = {
		TargetOffsetMax = 10, --5
		JumpThreshold = 1.5, --2.5
		NextPointThreshold = 4,
	},
	DefaultPathParams = {
		AgentRadius = 2,
		AgentHeight = 5
	}
}

function module.GetPathForPersonage(
	personage,
	destinationObject,
	pathParams)

	if pathParams == nil then 
		 pathParams = module.DefaultPathParams
	end
	
	local pathProgressData = setmetatable({}, pathProgressMeta)

	pathProgressData.Path = PathfindingService:CreatePath(pathParams)
	
	local personageRootPart = personage:FindFirstChild("HumanoidRootPart")
	if personageRootPart == nil then
		personageRootPart = personage.PrimaryPart or personage.FindFirstChild("Torso")
	end
	-- Compute and check the path
	pathProgressData.Path:ComputeAsync(personageRootPart.Position, destinationObject.Position)
	pathProgressData.PathCalculationAttempts = pathProgressData.PathCalculationAttempts + 1
	
	if pathProgressData.Path.Status == Enum.PathStatus.Success then
		return pathProgressData
	else
		warn("Unable to find path for " .. personage.Name .. " to " .. destinationObject.Name)
		local humanoid = personage:FindFirstChild("Humanoid")
		humanoid:MoveTo(personageRootPart.Position)
		return nil

	end
end

function module.ClearPathWaypointMarkers(  )
	local pointsFolder = rq.GetOrAddItem( "Points", "Folder", game.Workspace )
	pointsFolder:ClearAllChildren()
end

function module.DisplayPathWaypoints(pathProgressData)
	local pointsFolder = rq.GetOrAddItem( "Points", "Folder", game.Workspace )
	local waypoints = pathProgressData.Path:GetWaypoints()

	-- Loop through waypoints
	for _, waypoint in pairs(waypoints) do
		local part = Instance.new("Part")
		part.Shape = "Ball"
		part.Material = "Neon"
		part.Size = Vector3.new(0.6, 0.6, 0.6)
		part.Position = waypoint.Position
		part.Anchored = true
		part.CanCollide = false
		part.Parent = pointsFolder
	end
end

function module.MovePersonageOnPath(personage,
	pathProgressData,
	onWaypointReachedDelegate,
	personageMovementParams)

	if pathProgressData == nil or pathProgressData.Path.Status ~= Enum.PathStatus.Success then
		error("PATH NOT FOUND!!!")
	end
	
	if personageMovementParams == nil then
		personageMovementParams = rq.DeepCopyTable(module.DefaultPersonageMovementParams)
	end

 	local humanoid = personage:FindFirstChild("Humanoid")
	
	pathProgressData.Waypoints = pathProgressData.Path:GetWaypoints()
	local personageTorso = rq.PersonageTorsoOrEquivalent(personage)
	
	if pathProgressData.CurrentWaypointIndex < #pathProgressData.Waypoints then
		local currentPoint = pathProgressData.Waypoints[pathProgressData.CurrentWaypointIndex]
		local distance = (personageTorso.Position - currentPoint.Position).magnitude
		if distance < personageMovementParams.NextPointThreshold then
			pathProgressData.CurrentWaypointIndex = pathProgressData.CurrentWaypointIndex + 1
		end

		humanoid:MoveTo(pathProgressData.Waypoints[pathProgressData.CurrentWaypointIndex].Position)
		if pathProgressData.Waypoints[pathProgressData.CurrentWaypointIndex].Position.Y - 
			personageTorso.Position.Y > personageMovementParams.JumpThreshold then
			humanoid.Jump = true
		end
	end
	humanoid:MoveTo(
			pathProgressData.Waypoints[pathProgressData.CurrentWaypointIndex].Position)

	pathProgressData.WaypointReachedEventConnection = humanoid.MoveToFinished:Connect(
		onWaypointReachedDelegate
	)
	return pathProgressData
end

return module