Freecam Difference

Created Diff never expires
37 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
494 lines
46 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
503 lines
--!nonstrict
--!nonstrict
------------------------------------------------------------------------
------------------------------------------------------------------------
-- Freecam
-- Freecam
-- Cinematic free camera for spectating and video production.
-- Cinematic free camera for spectating and video production.
------------------------------------------------------------------------
------------------------------------------------------------------------


-- To exit and enter free camera, use key shortcut Left Shift + P

local pi = math.pi
local pi = math.pi
local abs = math.abs
local abs = math.abs
local clamp = math.clamp
local clamp = math.clamp
local exp = math.exp
local exp = math.exp
local rad = math.rad
local rad = math.rad
local sign = math.sign
local sign = math.sign
local sqrt = math.sqrt
local sqrt = math.sqrt
local tan = math.tan
local tan = math.tan


local ContextActionService = game:GetService("ContextActionService")
local ContextActionService = game:GetService("ContextActionService")
local Players = game:GetService("Players")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local RunService = game:GetService("RunService")
local StarterGui = game:GetService("StarterGui")
local StarterGui = game:GetService("StarterGui")
local UserInputService = game:GetService("UserInputService")
local UserInputService = game:GetService("UserInputService")
local Workspace = game:GetService("Workspace")
local Workspace = game:GetService("Workspace")
local Settings = UserSettings()
local Settings = UserSettings()
local GameSettings = Settings.GameSettings
local GameSettings = Settings.GameSettings


local LocalPlayer = Players.LocalPlayer
local LocalPlayer = Players.LocalPlayer
if not LocalPlayer then
if not LocalPlayer then
Players:GetPropertyChangedSignal("LocalPlayer"):Wait()
Players:GetPropertyChangedSignal("LocalPlayer"):Wait()
LocalPlayer = Players.LocalPlayer
LocalPlayer = Players.LocalPlayer
end
end


local Camera = Workspace.CurrentCamera
local Camera = Workspace.CurrentCamera
Workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function()
Workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function()
local newCamera = Workspace.CurrentCamera
local newCamera = Workspace.CurrentCamera
if newCamera then
if newCamera then
Camera = newCamera
Camera = newCamera
end
end
end)
end)


local FFlagUserExitFreecamBreaksWithShiftlock
local FFlagUserExitFreecamBreaksWithShiftlock
do
do
local success, result = pcall(function()
local success, result = pcall(function()
return UserSettings():IsUserFeatureEnabled("UserExitFreecamBreaksWithShiftlock")
return UserSettings():IsUserFeatureEnabled("UserExitFreecamBreaksWithShiftlock")
end)
end)
FFlagUserExitFreecamBreaksWithShiftlock = success and result
FFlagUserExitFreecamBreaksWithShiftlock = success and result
end

local FFlagUserShowGuiHideToggles
do
local success, result = pcall(function()
return UserSettings():IsUserFeatureEnabled("UserShowGuiHideToggles")
end)
FFlagUserShowGuiHideToggles = success and result
end
end


------------------------------------------------------------------------
------------------------------------------------------------------------


local FREECAM_ENABLED_ATTRIBUTE_NAME = "FreecamEnabled"
local TOGGLE_INPUT_PRIORITY = Enum.ContextActionPriority.Low.Value
local TOGGLE_INPUT_PRIORITY = Enum.ContextActionPriority.Low.Value
local INPUT_PRIORITY = Enum.ContextActionPriority.High.Value
local INPUT_PRIORITY = Enum.ContextActionPriority.High.Value
local FREECAM_MACRO_KB = {Enum.KeyCode.LeftShift, Enum.KeyCode.P}
local FREECAM_MACRO_KB = {Enum.KeyCode.LeftShift, Enum.KeyCode.P}


local NAV_GAIN = Vector3.new(1, 1, 1)*64
local NAV_GAIN = Vector3.new(1, 1, 1)*64
local PAN_GAIN = Vector2.new(0.75, 1)*8
local PAN_GAIN = Vector2.new(0.75, 1)*8
local FOV_GAIN = 300
local FOV_GAIN = 300


local PITCH_LIMIT = rad(90)
local PITCH_LIMIT = rad(90)


