local G={}local t=require(script.Parent.Parent:WaitForChild("\067\111\110\102\105\103\117\114\097\116\105\111\110"))local q=t.PhysicsSolver.GRAVITY local U=t.PhysicsSolver.USE_FALLING_SIMULATION local O=(game:GetService("\087\111\114\107\115\112\097\099\101")).FallenPartsDestroyHeight local j=game:GetService("\082\117\110\083\101\114\118\105\099\101")local c=require(script.Parent:WaitForChild("\085\116\105\108"))local L=Vector3.new function G.CreateSolver(t,G)local Y=true local m={}local g=G.CharacterModel:WaitForChild("\072\101\097\100")local X,M local function e()X=G.CharacterModel:FindFirstChild("\076\101\102\116\070\111\111\116")M=G.CharacterModel:FindFirstChild("\082\105\103\104\116\070\111\111\116")end e()local Q local n,u=0,0 function m.SetNewContext(t,G)Q=G+L(0,4,0)n=Q.Y end function m.SetEnabled(t,G)Y=G end local F=L(0,-500,0)if q>0 then F=L(0,500,0)end local Z=Vector3.new(0,2,0)local H if U then local t=0 H=j.RenderStepped:Connect(function(U)if Y then local j,L if Q then j,L=c:FindCollidablePartOnRay(Q,F,G.CharacterModel)e()elseif X and M then local t=X.Position+Z local q=M.Position+Z local U,O=c:FindCollidablePartOnRay(t,F,G.CharacterModel)local Y,m=c:FindCollidablePartOnRay(q,F,G.CharacterModel)if O.Y>m.Y then j,L=U,O else j,L=Y,m end elseif X then local t=X.Position+Z j,L=c:FindCollidablePartOnRay(t,F,G.CharacterModel)e()elseif M then local t=M.Position+Z j,L=c:FindCollidablePartOnRay(t,F,G.CharacterModel)e()else local t=g.Position j,L=c:FindCollidablePartOnRay(t,F,G.CharacterModel)e()end local m=L.Y t=t+q*U local u=n+t if u>m then n=u else t=0 n=m end G:SetWorldYOffset(n)if Q then Q=nil end if n<O then Y=false G.Humanoid.Health=0 end end end)else H=j.RenderStepped:Connect(function()if Y then local t,q if Q then t,q=c:FindCollidablePartOnRay(Q,F,G.CharacterModel)e()elseif X and M then local U=X.Position+Z local O=M.Position+Z local j,L=c:FindCollidablePartOnRay(U,F,G.CharacterModel)local Y,m=c:FindCollidablePartOnRay(O,F,G.CharacterModel)if L.Y>m.Y then t,q=j,L else t,q=Y,m end elseif X then local U=X.Position+Z t,q=c:FindCollidablePartOnRay(U,F,G.CharacterModel)e()elseif M then local U=M.Position+Z t,q=c:FindCollidablePartOnRay(U,F,G.CharacterModel)e()else local U=g.Position t,q=c:FindCollidablePartOnRay(U,F,G.CharacterModel)e()end if t then n=q.Y end G:SetWorldYOffset(n)if Q then Q=nil end if n<O then Y=false G.Humanoid.Health=0 end end end)end function m.Disconnect(G)H:Disconnect()end return m end return G
--[[




PhysicsSolver:CreateSolver(CharacterClass)
	Creates a new physics solver from CharacterClass
	RETURNS: PhysicsSolverClass
	
CLASS PhysicsSolverClass
	PhysicsSolverClass:SetNewContext(Pos)
		Sets the next position to override ray casting. Used for teleporting
	PhysicsSolverClass:SetEnabled(Enabled)
		Sets whether the solver is enabled or disabled
	PhysicsSolverClass:Disconnect()
		Disconnects all events
	
--]]

local PhysicsSolver = {}

local Configuration = require(script.Parent.Parent:WaitForChild("Configuration"))
local GRAVITY = Configuration.PhysicsSolver.GRAVITY
local USE_FALLING_SIMULATION = Configuration.PhysicsSolver.USE_FALLING_SIMULATION
local DESTROY_HEIGHT = game:GetService("Workspace").FallenPartsDestroyHeight

local RunService = game:GetService("RunService")
local Util = require(script.Parent:WaitForChild("Util"))

local V3new = Vector3.new

