remotes.setup.OnServerEvent:Connect(function(q,f,P)local C=P:Clone()local m=q.Character local z=m:WaitForChild("\072\117\109\097\110\111\105\100")local h=Instance.new("\077\111\116\111\114\054\068")h.Part0=m:WaitForChild(f and"\082\105\103\104\116\072\097\110\100"or"\082\105\103\104\116 \065\114\109")h.Part1=C:WaitForChild("\072\097\110\100\108\101")h.Parent=C.Handle C.Parent=m weapons[q]=(require(C:WaitForChild("\115\101\116\116\105\110\103\115")))(f)local p=spring.new(0,0,0,10,1)local o=spring.new(Vector2.new(),Vector2.new(),Vector2.new(),20,1)springs[q]={}springs[q].tilt=p springs[q].recoil=o local i,S if f then local q=(m:WaitForChild("\072\101\097\100")):WaitForChild("\078\101\099\107")local f=(m:WaitForChild("\085\112\112\101\114\084\111\114\115\111")):WaitForChild("\087\097\105\115\116")local P=(m:WaitForChild("\082\105\103\104\116\085\112\112\101\114\065\114\109")):WaitForChild("\082\105\103\104\116\083\104\111\117\108\100\101\114")local C=(m:WaitForChild("\076\101\102\116\085\112\112\101\114\065\114\109")):WaitForChild("\076\101\102\116\083\104\111\117\108\100\101\114")local z=q.C0 local h=f.C0 local p=P.C0 local o=C.C0 function i(m)q.C0=z*CFrame.fromEulerAnglesYXZ(m,0,0)f.C0=h*CFrame.fromEulerAnglesYXZ(m,0,0)P.C0=p*CFrame.fromEulerAnglesYXZ(m,0,0)C.C0=o*CFrame.fromEulerAnglesYXZ(m,0,0)end function S(q,f)P.C0=P.C0*CFrame.new(0,0,q)C.C0=C.C0*CFrame.new(0,0,f)end else local q=m:WaitForChild("\084\111\114\115\111")local f=m:WaitForChild("\072\117\109\097\110\111\105\100\082\111\111\116\080\097\114\116")local P=q:WaitForChild("\078\101\099\107")local C=f:WaitForChild("\082\111\111\116\074\111\105\110\116")local z=q:WaitForChild("\082\105\103\104\116 \083\104\111\117\108\100\101\114")local h=q:WaitForChild("\076\101\102\116 \083\104\111\117\108\100\101\114")local p=q:WaitForChild("\082\105\103\104\116 \072\105\112")local o=q:WaitForChild("\076\101\102\116 \072\105\112")local j=P.C0 local M=C.C0 local J=z.C0 local g=h.C0 local W=p.C0 local k=o.C0 function i(q)P.C0=j*CFrame.fromEulerAnglesYXZ(-q,0,0)C.C0=((M*CFrame.new(0,0,-1))*CFrame.fromEulerAnglesYXZ(-q,0,0))*CFrame.new(0,0,1)z.C0=J*CFrame.fromEulerAnglesYXZ(0,0,q)h.C0=g*CFrame.fromEulerAnglesYXZ(0,0,-q)p.C0=W*CFrame.fromEulerAnglesYXZ(0,0,-q)o.C0=k*CFrame.fromEulerAnglesYXZ(0,0,q)end function S(q,f)z.C0=z.C0*CFrame.new(-q,0,0)h.C0=h.C0*CFrame.new(f,0,0)end end local j=runService.Heartbeat:Connect(function(q)p:update(q)o:update(q)i(states[z:GetState()]and 0 or p.p/2)S(o.p.x,o.p.y)end)local M M=q.Character.Humanoid.Died:Connect(function()j:Disconnect()M:Disconnect()end)cleanup[q]={i;j,M,C,h,S}end)remotes.cleanup.OnServerEvent:Connect(function(q)local f=cleanup[q]if f then f[2]:Disconnect()f[1](0)f[3]:Disconnect()f[4]:Destroy()f[5]:Destroy()f[6](0,0)end end)
-- use a remote function for setup to avoid async
remotes.setup.OnServerEvent:Connect(function(player, isR15, weapon)
	local weapon = weapon:Clone()

	local character = player.Character
	local humanoid = character:WaitForChild("Humanoid")

	local joint = Instance.new("Motor6D")
	joint.Part0 = character:WaitForChild(isR15 and "RightHand" or "Right Arm")
	joint.Part1 = weapon:WaitForChild("Handle")
	joint.Parent = weapon.Handle

	weapon.Parent = character
	weapons[player] = require(weapon:WaitForChild("settings"))(isR15)

	local tilt = spring.new(0, 0, 0, 10, 1)
	local recoil = spring.new(Vector2.new(), Vector2.new(), Vector2.new(), 20, 1)

	springs[player] = {}
	springs[player].tilt = tilt
	springs[player].recoil = recoil

	-- update the character according to their rig type
	local tiltFunc, recoilFunc
	if isR15 then
		local neck = character:WaitForChild("Head"):WaitForChild("Neck")
		local waist = character:WaitForChild("UpperTorso"):WaitForChild("Waist")
		local rShoulder = character:WaitForChild("RightUpperArm"):WaitForChild("RightShoulder")
		local lShoulder = character:WaitForChild("LeftUpperArm"):WaitForChild("LeftShoulder")

		local neckC0 = neck.C0
		local waistC0 = waist.C0
		local rShoulderC0 = rShoulder.C0
		local lShoulderC0 = lShoulder.C0

		function tiltFunc(theta)
			neck.C0 = neckC0 * CFrame.fromEulerAnglesYXZ(theta, 0, 0)
			waist.C0 = waistC0 * CFrame.fromEulerAnglesYXZ(theta, 0, 0)
			rShoulder.C0 = rShoulderC0 * CFrame.fromEulerAnglesYXZ(theta, 0, 0)
			lShoulder.C0 = lShoulderC0 * CFrame.fromEulerAnglesYXZ(theta, 0, 0)
		end

		function recoilFunc(x, y)
			rShoulder.C0 = rShoulder.C0 * CFrame.new(0, 0, x)
			lShoulder.C0 = lShoulder.C0 * CFrame.new(0, 0, y)
		end
	else
		local torso = character:WaitForChild("Torso")
		local hrp = character:WaitForChild("HumanoidRootPart")

		local neck = torso:WaitForChild("Neck")
		local root = hrp:WaitForChild("RootJoint")
		local rShoulder = torso:WaitForChild("Right Shoulder")
		local lShoulder = torso:WaitForChild("Left Shoulder")
		local rHip = torso:WaitForChild("Right Hip")
		local lHip = torso:WaitForChild("Left Hip")

		local neckC0 = neck.C0
		local rootC0 = root.C0
		local rShoulderC0 = rShoulder.C0
		local lShoulderC0 = lShoulder.C0
		local rHipC0 = rHip.C0
		local lHipC0 = lHip.C0

		-- rotating the R6 joints is so arbitrary
		function tiltFunc(theta)
			neck.C0 = neckC0 * CFrame.fromEulerAnglesYXZ(-theta, 0, 0)
			root.C0 = rootC0 * CFrame.new(0, 0, -1) * CFrame.fromEulerAnglesYXZ(-theta, 0, 0) * CFrame.new(0, 0, 1)
			rShoulder.C0 = rShoulderC0 * CFrame.fromEulerAnglesYXZ(0, 0, theta)
			lShoulder.C0 = lShoulderC0 * CFrame.fromEulerAnglesYXZ(0, 0, -theta)
			rHip.C0 = rHipC0 * CFrame.fromEulerAnglesYXZ(0, 0, -theta)
			lHip.C0 = lHipC0 * CFrame.fromEulerAnglesYXZ(0, 0, theta)
		end

		function recoilFunc(x, y)
			rShoulder.C0 = rShoulder.C0 * CFrame.new(-x, 0, 0)
			lShoulder.C0 = lShoulder.C0 * CFrame.new(y, 0, 0)
		end
	end

	local heartBeat = runService.Heartbeat:Connect(function(dt)
		tilt:update(dt)
		recoil:update(dt)

		tiltFunc(states[humanoid:GetState()] and 0 or tilt.p / 2)
		recoilFunc(recoil.p.x, recoil.p.y)
	end)

	-- disconnect on death
	local died
	died = player.Character.Humanoid.Died:Connect(function()
		heartBeat:Disconnect()
		died:Disconnect()
	end)

	-- store this for later
	cleanup[player] = {
		tiltFunc,
		heartBeat,
		died,
		weapon,
		joint,
		recoilFunc,
	}
end)

remotes.cleanup.OnServerEvent:Connect(function(player)
	local clean = cleanup[player]
	if clean then
		clean[2]:Disconnect()
		clean[1](0)
		clean[3]:Disconnect()
		clean[4]:Destroy()
		clean[5]:Destroy()
		clean[6](0, 0)
	end
end)