local VEL_STIFFNESS = 1.5
local VEL_STIFFNESS = 1.5
local PAN_STIFFNESS = 1.0
local PAN_STIFFNESS = 1.0
local FOV_STIFFNESS = 4.0
local FOV_STIFFNESS = 4.0


------------------------------------------------------------------------
------------------------------------------------------------------------


local Spring = {} do
local Spring = {} do
Spring.__index = Spring
Spring.__index = Spring


function Spring.new(freq, pos)
function Spring.new(freq, pos)
local self = setmetatable({}, Spring)
local self = setmetatable({}, Spring)
self.f = freq
self.f = freq
self.p = pos
self.p = pos
self.v = pos*0
self.v = pos*0
return self
return self
end
end


function Spring:Update(dt, goal)
function Spring:Update(dt, goal)
local f = self.f*2*pi
local f = self.f*2*pi
local p0 = self.p
local p0 = self.p
local v0 = self.v
local v0 = self.v


local offset = goal - p0
local offset = goal - p0
local decay = exp(-f*dt)
local decay = exp(-f*dt)


local p1 = goal + (v0*dt - offset*(f*dt + 1))*decay
local p1 = goal + (v0*dt - offset*(f*dt + 1))*decay
local v1 = (f*dt*(offset*f - v0) + v0)*decay
local v1 = (f*dt*(offset*f - v0) + v0)*decay


self.p = p1
self.p = p1
self.v = v1
self.v = v1


return p1
return p1
end
end


function Spring:Reset(pos)
function Spring:Reset(pos)
self.p = pos
self.p = pos
self.v = pos*0
self.v = pos*0
end
end
end
end


------------------------------------------------------------------------
------------------------------------------------------------------------


local cameraPos = Vector3.new()
local cameraPos = Vector3.new()
local cameraRot = Vector2.new()
local cameraRot = Vector2.new()
local cameraFov = 0
local cameraFov = 0


local velSpring = Spring.new(VEL_STIFFNESS, Vector3.new())
local velSpring = Spring.new(VEL_STIFFNESS, Vector3.new())
local panSpring = Spring.new(PAN_STIFFNESS, Vector2.new())
local panSpring = Spring.new(PAN_STIFFNESS, Vector2.new())
local fovSpring = Spring.new(FOV_STIFFNESS, 0)
local fovSpring = Spring.new(FOV_STIFFNESS, 0)


------------------------------------------------------------------------
------------------------------------------------------------------------


local Input = {} do
local Input = {} do
local thumbstickCurve do
local thumbstickCurve do
local K_CURVATURE = 2.0
local K_CURVATURE = 2.0
local K_DEADZONE = 0.15
local K_DEADZONE = 0.15


local function fCurve(x)
local function fCurve(x)
return (exp(K_CURVATURE*x) - 1)/(exp(K_CURVATURE) - 1)
return (exp(K_CURVATURE*x) - 1)/(exp(K_CURVATURE) - 1)
end
end


local function fDeadzone(x)
local function fDeadzone(x)
return fCurve((x - K_DEADZONE)/(1 - K_DEADZONE))
return fCurve((x - K_DEADZONE)/(1 - K_DEADZONE))
end
end


function thumbstickCurve(x)
function thumbstickCurve(x)
return sign(x)*clamp(fDeadzone(abs(x)), 0, 1)
return sign(x)*clamp(fDeadzone(abs(x)), 0, 1)
end
end
end
end


local gamepad = {
local gamepad = {
ButtonX = 0,
ButtonX = 0,
ButtonY = 0,
ButtonY = 0,
DPadDown = 0,
DPadDown = 0,
DPadUp = 0,
DPadUp = 0,
ButtonL2 = 0,
ButtonL2 = 0,
ButtonR2 = 0,
ButtonR2 = 0,
Thumbstick1 = Vector2.new(),
Thumbstick1 = Vector2.new(),
Thumbstick2 = Vector2.new(),
Thumbstick2 = Vector2.new(),
}
}


