function CameraShaker.new(c,A)assert(type(c)=="\110\117\109\098\101\114","\082\101\110\100\101\114\080\114\105\111\114\105\116\121 \109\117\115\116 \098\101 \097 \110\117\109\098\101\114 \040\101\046\103\046\058 \069\110\117\109\046\082\101\110\100\101\114\080\114\105\111\114\105\116\121\046\067\097\109\101\114\097\046\086\097\108\117\101\041")assert(type(A)=="\102\117\110\099\116\105\111\110","\067\097\108\108\098\097\099\107 \109\117\115\116 \098\101 \097 \102\117\110\099\116\105\111\110")local p=setmetatable({_running=false;_renderName="\067\097\109\101\114\097\083\104\097\107\101\114",_renderPriority=c,_posAddShake=v3Zero,_rotAddShake=v3Zero;_camShakeInstances={},_removeInstances={},_callback=A},CameraShaker)return p end function CameraShaker.Start(c)if c._running then return end c._running=true local A=c._callback;(game:GetService("\082\117\110\083\101\114\118\105\099\101")):BindToRenderStep(c._renderName,c._renderPriority,function(p)profileBegin(profileTag)local l=c:Update(p)profileEnd()A(l)end)end function CameraShaker.Stop(c)if not c._running then return end;(game:GetService("\082\117\110\083\101\114\118\105\099\101")):UnbindFromRenderStep(c._renderName)c._running=false end function CameraShaker.StopSustained(A,c)for A,p in pairs(A._camShakeInstances)do if p.fadeOutDuration==0 then p:StartFadeOut(c or p.fadeInDuration)end end end function CameraShaker.Update(A,c)local p=v3Zero local l=v3Zero local u=A._camShakeInstances for I=1,#u,1 do local Z=u[I]local q=Z:GetState()if q==CameraShakeState.Inactive and Z.DeleteOnInactive then A._removeInstances[#A._removeInstances+1]=I elseif q~=CameraShakeState.Inactive then local A=Z:UpdateShake(c)p=p+A*Z.PositionInfluence l=l+A*Z.RotationInfluence end end for c=#A._removeInstances,1,-1 do local p=A._removeInstances[c]table.remove(u,p)A._removeInstances[c]=nil end return(CF(p)*ANG(0,RAD(l.Y),0))*ANG(RAD(l.X),0,RAD(l.Z))end function CameraShaker.Shake(A,c)assert(type(c)=="\116\097\098\108\101"and c._camShakeInstance,"\083\104\097\107\101\073\110\115\116\097\110\099\101 \109\117\115\116 \098\101 \111\102 \116\121\112\101 \067\097\109\101\114\097\083\104\097\107\101\073\110\115\116\097\110\099\101")A._camShakeInstances[#A._camShakeInstances+1]=c return c end function CameraShaker.ShakeSustain(A,c)assert(type(c)=="\116\097\098\108\101"and c._camShakeInstance,"\083\104\097\107\101\073\110\115\116\097\110\099\101 \109\117\115\116 \098\101 \111\102 \116\121\112\101 \067\097\109\101\114\097\083\104\097\107\101\073\110\115\116\097\110\099\101")A._camShakeInstances[#A._camShakeInstances+1]=c c:StartFadeIn(c.fadeInDuration)return c end function CameraShaker.ShakeOnce(Z,c,A,p,l,u,I)local q=CameraShakeInstance.new(c,A,p,l)q.PositionInfluence=typeof(u)=="\086\101\099\116\111\114\051"and u or defaultPosInfluence q.RotationInfluence=typeof(I)=="\086\101\099\116\111\114\051"and I or defaultRotInfluence Z._camShakeInstances[#Z._camShakeInstances+1]=q return q end function CameraShaker.StartShake(I,c,A,p,l,u)local Z=CameraShakeInstance.new(c,A,p)Z.PositionInfluence=typeof(l)=="\086\101\099\116\111\114\051"and l or defaultPosInfluence Z.RotationInfluence=typeof(u)=="\086\101\099\116\111\114\051"and u or defaultRotInfluence Z:StartFadeIn(p)I._camShakeInstances[#I._camShakeInstances+1]=Z return Z end return CameraShaker
--CameraShaker.Presets = require(script.CameraShakePresets)