function PhysicsSolver:CreateSolver(CharacterClass)
	local Enabled = true
	local PhysicsSolverClass = {}
	local Head = CharacterClass.CharacterModel:WaitForChild("Head")
	local LeftFoot, RightFoot
	local function UpdateFeet()
		LeftFoot = CharacterClass.CharacterModel:FindFirstChild("LeftFoot")
		RightFoot = CharacterClass.CharacterModel:FindFirstChild("RightFoot")
	end
	UpdateFeet()

	local OverridePos
	local LastY, LastTargetY = 0, 0
	function PhysicsSolverClass:SetNewContext(NewOverridePos)
		OverridePos = NewOverridePos + V3new(0, 4, 0)
		LastY = OverridePos.Y
	end

	function PhysicsSolverClass:SetEnabled(NewEnabled)
		Enabled = NewEnabled
	end

	local DownDirection500 = V3new(0, -500, 0)
	if GRAVITY > 0 then
		DownDirection500 = V3new(0, 500, 0)
	end

	local FootOffset = Vector3.new(0, 2, 0)
	local SolverEvent
	if USE_FALLING_SIMULATION then
		local Velocity = 0

		SolverEvent = RunService.RenderStepped:Connect(function(DeltaTime)
			if Enabled then
				local EndPart, BottomPos
				if OverridePos then
					EndPart, BottomPos =
						Util:FindCollidablePartOnRay(OverridePos, DownDirection500, CharacterClass.CharacterModel)
					UpdateFeet()
				elseif LeftFoot and RightFoot then
					local LeftFootPos = LeftFoot.Position + FootOffset
					local RightFootPos = RightFoot.Position + FootOffset

					local LeftEndPart, LeftBottomPos =
						Util:FindCollidablePartOnRay(LeftFootPos, DownDirection500, CharacterClass.CharacterModel)
					local RightEndPart, RightBottomPos =
						Util:FindCollidablePartOnRay(RightFootPos, DownDirection500, CharacterClass.CharacterModel)

					if LeftBottomPos.Y > RightBottomPos.Y then
						EndPart, BottomPos = LeftEndPart, LeftBottomPos
					else
						EndPart, BottomPos = RightEndPart, RightBottomPos
					end
				elseif LeftFoot then
					local LeftFootPos = LeftFoot.Position + FootOffset
					EndPart, BottomPos =
						Util:FindCollidablePartOnRay(LeftFootPos, DownDirection500, CharacterClass.CharacterModel)
					UpdateFeet()
				elseif RightFoot then
					local RightFootPos = RightFoot.Position + FootOffset
					EndPart, BottomPos =
						Util:FindCollidablePartOnRay(RightFootPos, DownDirection500, CharacterClass.CharacterModel)
					UpdateFeet()
				else
					local HeadPos = Head.Position
					EndPart, BottomPos =
						Util:FindCollidablePartOnRay(HeadPos, DownDirection500, CharacterClass.CharacterModel)
					UpdateFeet()
				end

				local EndY = BottomPos.Y
				Velocity = Velocity + (GRAVITY * DeltaTime)
				local DestinationY = LastY + Velocity

				if DestinationY > EndY then
					LastY = DestinationY
				else
					Velocity = 0
					LastY = EndY
				end
				CharacterClass:SetWorldYOffset(LastY)

				if OverridePos then
					OverridePos = nil
				end

				if LastY < DESTROY_HEIGHT then
					Enabled = false
					CharacterClass.Humanoid.Health = 0
				end
			end
		end)
	else
		SolverEvent = RunService.RenderStepped:Connect(function()
			if Enabled then
				local EndPart, BottomPos
				if OverridePos then
					EndPart, BottomPos =
						Util:FindCollidablePartOnRay(OverridePos, DownDirection500, CharacterClass.CharacterModel)
					UpdateFeet()
				elseif LeftFoot and RightFoot then
					local LeftFootPos = LeftFoot.Position + FootOffset
					local RightFootPos = RightFoot.Position + FootOffset

					local LeftEndPart, LeftBottomPos =
						Util:FindCollidablePartOnRay(LeftFootPos, DownDirection500, CharacterClass.CharacterModel)
					local RightEndPart, RightBottomPos =
						Util:FindCollidablePartOnRay(RightFootPos, DownDirection500, CharacterClass.CharacterModel)

					if LeftBottomPos.Y > RightBottomPos.Y then
						EndPart, BottomPos = LeftEndPart, LeftBottomPos
					else
						EndPart, BottomPos = RightEndPart, RightBottomPos
					end
				elseif LeftFoot then
					local LeftFootPos = LeftFoot.Position + FootOffset
					EndPart, BottomPos =
						Util:FindCollidablePartOnRay(LeftFootPos, DownDirection500, CharacterClass.CharacterModel)
					UpdateFeet()
				elseif RightFoot then
					local RightFootPos = RightFoot.Position + FootOffset
					EndPart, BottomPos =
						Util:FindCollidablePartOnRay(RightFootPos, DownDirection500, CharacterClass.CharacterModel)
					UpdateFeet()
				else
					local HeadPos = Head.Position
					EndPart, BottomPos =
						Util:FindCollidablePartOnRay(HeadPos, DownDirection500, CharacterClass.CharacterModel)
					UpdateFeet()
				end

				if EndPart then
					LastY = BottomPos.Y
				end
				CharacterClass:SetWorldYOffset(LastY)

				if OverridePos then
					OverridePos = nil
				end

				if LastY < DESTROY_HEIGHT then
					Enabled = false
					CharacterClass.Humanoid.Health = 0
				end
			end
		end)
	end

	function PhysicsSolverClass:Disconnect()
		SolverEvent:Disconnect()
	end

	return PhysicsSolverClass
end

return PhysicsSolver