local keyboard = {
local keyboard = {
W = 0,
W = 0,
A = 0,
A = 0,
S = 0,
S = 0,
D = 0,
D = 0,
E = 0,
E = 0,
Q = 0,
Q = 0,
U = 0,
U = 0,
H = 0,
H = 0,
J = 0,
J = 0,
K = 0,
K = 0,
I = 0,
I = 0,
Y = 0,
Y = 0,
Up = 0,
Up = 0,
Down = 0,
Down = 0,
LeftShift = 0,
LeftShift = 0,
RightShift = 0,
RightShift = 0,
}
}


local mouse = {
local mouse = {
Delta = Vector2.new(),
Delta = Vector2.new(),
MouseWheel = 0,
MouseWheel = 0,
}
}


local NAV_GAMEPAD_SPEED = Vector3.new(1, 1, 1)
local NAV_GAMEPAD_SPEED = Vector3.new(1, 1, 1)
local NAV_KEYBOARD_SPEED = Vector3.new(1, 1, 1)
local NAV_KEYBOARD_SPEED = Vector3.new(1, 1, 1)
local PAN_MOUSE_SPEED = Vector2.new(1, 1)*(pi/64)
local PAN_MOUSE_SPEED = Vector2.new(1, 1)*(pi/64)
local PAN_GAMEPAD_SPEED = Vector2.new(1, 1)*(pi/8)
local PAN_GAMEPAD_SPEED = Vector2.new(1, 1)*(pi/8)
local FOV_WHEEL_SPEED = 1.0
local FOV_WHEEL_SPEED = 1.0
local FOV_GAMEPAD_SPEED = 0.25
local FOV_GAMEPAD_SPEED = 0.25
local NAV_ADJ_SPEED = 0.75
local NAV_ADJ_SPEED = 0.75
local NAV_SHIFT_MUL = 0.25
local NAV_SHIFT_MUL = 0.25


local navSpeed = 1
local navSpeed = 1


function Input.Vel(dt)
function Input.Vel(dt)
navSpeed = clamp(navSpeed + dt*(keyboard.Up - keyboard.Down)*NAV_ADJ_SPEED, 0.01, 4)
navSpeed = clamp(navSpeed + dt*(keyboard.Up - keyboard.Down)*NAV_ADJ_SPEED, 0.01, 4)


local kGamepad = Vector3.new(
local kGamepad = Vector3.new(
thumbstickCurve(gamepad.Thumbstick1.X),
thumbstickCurve(gamepad.Thumbstick1.X),
thumbstickCurve(gamepad.ButtonR2) - thumbstickCurve(gamepad.ButtonL2),
thumbstickCurve(gamepad.ButtonR2) - thumbstickCurve(gamepad.ButtonL2),
thumbstickCurve(-gamepad.Thumbstick1.Y)
thumbstickCurve(-gamepad.Thumbstick1.Y)
)*NAV_GAMEPAD_SPEED
)*NAV_GAMEPAD_SPEED


local kKeyboard = Vector3.new(
local kKeyboard = Vector3.new(
keyboard.D - keyboard.A + keyboard.K - keyboard.H,
keyboard.D - keyboard.A + keyboard.K - keyboard.H,
keyboard.E - keyboard.Q + keyboard.I - keyboard.Y,
keyboard.E - keyboard.Q + keyboard.I - keyboard.Y,
keyboard.S - keyboard.W + keyboard.J - keyboard.U
keyboard.S - keyboard.W + keyboard.J - keyboard.U
)*NAV_KEYBOARD_SPEED
)*NAV_KEYBOARD_SPEED


local shift = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift)
local shift = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift)


return (kGamepad + kKeyboard)*(navSpeed*(shift and NAV_SHIFT_MUL or 1))
return (kGamepad + kKeyboard)*(navSpeed*(shift and NAV_SHIFT_MUL or 1))
end
end


function Input.Pan(dt)
function Input.Pan(dt)
local kGamepad = Vector2.new(
local kGamepad = Vector2.new(
thumbstickCurve(gamepad.Thumbstick2.Y),
thumbstickCurve(gamepad.Thumbstick2.Y),
thumbstickCurve(-gamepad.Thumbstick2.X)
thumbstickCurve(-gamepad.Thumbstick2.X)
)*PAN_GAMEPAD_SPEED
)*PAN_GAMEPAD_SPEED
local kMouse = mouse.Delta*PAN_MOUSE_SPEED
local kMouse = mouse.Delta*PAN_MOUSE_SPEED
mouse.Delta = Vector2.new()
mouse.Delta = Vector2.new()
return kGamepad + kMouse
return kGamepad + kMouse
end
end