function CameraShaker.new(renderPriority, callback)
	assert(type(renderPriority) == "number", "RenderPriority must be a number (e.g.: Enum.RenderPriority.Camera.Value)")
	assert(type(callback) == "function", "Callback must be a function")

	local self = setmetatable({
		_running = false,
		_renderName = "CameraShaker",
		_renderPriority = renderPriority,
		_posAddShake = v3Zero,
		_rotAddShake = v3Zero,
		_camShakeInstances = {},
		_removeInstances = {},
		_callback = callback,
	}, CameraShaker)

	return self
end

function CameraShaker:Start()
	if self._running then
		return
	end
	self._running = true
	local callback = self._callback
	game:GetService("RunService"):BindToRenderStep(self._renderName, self._renderPriority, function(dt)
		profileBegin(profileTag)
		local cf = self:Update(dt)
		profileEnd()
		callback(cf)
	end)
end

function CameraShaker:Stop()
	if not self._running then
		return
	end
	game:GetService("RunService"):UnbindFromRenderStep(self._renderName)
	self._running = false
end

function CameraShaker:StopSustained(duration)
	for _, c in pairs(self._camShakeInstances) do
		if c.fadeOutDuration == 0 then
			c:StartFadeOut(duration or c.fadeInDuration)
		end
	end
end

function CameraShaker:Update(dt)
	local posAddShake = v3Zero
	local rotAddShake = v3Zero

	local instances = self._camShakeInstances

	-- Update all instances:
	for i = 1, #instances do
		local c = instances[i]
		local state = c:GetState()

		if state == CameraShakeState.Inactive and c.DeleteOnInactive then
			self._removeInstances[#self._removeInstances + 1] = i
		elseif state ~= CameraShakeState.Inactive then
			local shake = c:UpdateShake(dt)
			posAddShake = posAddShake + (shake * c.PositionInfluence)
			rotAddShake = rotAddShake + (shake * c.RotationInfluence)
		end
	end

	-- Remove dead instances:
	for i = #self._removeInstances, 1, -1 do
		local instIndex = self._removeInstances[i]
		table.remove(instances, instIndex)
		self._removeInstances[i] = nil
	end

	return CF(posAddShake) * ANG(0, RAD(rotAddShake.Y), 0) * ANG(RAD(rotAddShake.X), 0, RAD(rotAddShake.Z))
end

function CameraShaker:Shake(shakeInstance)
	assert(
		type(shakeInstance) == "table" and shakeInstance._camShakeInstance,
		"ShakeInstance must be of type CameraShakeInstance"
	)
	self._camShakeInstances[#self._camShakeInstances + 1] = shakeInstance
	return shakeInstance
end

function CameraShaker:ShakeSustain(shakeInstance)
	assert(
		type(shakeInstance) == "table" and shakeInstance._camShakeInstance,
		"ShakeInstance must be of type CameraShakeInstance"
	)
	self._camShakeInstances[#self._camShakeInstances + 1] = shakeInstance
	shakeInstance:StartFadeIn(shakeInstance.fadeInDuration)
	return shakeInstance
end

function CameraShaker:ShakeOnce(magnitude, roughness, fadeInTime, fadeOutTime, posInfluence, rotInfluence)
	local shakeInstance = CameraShakeInstance.new(magnitude, roughness, fadeInTime, fadeOutTime)
	shakeInstance.PositionInfluence = (typeof(posInfluence) == "Vector3" and posInfluence or defaultPosInfluence)
	shakeInstance.RotationInfluence = (typeof(rotInfluence) == "Vector3" and rotInfluence or defaultRotInfluence)
	self._camShakeInstances[#self._camShakeInstances + 1] = shakeInstance
	return shakeInstance
end

function CameraShaker:StartShake(magnitude, roughness, fadeInTime, posInfluence, rotInfluence)
	local shakeInstance = CameraShakeInstance.new(magnitude, roughness, fadeInTime)
	shakeInstance.PositionInfluence = (typeof(posInfluence) == "Vector3" and posInfluence or defaultPosInfluence)
	shakeInstance.RotationInfluence = (typeof(rotInfluence) == "Vector3" and rotInfluence or defaultRotInfluence)
	shakeInstance:StartFadeIn(fadeInTime)
	self._camShakeInstances[#self._camShakeInstances + 1] = shakeInstance
	return shakeInstance
end

return CameraShaker