function Input.Fov(dt)
function Input.Fov(dt)
local kGamepad = (gamepad.ButtonX - gamepad.ButtonY)*FOV_GAMEPAD_SPEED
local kGamepad = (gamepad.ButtonX - gamepad.ButtonY)*FOV_GAMEPAD_SPEED
local kMouse = mouse.MouseWheel*FOV_WHEEL_SPEED
local kMouse = mouse.MouseWheel*FOV_WHEEL_SPEED
mouse.MouseWheel = 0
mouse.MouseWheel = 0
return kGamepad + kMouse
return kGamepad + kMouse
end
end


do
do
local function Keypress(action, state, input)
local function Keypress(action, state, input)
keyboard[input.KeyCode.Name] = state == Enum.UserInputState.Begin and 1 or 0
keyboard[input.KeyCode.Name] = state == Enum.UserInputState.Begin and 1 or 0
return Enum.ContextActionResult.Sink
return Enum.ContextActionResult.Sink
end
end


local function GpButton(action, state, input)
local function GpButton(action, state, input)
gamepad[input.KeyCode.Name] = state == Enum.UserInputState.Begin and 1 or 0
gamepad[input.KeyCode.Name] = state == Enum.UserInputState.Begin and 1 or 0
return Enum.ContextActionResult.Sink
return Enum.ContextActionResult.Sink
end
end


local function MousePan(action, state, input)
local function MousePan(action, state, input)
local delta = input.Delta
local delta = input.Delta
mouse.Delta = Vector2.new(-delta.y, -delta.x)
mouse.Delta = Vector2.new(-delta.y, -delta.x)
return Enum.ContextActionResult.Sink
return Enum.ContextActionResult.Sink
end
end


local function Thumb(action, state, input)
local function Thumb(action, state, input)
gamepad[input.KeyCode.Name] = input.Position
gamepad[input.KeyCode.Name] = input.Position
return Enum.ContextActionResult.Sink
return Enum.ContextActionResult.Sink
end
end


local function Trigger(action, state, input)
local function Trigger(action, state, input)
gamepad[input.KeyCode.Name] = input.Position.z
gamepad[input.KeyCode.Name] = input.Position.z
return Enum.ContextActionResult.Sink
return Enum.ContextActionResult.Sink
end
end


local function MouseWheel(action, state, input)
local function MouseWheel(action, state, input)
mouse[input.UserInputType.Name] = -input.Position.z
mouse[input.UserInputType.Name] = -input.Position.z
return Enum.ContextActionResult.Sink
return Enum.ContextActionResult.Sink
end
end


local function Zero(t)
local function Zero(t)
for k, v in pairs(t) do
for k, v in pairs(t) do
t[k] = v*0
t[k] = v*0
end
end
end
end


function Input.StartCapture()
function Input.StartCapture()
ContextActionService:BindActionAtPriority("FreecamKeyboard", Keypress, false, INPUT_PRIORITY,
ContextActionService:BindActionAtPriority("FreecamKeyboard", Keypress, false, INPUT_PRIORITY,
Enum.KeyCode.W, Enum.KeyCode.U,
Enum.KeyCode.W, Enum.KeyCode.U,
Enum.KeyCode.A, Enum.KeyCode.H,
Enum.KeyCode.A, Enum.KeyCode.H,
Enum.KeyCode.S, Enum.KeyCode.J,
Enum.KeyCode.S, Enum.KeyCode.J,
Enum.KeyCode.D, Enum.KeyCode.K,
Enum.KeyCode.D, Enum.KeyCode.K,
Enum.KeyCode.E, Enum.KeyCode.I,
Enum.KeyCode.E, Enum.KeyCode.I,
Enum.KeyCode.Q, Enum.KeyCode.Y,
Enum.KeyCode.Q, Enum.KeyCode.Y,
Enum.KeyCode.Up, Enum.KeyCode.Down
Enum.KeyCode.Up, Enum.KeyCode.Down
)
)
ContextActionService:BindActionAtPriority("FreecamMousePan", MousePan, false, INPUT_PRIORITY, Enum.UserInputType.MouseMovement)
ContextActionService:BindActionAtPriority("FreecamMousePan", MousePan, false, INPUT_PRIORITY, Enum.UserInputType.MouseMovement)
ContextActionService:BindActionAtPriority("FreecamMouseWheel", MouseWheel, false, INPUT_PRIORITY, Enum.UserInputType.MouseWheel)
ContextActionService:BindActionAtPriority("FreecamMouseWheel", MouseWheel, false, INPUT_PRIORITY, Enum.UserInputType.MouseWheel)
ContextActionService:BindActionAtPriority("FreecamGamepadButton", GpButton, false, INPUT_PRIORITY, Enum.KeyCode.ButtonX, Enum.KeyCode.ButtonY)
ContextActionService:BindActionAtPriority("FreecamGamepadButton", GpButton, false, INPUT_PRIORITY, Enum.KeyCode.ButtonX, Enum.KeyCode.ButtonY)
ContextActionService:BindActionAtPriority("FreecamGamepadTrigger", Trigger, false, INPUT_PRIORITY, Enum.KeyCode.ButtonR2, Enum.KeyCode.ButtonL2)
ContextActionService:BindActionAtPriority("FreecamGamepadTrigger", Trigger, false, INPUT_PRIORITY, Enum.KeyCode.ButtonR2, Enum.KeyCode.ButtonL2)
ContextActionService:BindActionAtPriority("FreecamGamepadThumbstick", Thumb, false, INPUT_PRIORITY, Enum.KeyCode.Thumbstick1, Enum.KeyCode.Thumbstick2)
ContextActionService:BindActionAtPriority("FreecamGamepadThumbstick", Thumb, false, INPUT_PRIORITY, Enum.KeyCode.Thumbstick1, Enum.KeyCode.Thumbstick2)
end
end


function Input.StopCapture()
function Input.StopCapture()
navSpeed = 1
navSpeed = 1
Zero(gamepad)
Zero(gamepad)
Zero(keyboard)
Zero(keyboard)
Zero(mouse)
Zero(mouse)
ContextActionService:UnbindAction("FreecamKeyboard")
ContextActionService:UnbindAction("FreecamKeyboard")
ContextActionService:UnbindAction("FreecamMousePan")
ContextActionService:UnbindAction("FreecamMousePan")
ContextActionService:UnbindAction("FreecamMouseWheel")
ContextActionService:UnbindAction("FreecamMouseWheel")
ContextActionService:UnbindAction("FreecamGamepadButton")
ContextActionService:UnbindAction("FreecamGamepadButton")
ContextActionService:UnbindAction("FreecamGamepadTrigger")
ContextActionService:UnbindAction("FreecamGamepadTrigger")
ContextActionService:UnbindAction("FreecamGamepadThumbstick")
ContextActionService:UnbindAction("FreecamGamepadThumbstick")
end
end
end
end
end
end


local function GetFocusDistance(cameraFrame)
local znear = 0.1
local viewport = Camera.ViewportSize
local projy = 2*tan(cameraFov/2)
local projx = viewport.x/viewport.y*projy
local fx = cameraFrame.rightVector
local fy = cameraFrame.upVector
local fz = cameraFrame.lookVector

local minVect = Vector3.new()
local minDist = 512

for x = 0, 1, 0.5 do
for y = 0, 1, 0.5 do
local cx = (x - 0.5)*projx
local cy = (y - 0.5)*projy
local offset = fx*cx - fy*cy + fz
local origin = cameraFrame.p + offset*znear
local _, hit = Workspace:FindPartOnRay(Ray.new(origin, offset.unit*minDist))
local dist = (hit - origin).magnitude
if minDist > dist then
minDist = dist
minVect = offset.unit
end
end
end

return fz:Dot(minVect)*minDist
end

------------------------------------------------------------------------
------------------------------------------------------------------------


local function StepFreecam(dt)
local function StepFreecam(dt)
local vel = velSpring:Update(dt, Input.Vel(dt))
local vel = velSpring:Update(dt, Input.Vel(dt))
local pan = panSpring:Update(dt, Input.Pan(dt))
local pan = panSpring:Update(dt, Input.Pan(dt))
local fov = fovSpring:Update(dt, Input.Fov(dt))
local fov = fovSpring:Update(dt, Input.Fov(dt))


local zoomFactor = sqrt(tan(rad(70/2))/tan(rad(cameraFov/2)))
local zoomFactor = sqrt(tan(rad(70/2))/tan(rad(cameraFov/2)))


cameraFov = clamp(cameraFov + fov*FOV_GAIN*(dt/zoomFactor), 1, 120)
cameraFov = clamp(cameraFov + fov*FOV_GAIN*(dt/zoomFactor), 1, 120)
cameraRot = cameraRot + pan*PAN_GAIN*(dt/zoomFactor)
cameraRot = cameraRot + pan*PAN_GAIN*(dt/zoomFactor)
cameraRot = Vector2.new(clamp(cameraRot.x, -PITCH_LIMIT, PITCH_LIMIT), cameraRot.y%(2*pi))
cameraRot = Vector2.new(clamp(cameraRot.x, -PITCH_LIMIT, PITCH_LIMIT), cameraRot.y%(2*pi))


local cameraCFrame = CFrame.new(cameraPos)*CFrame.fromOrientation(cameraRot.x, cameraRot.y, 0)*CFrame.new(vel*NAV_GAIN*dt)
local cameraCFrame = CFrame.new(cameraPos)*CFrame.fromOrientation(cameraRot.x, cameraRot.y, 0)*CFrame.new(vel*NAV_GAIN*dt)
cameraPos = cameraCFrame.p
cameraPos = cameraCFrame.p


Camera.CFrame = cameraCFrame
Camera.CFrame = cameraCFrame
Camera.Focus = cameraCFrame*CFrame.new(0, 0, -GetFocusDistance(cameraCFrame))
Camera.Focus = cameraCFrame
Camera.FieldOfView = cameraFov
Camera.FieldOfView = cameraFov
end
end


local function CheckMouseLockAvailability()
local function CheckMouseLockAvailability()
local devAllowsMouseLock = Players.LocalPlayer.DevEnableMouseLock
local devAllowsMouseLock = Players.LocalPlayer.DevEnableMouseLock
local devMovementModeIsScriptable = Players.LocalPlayer.DevComputerMovementMode == Enum.DevComputerMovementMode.Scriptable
local devMovementModeIsScriptable = Players.LocalPlayer.DevComputerMovementMode == Enum.DevComputerMovementMode.Scriptable
local userHasMouseLockModeEnabled = GameSettings.ControlMode == Enum.ControlMode.MouseLockSwitch
local userHasMouseLockModeEnabled = GameSettings.ControlMode == Enum.ControlMode.MouseLockSwitch
local userHasClickToMoveEnabled = GameSettings.ComputerMovementMode == Enum.ComputerMovementMode.ClickToMove
local userHasClickToMoveEnabled = GameSettings.ComputerMovementMode == Enum.ComputerMovementMode.ClickToMove
local MouseLockAvailable = devAllowsMouseLock and userHasMouseLockModeEnabled and not userHasClickToMoveEnabled and not devMovementModeIsScriptable
local MouseLockAvailable = devAllowsMouseLock and userHasMouseLockModeEnabled and not userHasClickToMoveEnabled and not devMovementModeIsScriptable


return MouseLockAvailable
return MouseLockAvailable
end
end


------------------------------------------------------------------------
------------------------------------------------------------------------


local PlayerState = {} do
local PlayerState = {} do
local mouseBehavior
local mouseBehavior
local mouseIconEnabled
local mouseIconEnabled
local cameraType
local cameraType
local cameraFocus
local cameraFocus
local cameraCFrame
local cameraCFrame
local cameraFieldOfView
local cameraFieldOfView
local screenGuis = {}
local screenGuis = {}
local coreGuis = {
local coreGuis = {
Backpack = true,
Backpack = true,
Chat = true,
Chat = true,
Health = true,
Health = true,
PlayerList = true,
PlayerList = true,
}
}
local setCores = {
local setCores = {
BadgesNotificationsActive = true,
BadgesNotificationsActive = true,
PointsNotificationsActive = true,
PointsNotificationsActive = true,
}
}


-- Save state and set up for freecam
-- Save state and set up for freecam
function PlayerState.Push()
function PlayerState.Push()
for name in pairs(coreGuis) do
for name in pairs(coreGuis) do
coreGuis[name] = StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType[name])
coreGuis[name] = StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType[name])
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType[name], false)
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType[name], false)
end
end
for name in pairs(setCores) do
for name in pairs(setCores) do
setCores[name] = StarterGui:GetCore(name)
setCores[name] = StarterGui:GetCore(name)
StarterGui:SetCore(name, false)
StarterGui:SetCore(name, false)
end
end
local playergui = LocalPlayer:FindFirstChildOfClass("PlayerGui")
local playergui = LocalPlayer:FindFirstChildOfClass("PlayerGui")
if playergui then
if playergui then
for _, gui in pairs(playergui:GetChildren()) do
for _, gui in pairs(playergui:GetChildren()) do
if gui:IsA("ScreenGui") and gui.Enabled then
if gui:IsA("ScreenGui") and gui.Enabled then
screenGuis[#screenGuis + 1] = gui
screenGuis[#screenGuis + 1] = gui
gui.Enabled = false
gui.Enabled = false
end
end
end
end
end
end


cameraFieldOfView = Camera.FieldOfView
cameraFieldOfView = Camera.FieldOfView
Camera.FieldOfView = 70
Camera.FieldOfView = 70


cameraType = Camera.CameraType
cameraType = Camera.CameraType
Camera.CameraType = Enum.CameraType.Custom
Camera.CameraType = Enum.CameraType.Custom


cameraCFrame = Camera.CFrame
cameraCFrame = Camera.CFrame
cameraFocus = Camera.Focus
cameraFocus = Camera.Focus


mouseIconEnabled = UserInputService.MouseIconEnabled
mouseIconEnabled = UserInputService.MouseIconEnabled
UserInputService.MouseIconEnabled = false
UserInputService.MouseIconEnabled = false


if FFlagUserExitFreecamBreaksWithShiftlock and CheckMouseLockAvailability() then
if FFlagUserExitFreecamBreaksWithShiftlock and CheckMouseLockAvailability() then
mouseBehavior = Enum.MouseBehavior.Default
mouseBehavior = Enum.MouseBehavior.Default
else
else
mouseBehavior = UserInputService.MouseBehavior
mouseBehavior = UserInputService.MouseBehavior
end
end
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
end
end


-- Restore state
-- Restore state
function PlayerState.Pop()
function PlayerState.Pop()
for name, isEnabled in pairs(coreGuis) do
for name, isEnabled in pairs(coreGuis) do
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType[name], isEnabled)
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType[name], isEnabled)
end
end
for name, isEnabled in pairs(setCores) do
for name, isEnabled in pairs(setCores) do
StarterGui:SetCore(name, isEnabled)
StarterGui:SetCore(name, isEnabled)
end
end
for _, gui in pairs(screenGuis) do
for _, gui in pairs(screenGuis) do
if gui.Parent then
if gui.Parent then
gui.Enabled = true
gui.Enabled = true
end
end
end
end


Camera.FieldOfView = cameraFieldOfView
Camera.FieldOfView = cameraFieldOfView
cameraFieldOfView = nil
cameraFieldOfView = nil


Camera.CameraType = cameraType
Camera.CameraType = cameraType
cameraType = nil
cameraType = nil


Camera.CFrame = cameraCFrame
Camera.CFrame = cameraCFrame
cameraCFrame = nil
cameraCFrame = nil


Camera.Focus = cameraFocus
Camera.Focus = cameraFocus
cameraFocus = nil
cameraFocus = nil


UserInputService.MouseIconEnabled = mouseIconEnabled
UserInputService.MouseIconEnabled = mouseIconEnabled
mouseIconEnabled = nil
mouseIconEnabled = nil


UserInputService.MouseBehavior = mouseBehavior
UserInputService.MouseBehavior = mouseBehavior
mouseBehavior = nil
mouseBehavior = nil
end
end
end
end


local function StartFreecam()
local function StartFreecam()
if FFlagUserShowGuiHideToggles then
script:SetAttribute(FREECAM_ENABLED_ATTRIBUTE_NAME, true)
end

local cameraCFrame = Camera.CFrame
local cameraCFrame = Camera.CFrame
cameraRot = Vector2.new(cameraCFrame:toEulerAnglesYXZ())
cameraRot = Vector2.new(cameraCFrame:toEulerAnglesYXZ())
cameraPos = cameraCFrame.p
cameraPos = cameraCFrame.p
cameraFov = Camera.FieldOfView
cameraFov = Camera.FieldOfView


velSpring:Reset(Vector3.new())
velSpring:Reset(Vector3.new())
panSpring:Reset(Vector2.new())
panSpring:Reset(Vector2.new())
fovSpring:Reset(0)
fovSpring:Reset(0)


PlayerState.Push()
PlayerState.Push()
RunService:BindToRenderStep("Freecam", Enum.RenderPriority.Camera.Value, StepFreecam)
RunService:BindToRenderStep("Freecam", Enum.RenderPriority.Camera.Value, StepFreecam)
Input.StartCapture()
Input.StartCapture()
end
end


local function StopFreecam()
local function StopFreecam()
if FFlagUserShowGuiHideToggles then
script:SetAttribute(FREECAM_ENABLED_ATTRIBUTE_NAME, false)
end

Input.StopCapture()
Input.StopCapture()
RunService:UnbindFromRenderStep("Freecam")
RunService:UnbindFromRenderStep("Freecam")
PlayerState.Pop()
PlayerState.Pop()
end
end


------------------------------------------------------------------------
------------------------------------------------------------------------


do
do
local enabled = false
local enabled = false


local function ToggleFreecam()
local function ToggleFreecam()
if enabled then
if enabled then
StopFreecam()
StopFreecam()
else
else
StartFreecam()
StartFreecam()
end
end
enabled = not enabled
enabled = not enabled
end
end


local function CheckMacro(macro)
local function CheckMacro(macro)
for i = 1, #macro - 1 do
for i = 1, #macro - 1 do
if not UserInputService:IsKeyDown(macro[i]) then
if not UserInputService:IsKeyDown(macro[i]) then
return
return
end
end
end
end
ToggleFreecam()
ToggleFreecam()
end
end


local function HandleActivationInput(action, state, input)
local function HandleActivationInput(action, state, input)
if state == Enum.UserInputState.Begin then
if state == Enum.UserInputState.Begin then
if input.KeyCode == FREECAM_MACRO_KB[#FREECAM_MACRO_KB] then
if input.KeyCode == FREECAM_MACRO_KB[#FREECAM_MACRO_KB] then
CheckMacro(FREECAM_MACRO_KB)
CheckMacro(FREECAM_MACRO_KB)
end
end
end
end
return Enum.ContextActionResult.Pass
return Enum.ContextActionResult.Pass
end
end


ContextActionService:BindActionAtPriority("FreecamToggle", HandleActivationInput, false, TOGGLE_INPUT_PRIORITY, FREECAM_MACRO_KB[#FREECAM_MACRO_KB])
ContextActionService:BindActionAtPriority("FreecamToggle", HandleActivationInput, false, TOGGLE_INPUT_PRIORITY, FREECAM_MACRO_KB[#FREECAM_MACRO_KB])

if FFlagUserShowGuiHideToggles then
script:SetAttribute(FREECAM_ENABLED_ATTRIBUTE_NAME, enabled)
script:GetAttributeChangedSignal(FREECAM_ENABLED_ATTRIBUTE_NAME):Connect(function()
local attributeValue = script:GetAttribute(FREECAM_ENABLED_ATTRIBUTE_NAME)

if typeof(attributeValue) ~= "boolean" then
script:SetAttribute(FREECAM_ENABLED_ATTRIBUTE_NAME, enabled)
return
end

-- If the attribute's value and `enabled` var don't match, pick attribute value as
-- source of truth
if attributeValue ~= enabled then
if attributeValue then
StartFreecam()
enabled = true
else
StopFreecam()
enabled = false
end
end
end)
end
end
end