The text below is selected, press Ctrl+C to copy to your clipboard. (⌘+C on Mac) No line numbers will be copied.
Guest
Walk on walls script script pastebin roblox
By Walk on walls script on 2024-09-22 08:00 am | Syntax: LUA | Views: 8



New Script | Raw | Show/Hide line no. | Copy text to clipboard
  1. --[[
  2. local _p = game:WaitForChild("Players")
  3. local _plr = _p.ChildAdded:Wait()
  4. if _plr == _p.LocalPlayer then
  5.         _plr.ChildAdded:Connect(function(cccc)
  6.                 if c.Name == "PlayerScriptsLoader" then
  7.                         c.Disabled = true
  8.                 end
  9.         end)
  10. end
  11. ]]
  12. repeat wait()
  13. a = pcall(function()
  14.         game:WaitForChild("Players").LocalPlayer:WaitForChild("PlayerScripts").ChildAdded:Connect(function(c)
  15.                 if c.Name == "PlayerScriptsLoader"then
  16.                         c.Disabled = true
  17.                 end
  18.         end)
  19.         end)
  20.         if a == true then break end
  21. until true == false
  22. game:WaitForChild("Players").LocalPlayer:WaitForChild("PlayerScripts").ChildAdded:Connect(function(c)
  23.         if c.Name == "PlayerScriptsLoader"then
  24.                 c.Disabled = true
  25.         end
  26. end)
  27.  
  28.  
  29. function _CameraUI()
  30.         local Players = game:GetService("Players")
  31.         local TweenService = game:GetService("TweenService")
  32.        
  33.         local LocalPlayer = Players.LocalPlayer
  34.         if not LocalPlayer then
  35.                 Players:GetPropertyChangedSignal("LocalPlayer"):Wait()
  36.                 LocalPlayer = Players.LocalPlayer
  37.         end
  38.        
  39.         local function waitForChildOfClass(parent, class)
  40.                 local child = parent:FindFirstChildOfClass(class)
  41.                 while not child or child.ClassName ~= class do
  42.                         child = parent.ChildAdded:Wait()
  43.                 end
  44.                 return child
  45.         end
  46.        
  47.         local PlayerGui = waitForChildOfClass(LocalPlayer, "PlayerGui")
  48.        
  49.         local TOAST_OPEN_SIZE = UDim2.new(0, 326, 0, 58)
  50.         local TOAST_CLOSED_SIZE = UDim2.new(0, 80, 0, 58)
  51.         local TOAST_BACKGROUND_COLOR = Color3.fromRGB(32, 32, 32)
  52.         local TOAST_BACKGROUND_TRANS = 0.4
  53.         local TOAST_FOREGROUND_COLOR = Color3.fromRGB(200, 200, 200)
  54.         local TOAST_FOREGROUND_TRANS = 0
  55.        
  56.         -- Convenient syntax for creating a tree of instanes
  57.         local function create(className)
  58.                 return function(props)
  59.                         local inst = Instance.new(className)
  60.                         local parent = props.Parent
  61.                         props.Parent = nil
  62.                         for name, val in pairs(props) do
  63.                                 if type(name) == "string" then
  64.                                         inst[name] = val
  65.                                 else
  66.                                         val.Parent = inst
  67.                                 end
  68.                         end
  69.                         -- Only set parent after all other properties are initialized
  70.                         inst.Parent = parent
  71.                         return inst
  72.                 end
  73.         end
  74.        
  75.         local initialized = false
  76.        
  77.         local uiRoot
  78.         local toast
  79.         local toastIcon
  80.         local toastUpperText
  81.         local toastLowerText
  82.        
  83.         local function initializeUI()
  84.                 assert(not initialized)
  85.        
  86.                 uiRoot = create("ScreenGui"){
  87.                         Name = "RbxCameraUI",
  88.                         AutoLocalize = false,
  89.                         Enabled = true,
  90.                         DisplayOrder = -1, -- Appears behind default developer UI
  91.                         IgnoreGuiInset = false,
  92.                         ResetOnSpawn = false,
  93.                         ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
  94.        
  95.                         create("ImageLabel"){
  96.                                 Name = "Toast",
  97.                                 Visible = false,
  98.                                 AnchorPoint = Vector2.new(0.5, 0),
  99.                                 BackgroundTransparency = 1,
  100.                                 BorderSizePixel = 0,
  101.                                 Position = UDim2.new(0.5, 0, 0, 8),
  102.                                 Size = TOAST_CLOSED_SIZE,
  103.                                 Image = "rbxasset://textures/ui/Camera/CameraToast9Slice.png",
  104.                                 ImageColor3 = TOAST_BACKGROUND_COLOR,
  105.                                 ImageRectSize = Vector2.new(6, 6),
  106.                                 ImageTransparency = 1,
  107.                                 ScaleType = Enum.ScaleType.Slice,
  108.                                 SliceCenter = Rect.new(3, 3, 3, 3),
  109.                                 ClipsDescendants = true,
  110.        
  111.                                 create("Frame"){
  112.                                         Name = "IconBuffer",
  113.                                         BackgroundTransparency = 1,
  114.                                         BorderSizePixel = 0,
  115.                                         Position = UDim2.new(0, 0, 0, 0),
  116.                                         Size = UDim2.new(0, 80, 1, 0),
  117.        
  118.                                         create("ImageLabel"){
  119.                                                 Name = "Icon",
  120.                                                 AnchorPoint = Vector2.new(0.5, 0.5),
  121.                                                 BackgroundTransparency = 1,
  122.                                                 Position = UDim2.new(0.5, 0, 0.5, 0),
  123.                                                 Size = UDim2.new(0, 48, 0, 48),
  124.                                                 ZIndex = 2,
  125.                                                 Image = "rbxasset://textures/ui/Camera/CameraToastIcon.png",
  126.                                                 ImageColor3 = TOAST_FOREGROUND_COLOR,
  127.                                                 ImageTransparency = 1,
  128.                                         }
  129.                                 },
  130.        
  131.                                 create("Frame"){
  132.                                         Name = "TextBuffer",
  133.                                         BackgroundTransparency = 1,
  134.                                         BorderSizePixel = 0,
  135.                                         Position = UDim2.new(0, 80, 0, 0),
  136.                                         Size = UDim2.new(1, -80, 1, 0),
  137.                                         ClipsDescendants = true,
  138.        
  139.                                         create("TextLabel"){
  140.                                                 Name = "Upper",
  141.                                                 AnchorPoint = Vector2.new(0, 1),
  142.                                                 BackgroundTransparency = 1,
  143.                                                 Position = UDim2.new(0, 0, 0.5, 0),
  144.                                                 Size = UDim2.new(1, 0, 0, 19),
  145.                                                 Font = Enum.Font.GothamSemibold,
  146.                                                 Text = "Camera control enabled",
  147.                                                 TextColor3 = TOAST_FOREGROUND_COLOR,
  148.                                                 TextTransparency = 1,
  149.                                                 TextSize = 19,
  150.                                                 TextXAlignment = Enum.TextXAlignment.Left,
  151.                                                 TextYAlignment = Enum.TextYAlignment.Center,
  152.                                         },
  153.        
  154.                                         create("TextLabel"){
  155.                                                 Name = "Lower",
  156.                                                 AnchorPoint = Vector2.new(0, 0),
  157.                                                 BackgroundTransparency = 1,
  158.                                                 Position = UDim2.new(0, 0, 0.5, 3),
  159.                                                 Size = UDim2.new(1, 0, 0, 15),
  160.                                                 Font = Enum.Font.Gotham,
  161.                                                 Text = "Right mouse button to toggle",
  162.                                                 TextColor3 = TOAST_FOREGROUND_COLOR,
  163.                                                 TextTransparency = 1,
  164.                                                 TextSize = 15,
  165.                                                 TextXAlignment = Enum.TextXAlignment.Left,
  166.                                                 TextYAlignment = Enum.TextYAlignment.Center,
  167.                                         },
  168.                                 },
  169.                         },
  170.        
  171.                         Parent = PlayerGui,
  172.                 }
  173.        
  174.                 toast = uiRoot.Toast
  175.                 toastIcon = toast.IconBuffer.Icon
  176.                 toastUpperText = toast.TextBuffer.Upper
  177.                 toastLowerText = toast.TextBuffer.Lower
  178.        
  179.                 initialized = true
  180.         end
  181.        
  182.         local CameraUI = {}
  183.        
  184.         do
  185.                 -- Instantaneously disable the toast or enable for opening later on. Used when switching camera modes.
  186.                 function CameraUI.setCameraModeToastEnabled(enabled)
  187.                         if not enabled and not initialized then
  188.                                 return
  189.                         end
  190.        
  191.                         if not initialized then
  192.                                 initializeUI()
  193.                         end
  194.        
  195.                         toast.Visible = enabled
  196.                         if not enabled then
  197.                                 CameraUI.setCameraModeToastOpen(false)
  198.                         end
  199.                 end
  200.        
  201.                 local tweenInfo = TweenInfo.new(0.25, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
  202.        
  203.                 -- Tween the toast in or out. Toast must be enabled with setCameraModeToastEnabled.
  204.                 function CameraUI.setCameraModeToastOpen(open)
  205.                         assert(initialized)
  206.        
  207.                         TweenService:Create(toast, tweenInfo, {
  208.                                 Size = open and TOAST_OPEN_SIZE or TOAST_CLOSED_SIZE,
  209.                                 ImageTransparency = open and TOAST_BACKGROUND_TRANS or 1,
  210.                         }):Play()
  211.        
  212.                         TweenService:Create(toastIcon, tweenInfo, {
  213.                                 ImageTransparency = open and TOAST_FOREGROUND_TRANS or 1,
  214.                         }):Play()
  215.        
  216.                         TweenService:Create(toastUpperText, tweenInfo, {
  217.                                 TextTransparency = open and TOAST_FOREGROUND_TRANS or 1,
  218.                         }):Play()
  219.        
  220.                         TweenService:Create(toastLowerText, tweenInfo, {
  221.                                 TextTransparency = open and TOAST_FOREGROUND_TRANS or 1,
  222.                         }):Play()
  223.                 end
  224.         end
  225.        
  226.         return CameraUI
  227. end
  228.  
  229. function _CameraToggleStateController()
  230.         local Players = game:GetService("Players")
  231.         local UserInputService = game:GetService("UserInputService")
  232.         local GameSettings = UserSettings():GetService("UserGameSettings")
  233.        
  234.         local LocalPlayer = Players.LocalPlayer
  235.         if not LocalPlayer then
  236.                 Players:GetPropertyChangedSignal("LocalPlayer"):Wait()
  237.                 LocalPlayer = Players.LocalPlayer
  238.         end
  239.        
  240.         local Mouse = LocalPlayer:GetMouse()
  241.        
  242.         local Input = _CameraInput()
  243.         local CameraUI = _CameraUI()
  244.        
  245.         local lastTogglePan = false
  246.         local lastTogglePanChange = tick()
  247.        
  248.         local CROSS_MOUSE_ICON = "rbxasset://textures/Cursors/CrossMouseIcon.png"
  249.        
  250.         local lockStateDirty = false
  251.         local wasTogglePanOnTheLastTimeYouWentIntoFirstPerson = false
  252.         local lastFirstPerson = false
  253.        
  254.         CameraUI.setCameraModeToastEnabled(false)
  255.        
  256.         return function(isFirstPerson)
  257.                 local togglePan = Input.getTogglePan()
  258.                 local toastTimeout = 3
  259.        
  260.                 if isFirstPerson and togglePan ~= lastTogglePan then
  261.                         lockStateDirty = true
  262.                 end
  263.        
  264.                 if lastTogglePan ~= togglePan or tick() - lastTogglePanChange > toastTimeout then
  265.                         local doShow = togglePan and tick() - lastTogglePanChange < toastTimeout
  266.        
  267.                         CameraUI.setCameraModeToastOpen(doShow)
  268.        
  269.                         if togglePan then
  270.                                 lockStateDirty = false
  271.                         end
  272.                         lastTogglePanChange = tick()
  273.                         lastTogglePan = togglePan
  274.                 end
  275.        
  276.                 if isFirstPerson ~= lastFirstPerson then
  277.                         if isFirstPerson then
  278.                                 wasTogglePanOnTheLastTimeYouWentIntoFirstPerson = Input.getTogglePan()
  279.                                 Input.setTogglePan(true)
  280.                         elseif not lockStateDirty then
  281.                                 Input.setTogglePan(wasTogglePanOnTheLastTimeYouWentIntoFirstPerson)
  282.                         end
  283.                 end
  284.        
  285.                 if isFirstPerson then
  286.                         if Input.getTogglePan() then
  287.                                 Mouse.Icon = CROSS_MOUSE_ICON
  288.                                 UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
  289.                                 --GameSettings.RotationType = Enum.RotationType.CameraRelative
  290.                         else
  291.                                 Mouse.Icon = ""
  292.                                 UserInputService.MouseBehavior = Enum.MouseBehavior.Default
  293.                                 --GameSettings.RotationType = Enum.RotationType.CameraRelative
  294.                         end
  295.        
  296.                 elseif Input.getTogglePan() then
  297.                         Mouse.Icon = CROSS_MOUSE_ICON
  298.                         UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
  299.                         GameSettings.RotationType = Enum.RotationType.MovementRelative
  300.        
  301.                 elseif Input.getHoldPan() then
  302.                         Mouse.Icon = ""
  303.                         UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
  304.                         GameSettings.RotationType = Enum.RotationType.MovementRelative
  305.        
  306.                 else
  307.                         Mouse.Icon = ""
  308.                         UserInputService.MouseBehavior = Enum.MouseBehavior.Default
  309.                         GameSettings.RotationType = Enum.RotationType.MovementRelative
  310.                 end
  311.        
  312.                 lastFirstPerson = isFirstPerson
  313.         end
  314. end
  315.  
  316. function _CameraInput()
  317.         local UserInputService = game:GetService("UserInputService")
  318.        
  319.         local MB_TAP_LENGTH = 0.3 -- length of time for a short mouse button tap to be registered
  320.        
  321.         local rmbDown, rmbUp
  322.         do
  323.                 local rmbDownBindable = Instance.new("BindableEvent")
  324.                 local rmbUpBindable = Instance.new("BindableEvent")
  325.        
  326.                 rmbDown = rmbDownBindable.Event
  327.                 rmbUp = rmbUpBindable.Event
  328.        
  329.                 UserInputService.InputBegan:Connect(function(input, gpe)
  330.                         if not gpe and input.UserInputType == Enum.UserInputType.MouseButton2 then
  331.                                 rmbDownBindable:Fire()
  332.                         end
  333.                 end)
  334.        
  335.                 UserInputService.InputEnded:Connect(function(input, gpe)
  336.                         if input.UserInputType == Enum.UserInputType.MouseButton2 then
  337.                                 rmbUpBindable:Fire()
  338.                         end
  339.                 end)
  340.         end
  341.        
  342.         local holdPan = false
  343.         local togglePan = false
  344.         local lastRmbDown = 0 -- tick() timestamp of the last right mouse button down event
  345.        
  346.         local CameraInput = {}
  347.        
  348.         function CameraInput.getHoldPan()
  349.                 return holdPan
  350.         end
  351.        
  352.         function CameraInput.getTogglePan()
  353.                 return togglePan
  354.         end
  355.        
  356.         function CameraInput.getPanning()
  357.                 return togglePan or holdPan
  358.         end
  359.        
  360.         function CameraInput.setTogglePan(value)
  361.                 togglePan = value
  362.         end
  363.        
  364.         local cameraToggleInputEnabled = false
  365.         local rmbDownConnection
  366.         local rmbUpConnection
  367.        
  368.         function CameraInput.enableCameraToggleInput()
  369.                 if cameraToggleInputEnabled then
  370.                         return
  371.                 end
  372.                 cameraToggleInputEnabled = true
  373.        
  374.                 holdPan = false
  375.                 togglePan = false
  376.        
  377.                 if rmbDownConnection then
  378.                         rmbDownConnection:Disconnect()
  379.                 end
  380.        
  381.                 if rmbUpConnection then
  382.                         rmbUpConnection:Disconnect()
  383.                 end
  384.        
  385.                 rmbDownConnection = rmbDown:Connect(function()
  386.                         holdPan = true
  387.                         lastRmbDown = tick()
  388.                 end)
  389.        
  390.                 rmbUpConnection = rmbUp:Connect(function()
  391.                         holdPan = false
  392.                         if tick() - lastRmbDown < MB_TAP_LENGTH and (togglePan or UserInputService:GetMouseDelta().Magnitude < 2) then
  393.                                 togglePan = not togglePan
  394.                         end
  395.                 end)
  396.         end
  397.        
  398.         function CameraInput.disableCameraToggleInput()
  399.                 if not cameraToggleInputEnabled then
  400.                         return
  401.                 end
  402.                 cameraToggleInputEnabled = false
  403.        
  404.                 if rmbDownConnection then
  405.                         rmbDownConnection:Disconnect()
  406.                         rmbDownConnection = nil
  407.                 end
  408.                 if rmbUpConnection then
  409.                         rmbUpConnection:Disconnect()
  410.                         rmbUpConnection = nil
  411.                 end
  412.         end
  413.        
  414.         return CameraInput
  415. end
  416.  
  417. function _BaseCamera()
  418.         --[[
  419.                 BaseCamera - Abstract base class for camera control modules
  420.                 2018 Camera Update - AllYourBlox
  421.         --]]
  422.        
  423.         --[[ Local Constants ]]--
  424.         local UNIT_Z = Vector3.new(0,0,1)
  425.         local X1_Y0_Z1 = Vector3.new(1,0,1)     --Note: not a unit vector, used for projecting onto XZ plane
  426.        
  427.         local THUMBSTICK_DEADZONE = 0.2
  428.         local DEFAULT_DISTANCE = 12.5   -- Studs
  429.         local PORTRAIT_DEFAULT_DISTANCE = 25            -- Studs
  430.         local FIRST_PERSON_DISTANCE_THRESHOLD = 1.0 -- Below this value, snap into first person
  431.        
  432.         local CAMERA_ACTION_PRIORITY = Enum.ContextActionPriority.Default.Value
  433.        
  434.         -- Note: DotProduct check in CoordinateFrame::lookAt() prevents using values within about
  435.         -- 8.11 degrees of the +/- Y axis, that's why these limits are currently 80 degrees
  436.         local MIN_Y = math.rad(-80)
  437.         local MAX_Y = math.rad(80)
  438.        
  439.         local TOUCH_ADJUST_AREA_UP = math.rad(30)
  440.         local TOUCH_ADJUST_AREA_DOWN = math.rad(-15)
  441.        
  442.         local TOUCH_SENSITIVTY_ADJUST_MAX_Y = 2.1
  443.         local TOUCH_SENSITIVTY_ADJUST_MIN_Y = 0.5
  444.        
  445.         local VR_ANGLE = math.rad(15)
  446.         local VR_LOW_INTENSITY_ROTATION = Vector2.new(math.rad(15), 0)
  447.         local VR_HIGH_INTENSITY_ROTATION = Vector2.new(math.rad(45), 0)
  448.         local VR_LOW_INTENSITY_REPEAT = 0.1
  449.         local VR_HIGH_INTENSITY_REPEAT = 0.4
  450.        
  451.         local ZERO_VECTOR2 = Vector2.new(0,0)
  452.         local ZERO_VECTOR3 = Vector3.new(0,0,0)
  453.        
  454.         local TOUCH_SENSITIVTY = Vector2.new(0.00945 * math.pi, 0.003375 * math.pi)
  455.         local MOUSE_SENSITIVITY = Vector2.new( 0.002 * math.pi, 0.0015 * math.pi )
  456.        
  457.         local SEAT_OFFSET = Vector3.new(0,5,0)
  458.         local VR_SEAT_OFFSET = Vector3.new(0,4,0)
  459.         local HEAD_OFFSET = Vector3.new(0,1.5,0)
  460.         local R15_HEAD_OFFSET = Vector3.new(0, 1.5, 0)
  461.         local R15_HEAD_OFFSET_NO_SCALING = Vector3.new(0, 2, 0)
  462.         local HUMANOID_ROOT_PART_SIZE = Vector3.new(2, 2, 1)
  463.        
  464.         local GAMEPAD_ZOOM_STEP_1 = 0
  465.         local GAMEPAD_ZOOM_STEP_2 = 10
  466.         local GAMEPAD_ZOOM_STEP_3 = 20
  467.        
  468.         local PAN_SENSITIVITY = 20
  469.         local ZOOM_SENSITIVITY_CURVATURE = 0.5
  470.        
  471.         local abs = math.abs
  472.         local sign = math.sign
  473.        
  474.         local FFlagUserCameraToggle do
  475.                 local success, result = pcall(function()
  476.                         return UserSettings():IsUserFeatureEnabled("UserCameraToggle")
  477.                 end)
  478.                 FFlagUserCameraToggle = success and result
  479.         end
  480.        
  481.         local FFlagUserDontAdjustSensitvityForPortrait do
  482.                 local success, result = pcall(function()
  483.                         return UserSettings():IsUserFeatureEnabled("UserDontAdjustSensitvityForPortrait")
  484.                 end)
  485.                 FFlagUserDontAdjustSensitvityForPortrait = success and result
  486.         end
  487.        
  488.         local FFlagUserFixZoomInZoomOutDiscrepancy do
  489.                 local success, result = pcall(function()
  490.                         return UserSettings():IsUserFeatureEnabled("UserFixZoomInZoomOutDiscrepancy")
  491.                 end)
  492.                 FFlagUserFixZoomInZoomOutDiscrepancy = success and result
  493.         end
  494.        
  495.         local Util = _CameraUtils()
  496.         local ZoomController = _ZoomController()
  497.         local CameraToggleStateController = _CameraToggleStateController()
  498.         local CameraInput = _CameraInput()
  499.         local CameraUI = _CameraUI()
  500.        
  501.         --[[ Roblox Services ]]--
  502.         local Players = game:GetService("Players")
  503.         local UserInputService = game:GetService("UserInputService")
  504.         local StarterGui = game:GetService("StarterGui")
  505.         local GuiService = game:GetService("GuiService")
  506.         local ContextActionService = game:GetService("ContextActionService")
  507.         local VRService = game:GetService("VRService")
  508.         local UserGameSettings = UserSettings():GetService("UserGameSettings")
  509.        
  510.         local player = Players.LocalPlayer
  511.        
  512.         --[[ The Module ]]--
  513.         local BaseCamera = {}
  514.         BaseCamera.__index = BaseCamera
  515.        
  516.         function BaseCamera.new()
  517.                 local self = setmetatable({}, BaseCamera)
  518.        
  519.                 -- So that derived classes have access to this
  520.                 self.FIRST_PERSON_DISTANCE_THRESHOLD = FIRST_PERSON_DISTANCE_THRESHOLD
  521.        
  522.                 self.cameraType = nil
  523.                 self.cameraMovementMode = nil
  524.        
  525.                 self.lastCameraTransform = nil
  526.                 self.rotateInput = ZERO_VECTOR2
  527.                 self.userPanningCamera = false
  528.                 self.lastUserPanCamera = tick()
  529.        
  530.                 self.humanoidRootPart = nil
  531.                 self.humanoidCache = {}
  532.        
  533.                 -- Subject and position on last update call
  534.                 self.lastSubject = nil
  535.                 self.lastSubjectPosition = Vector3.new(0,5,0)
  536.        
  537.                 -- These subject distance members refer to the nominal camera-to-subject follow distance that the camera
  538.                 -- is trying to maintain, not the actual measured value.
  539.                 -- The default is updated when screen orientation or the min/max distances change,
  540.                 -- to be sure the default is always in range and appropriate for the orientation.
  541.                 self.defaultSubjectDistance = math.clamp(DEFAULT_DISTANCE, player.CameraMinZoomDistance, player.CameraMaxZoomDistance)
  542.                 self.currentSubjectDistance = math.clamp(DEFAULT_DISTANCE, player.CameraMinZoomDistance, player.CameraMaxZoomDistance)
  543.        
  544.                 self.inFirstPerson = false
  545.                 self.inMouseLockedMode = false
  546.                 self.portraitMode = false
  547.                 self.isSmallTouchScreen = false
  548.        
  549.                 -- Used by modules which want to reset the camera angle on respawn.
  550.                 self.resetCameraAngle = true
  551.        
  552.                 self.enabled = false
  553.        
  554.                 -- Input Event Connections
  555.                 self.inputBeganConn = nil
  556.                 self.inputChangedConn = nil
  557.                 self.inputEndedConn = nil
  558.        
  559.                 self.startPos = nil
  560.                 self.lastPos = nil
  561.                 self.panBeginLook = nil
  562.        
  563.                 self.panEnabled = true
  564.                 self.keyPanEnabled = true
  565.                 self.distanceChangeEnabled = true
  566.        
  567.                 self.PlayerGui = nil
  568.        
  569.                 self.cameraChangedConn = nil
  570.                 self.viewportSizeChangedConn = nil
  571.        
  572.                 self.boundContextActions = {}
  573.        
  574.                 -- VR Support
  575.                 self.shouldUseVRRotation = false
  576.                 self.VRRotationIntensityAvailable = false
  577.                 self.lastVRRotationIntensityCheckTime = 0
  578.                 self.lastVRRotationTime = 0
  579.                 self.vrRotateKeyCooldown = {}
  580.                 self.cameraTranslationConstraints = Vector3.new(1, 1, 1)
  581.                 self.humanoidJumpOrigin = nil
  582.                 self.trackingHumanoid = nil
  583.                 self.cameraFrozen = false
  584.                 self.subjectStateChangedConn = nil
  585.        
  586.                 -- Gamepad support
  587.                 self.activeGamepad = nil
  588.                 self.gamepadPanningCamera = false
  589.                 self.lastThumbstickRotate = nil
  590.                 self.numOfSeconds = 0.7
  591.                 self.currentSpeed = 0
  592.                 self.maxSpeed = 6
  593.                 self.vrMaxSpeed = 4
  594.                 self.lastThumbstickPos = Vector2.new(0,0)
  595.                 self.ySensitivity = 0.65
  596.                 self.lastVelocity = nil
  597.                 self.gamepadConnectedConn = nil
  598.                 self.gamepadDisconnectedConn = nil
  599.                 self.currentZoomSpeed = 1.0
  600.                 self.L3ButtonDown = false
  601.                 self.dpadLeftDown = false
  602.                 self.dpadRightDown = false
  603.        
  604.                 -- Touch input support
  605.                 self.isDynamicThumbstickEnabled = false
  606.                 self.fingerTouches = {}
  607.                 self.dynamicTouchInput = nil
  608.                 self.numUnsunkTouches = 0
  609.                 self.inputStartPositions = {}
  610.                 self.inputStartTimes = {}
  611.                 self.startingDiff = nil
  612.                 self.pinchBeginZoom = nil
  613.                 self.userPanningTheCamera = false
  614.                 self.touchActivateConn = nil
  615.        
  616.                 -- Mouse locked formerly known as shift lock mode
  617.                 self.mouseLockOffset = ZERO_VECTOR3
  618.        
  619.                 -- [[ NOTICE ]] --
  620.                 -- Initialization things used to always execute at game load time, but now these camera modules are instantiated
  621.                 -- when needed, so the code here may run well after the start of the game
  622.        
  623.                 if player.Character then
  624.                         self:OnCharacterAdded(player.Character)
  625.                 end
  626.        
  627.                 player.CharacterAdded:Connect(function(char)
  628.                         self:OnCharacterAdded(char)
  629.                 end)
  630.        
  631.                 if self.cameraChangedConn then self.cameraChangedConn:Disconnect() end
  632.                 self.cameraChangedConn = workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function()
  633.                         self:OnCurrentCameraChanged()
  634.                 end)
  635.                 self:OnCurrentCameraChanged()
  636.        
  637.                 if self.playerCameraModeChangeConn then self.playerCameraModeChangeConn:Disconnect() end
  638.                 self.playerCameraModeChangeConn = player:GetPropertyChangedSignal("CameraMode"):Connect(function()
  639.                         self:OnPlayerCameraPropertyChange()
  640.                 end)
  641.        
  642.                 if self.minDistanceChangeConn then self.minDistanceChangeConn:Disconnect() end
  643.                 self.minDistanceChangeConn = player:GetPropertyChangedSignal("CameraMinZoomDistance"):Connect(function()
  644.                         self:OnPlayerCameraPropertyChange()
  645.                 end)
  646.        
  647.                 if self.maxDistanceChangeConn then self.maxDistanceChangeConn:Disconnect() end
  648.                 self.maxDistanceChangeConn = player:GetPropertyChangedSignal("CameraMaxZoomDistance"):Connect(function()
  649.                         self:OnPlayerCameraPropertyChange()
  650.                 end)
  651.        
  652.                 if self.playerDevTouchMoveModeChangeConn then self.playerDevTouchMoveModeChangeConn:Disconnect() end
  653.                 self.playerDevTouchMoveModeChangeConn = player:GetPropertyChangedSignal("DevTouchMovementMode"):Connect(function()
  654.                         self:OnDevTouchMovementModeChanged()
  655.                 end)
  656.                 self:OnDevTouchMovementModeChanged() -- Init
  657.        
  658.                 if self.gameSettingsTouchMoveMoveChangeConn then self.gameSettingsTouchMoveMoveChangeConn:Disconnect() end
  659.                 self.gameSettingsTouchMoveMoveChangeConn = UserGameSettings:GetPropertyChangedSignal("TouchMovementMode"):Connect(function()
  660.                         self:OnGameSettingsTouchMovementModeChanged()
  661.                 end)
  662.                 self:OnGameSettingsTouchMovementModeChanged() -- Init
  663.        
  664.                 UserGameSettings:SetCameraYInvertVisible()
  665.                 UserGameSettings:SetGamepadCameraSensitivityVisible()
  666.        
  667.                 self.hasGameLoaded = game:IsLoaded()
  668.                 if not self.hasGameLoaded then
  669.                         self.gameLoadedConn = game.Loaded:Connect(function()
  670.                                 self.hasGameLoaded = true
  671.                                 self.gameLoadedConn:Disconnect()
  672.                                 self.gameLoadedConn = nil
  673.                         end)
  674.                 end
  675.        
  676.                 self:OnPlayerCameraPropertyChange()
  677.        
  678.                 return self
  679.         end
  680.        
  681.         function BaseCamera:GetModuleName()
  682.                 return "BaseCamera"
  683.         end
  684.        
  685.         function BaseCamera:OnCharacterAdded(char)
  686.                 self.resetCameraAngle = self.resetCameraAngle or self:GetEnabled()
  687.                 self.humanoidRootPart = nil
  688.                 if UserInputService.TouchEnabled then
  689.                         self.PlayerGui = player:WaitForChild("PlayerGui")
  690.                         for _, child in ipairs(char:GetChildren()) do
  691.                                 if child:IsA("Tool") then
  692.                                         self.isAToolEquipped = true
  693.                                 end
  694.                         end
  695.                         char.ChildAdded:Connect(function(child)
  696.                                 if child:IsA("Tool") then
  697.                                         self.isAToolEquipped = true
  698.                                 end
  699.                         end)
  700.                         char.ChildRemoved:Connect(function(child)
  701.                                 if child:IsA("Tool") then
  702.                                         self.isAToolEquipped = false
  703.                                 end
  704.                         end)
  705.                 end
  706.         end
  707.        
  708.         function BaseCamera:GetHumanoidRootPart()
  709.                 if not self.humanoidRootPart then
  710.                         if player.Character then
  711.                                 local humanoid = player.Character:FindFirstChildOfClass("Humanoid")
  712.                                 if humanoid then
  713.                                         self.humanoidRootPart = humanoid.RootPart
  714.                                 end
  715.                         end
  716.                 end
  717.                 return self.humanoidRootPart
  718.         end
  719.        
  720.         function BaseCamera:GetBodyPartToFollow(humanoid, isDead)
  721.                 -- If the humanoid is dead, prefer the head part if one still exists as a sibling of the humanoid
  722.                 if humanoid:GetState() == Enum.HumanoidStateType.Dead then
  723.                         local character = humanoid.Parent
  724.                         if character and character:IsA("Model") then
  725.                                 return character:FindFirstChild("Head") or humanoid.RootPart
  726.                         end
  727.                 end
  728.        
  729.                 return humanoid.RootPart
  730.         end
  731.        
  732.         function BaseCamera:GetSubjectPosition()
  733.                 local result = self.lastSubjectPosition
  734.                 local camera = game.Workspace.CurrentCamera
  735.                 local cameraSubject = camera and camera.CameraSubject
  736.        
  737.                 if cameraSubject then
  738.                         if cameraSubject:IsA("Humanoid") then
  739.                                 local humanoid = cameraSubject
  740.                                 local humanoidIsDead = humanoid:GetState() == Enum.HumanoidStateType.Dead
  741.        
  742.                                 if VRService.VREnabled and humanoidIsDead and humanoid == self.lastSubject then
  743.                                         result = self.lastSubjectPosition
  744.                                 else
  745.                                         local bodyPartToFollow = humanoid.RootPart
  746.        
  747.                                         -- If the humanoid is dead, prefer their head part as a follow target, if it exists
  748.                                         if humanoidIsDead then
  749.                                                 if humanoid.Parent and humanoid.Parent:IsA("Model") then
  750.                                                         bodyPartToFollow = humanoid.Parent:FindFirstChild("Head") or bodyPartToFollow
  751.                                                 end
  752.                                         end
  753.        
  754.                                         if bodyPartToFollow and bodyPartToFollow:IsA("BasePart") then
  755.                                                 local heightOffset
  756.                                                 if humanoid.RigType == Enum.HumanoidRigType.R15 then
  757.                                                         if humanoid.AutomaticScalingEnabled then
  758.                                                                 heightOffset = R15_HEAD_OFFSET
  759.                                                                 if bodyPartToFollow == humanoid.RootPart then
  760.                                                                         local rootPartSizeOffset = (humanoid.RootPart.Size.Y/2) - (HUMANOID_ROOT_PART_SIZE.Y/2)
  761.                                                                         heightOffset = heightOffset + Vector3.new(0, rootPartSizeOffset, 0)
  762.                                                                 end
  763.                                                         else
  764.                                                                 heightOffset = R15_HEAD_OFFSET_NO_SCALING
  765.                                                         end
  766.                                                 else
  767.                                                         heightOffset = HEAD_OFFSET
  768.                                                 end
  769.        
  770.                                                 if humanoidIsDead then
  771.                                                         heightOffset = ZERO_VECTOR3
  772.                                                 end
  773.        
  774.                                                 result = bodyPartToFollow.CFrame.p + bodyPartToFollow.CFrame:vectorToWorldSpace(heightOffset + humanoid.CameraOffset)
  775.                                         end
  776.                                 end
  777.        
  778.                         elseif cameraSubject:IsA("VehicleSeat") then
  779.                                 local offset = SEAT_OFFSET
  780.                                 if VRService.VREnabled then
  781.                                         offset = VR_SEAT_OFFSET
  782.                                 end
  783.                                 result = cameraSubject.CFrame.p + cameraSubject.CFrame:vectorToWorldSpace(offset)
  784.                         elseif cameraSubject:IsA("SkateboardPlatform") then
  785.                                 result = cameraSubject.CFrame.p + SEAT_OFFSET
  786.                         elseif cameraSubject:IsA("BasePart") then
  787.                                 result = cameraSubject.CFrame.p
  788.                         elseif cameraSubject:IsA("Model") then
  789.                                 if cameraSubject.PrimaryPart then
  790.                                         result = cameraSubject:GetPrimaryPartCFrame().p
  791.                                 else
  792.                                         result = cameraSubject:GetModelCFrame().p
  793.                                 end
  794.                         end
  795.                 else
  796.                         -- cameraSubject is nil
  797.                         -- Note: Previous RootCamera did not have this else case and let self.lastSubject and self.lastSubjectPosition
  798.                         -- both get set to nil in the case of cameraSubject being nil. This function now exits here to preserve the
  799.                         -- last set valid values for these, as nil values are not handled cases
  800.                         return
  801.                 end
  802.        
  803.                 self.lastSubject = cameraSubject
  804.                 self.lastSubjectPosition = result
  805.        
  806.                 return result
  807.         end
  808.        
  809.         function BaseCamera:UpdateDefaultSubjectDistance()
  810.                 if self.portraitMode then
  811.                         self.defaultSubjectDistance = math.clamp(PORTRAIT_DEFAULT_DISTANCE, player.CameraMinZoomDistance, player.CameraMaxZoomDistance)
  812.                 else
  813.                         self.defaultSubjectDistance = math.clamp(DEFAULT_DISTANCE, player.CameraMinZoomDistance, player.CameraMaxZoomDistance)
  814.                 end
  815.         end
  816.        
  817.         function BaseCamera:OnViewportSizeChanged()
  818.                 local camera = game.Workspace.CurrentCamera
  819.                 local size = camera.ViewportSize
  820.                 self.portraitMode = size.X < size.Y
  821.                 self.isSmallTouchScreen = UserInputService.TouchEnabled and (size.Y < 500 or size.X < 700)
  822.        
  823.                 self:UpdateDefaultSubjectDistance()
  824.         end
  825.        
  826.         -- Listener for changes to workspace.CurrentCamera
  827.         function BaseCamera:OnCurrentCameraChanged()
  828.                 if UserInputService.TouchEnabled then
  829.                         if self.viewportSizeChangedConn then
  830.                                 self.viewportSizeChangedConn:Disconnect()
  831.                                 self.viewportSizeChangedConn = nil
  832.                         end
  833.        
  834.                         local newCamera = game.Workspace.CurrentCamera
  835.        
  836.                         if newCamera then
  837.                                 self:OnViewportSizeChanged()
  838.                                 self.viewportSizeChangedConn = newCamera:GetPropertyChangedSignal("ViewportSize"):Connect(function()
  839.                                         self:OnViewportSizeChanged()
  840.                                 end)
  841.                         end
  842.                 end
  843.        
  844.                 -- VR support additions
  845.                 if self.cameraSubjectChangedConn then
  846.                         self.cameraSubjectChangedConn:Disconnect()
  847.                         self.cameraSubjectChangedConn = nil
  848.                 end
  849.        
  850.                 local camera = game.Workspace.CurrentCamera
  851.                 if camera then
  852.                         self.cameraSubjectChangedConn = camera:GetPropertyChangedSignal("CameraSubject"):Connect(function()
  853.                                 self:OnNewCameraSubject()
  854.                         end)
  855.                         self:OnNewCameraSubject()
  856.                 end
  857.         end
  858.        
  859.         function BaseCamera:OnDynamicThumbstickEnabled()
  860.                 if UserInputService.TouchEnabled then
  861.                         self.isDynamicThumbstickEnabled = true
  862.                 end
  863.         end
  864.        
  865.         function BaseCamera:OnDynamicThumbstickDisabled()
  866.                 self.isDynamicThumbstickEnabled = false
  867.         end
  868.        
  869.         function BaseCamera:OnGameSettingsTouchMovementModeChanged()
  870.                 if player.DevTouchMovementMode == Enum.DevTouchMovementMode.UserChoice then
  871.                         if (UserGameSettings.TouchMovementMode == Enum.TouchMovementMode.DynamicThumbstick
  872.                                 or UserGameSettings.TouchMovementMode == Enum.TouchMovementMode.Default) then
  873.                                 self:OnDynamicThumbstickEnabled()
  874.                         else
  875.                                 self:OnDynamicThumbstickDisabled()
  876.                         end
  877.                 end
  878.         end
  879.        
  880.         function BaseCamera:OnDevTouchMovementModeChanged()
  881.                 if player.DevTouchMovementMode.Name == "DynamicThumbstick" then
  882.                         self:OnDynamicThumbstickEnabled()
  883.                 else
  884.                         self:OnGameSettingsTouchMovementModeChanged()
  885.                 end
  886.         end
  887.        
  888.         function BaseCamera:OnPlayerCameraPropertyChange()
  889.                 -- This call forces re-evaluation of player.CameraMode and clamping to min/max distance which may have changed
  890.                 self:SetCameraToSubjectDistance(self.currentSubjectDistance)
  891.         end
  892.        
  893.         function BaseCamera:GetCameraHeight()
  894.                 if VRService.VREnabled and not self.inFirstPerson then
  895.                         return math.sin(VR_ANGLE) * self.currentSubjectDistance
  896.                 end
  897.                 return 0
  898.         end
  899.        
  900.         function BaseCamera:InputTranslationToCameraAngleChange(translationVector, sensitivity)
  901.                 if not FFlagUserDontAdjustSensitvityForPortrait then
  902.                         local camera = game.Workspace.CurrentCamera
  903.                         if camera and camera.ViewportSize.X > 0 and camera.ViewportSize.Y > 0 and (camera.ViewportSize.Y > camera.ViewportSize.X) then
  904.                                 -- Screen has portrait orientation, swap X and Y sensitivity
  905.                                 return translationVector * Vector2.new( sensitivity.Y, sensitivity.X)
  906.                         end
  907.                 end
  908.                 return translationVector * sensitivity
  909.         end
  910.        
  911.         function BaseCamera:Enable(enable)
  912.                 if self.enabled ~= enable then
  913.                         self.enabled = enable
  914.                         if self.enabled then
  915.                                 self:ConnectInputEvents()
  916.                                 self:BindContextActions()
  917.        
  918.                                 if player.CameraMode == Enum.CameraMode.LockFirstPerson then
  919.                                         self.currentSubjectDistance = 0.5
  920.                                         if not self.inFirstPerson then
  921.                                                 self:EnterFirstPerson()
  922.                                         end
  923.                                 end
  924.                         else
  925.                                 self:DisconnectInputEvents()
  926.                                 self:UnbindContextActions()
  927.                                 -- Clean up additional event listeners and reset a bunch of properties
  928.                                 self:Cleanup()
  929.                         end
  930.                 end
  931.         end
  932.        
  933.         function BaseCamera:GetEnabled()
  934.                 return self.enabled
  935.         end
  936.        
  937.         function BaseCamera:OnInputBegan(input, processed)
  938.                 if input.UserInputType == Enum.UserInputType.Touch then
  939.                         self:OnTouchBegan(input, processed)
  940.                 elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
  941.                         self:OnMouse2Down(input, processed)
  942.                 elseif input.UserInputType == Enum.UserInputType.MouseButton3 then
  943.                         self:OnMouse3Down(input, processed)
  944.                 end
  945.         end
  946.        
  947.         function BaseCamera:OnInputChanged(input, processed)
  948.                 if input.UserInputType == Enum.UserInputType.Touch then
  949.                         self:OnTouchChanged(input, processed)
  950.                 elseif input.UserInputType == Enum.UserInputType.MouseMovement then
  951.                         self:OnMouseMoved(input, processed)
  952.                 end
  953.         end
  954.        
  955.         function BaseCamera:OnInputEnded(input, processed)
  956.                 if input.UserInputType == Enum.UserInputType.Touch then
  957.                         self:OnTouchEnded(input, processed)
  958.                 elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
  959.                         self:OnMouse2Up(input, processed)
  960.                 elseif input.UserInputType == Enum.UserInputType.MouseButton3 then
  961.                         self:OnMouse3Up(input, processed)
  962.                 end
  963.         end
  964.        
  965.         function BaseCamera:OnPointerAction(wheel, pan, pinch, processed)
  966.                 if processed then
  967.                         return
  968.                 end
  969.        
  970.                 if pan.Magnitude > 0 then
  971.                         local inversionVector = Vector2.new(1, UserGameSettings:GetCameraYInvertValue())
  972.                         local rotateDelta = self:InputTranslationToCameraAngleChange(PAN_SENSITIVITY*pan, MOUSE_SENSITIVITY)*inversionVector
  973.                         self.rotateInput = self.rotateInput + rotateDelta
  974.                 end
  975.        
  976.                 local zoom = self.currentSubjectDistance
  977.                 local zoomDelta = -(wheel + pinch)
  978.        
  979.                 if abs(zoomDelta) > 0 then
  980.                         local newZoom
  981.                         if self.inFirstPerson and zoomDelta > 0 then
  982.                                 newZoom = FIRST_PERSON_DISTANCE_THRESHOLD
  983.                         else
  984.                                 if FFlagUserFixZoomInZoomOutDiscrepancy then
  985.                                         if (zoomDelta > 0) then
  986.                                                 newZoom = zoom + zoomDelta*(1 + zoom*ZOOM_SENSITIVITY_CURVATURE)
  987.                                         else
  988.                                                 newZoom = (zoom + zoomDelta) / (1 - zoomDelta*ZOOM_SENSITIVITY_CURVATURE)
  989.                                         end
  990.                                 else
  991.                                         newZoom = zoom + zoomDelta*(1 + zoom*ZOOM_SENSITIVITY_CURVATURE)
  992.                                 end
  993.                         end
  994.        
  995.                         self:SetCameraToSubjectDistance(newZoom)
  996.                 end
  997.         end
  998.        
  999.         function BaseCamera:ConnectInputEvents()
  1000.                 self.pointerActionConn = UserInputService.PointerAction:Connect(function(wheel, pan, pinch, processed)
  1001.                         self:OnPointerAction(wheel, pan, pinch, processed)
  1002.                 end)
  1003.        
  1004.                 self.inputBeganConn = UserInputService.InputBegan:Connect(function(input, processed)
  1005.                         self:OnInputBegan(input, processed)
  1006.                 end)
  1007.        
  1008.                 self.inputChangedConn = UserInputService.InputChanged:Connect(function(input, processed)
  1009.                         self:OnInputChanged(input, processed)
  1010.                 end)
  1011.        
  1012.                 self.inputEndedConn = UserInputService.InputEnded:Connect(function(input, processed)
  1013.                         self:OnInputEnded(input, processed)
  1014.                 end)
  1015.        
  1016.                 self.menuOpenedConn = GuiService.MenuOpened:connect(function()
  1017.                         self:ResetInputStates()
  1018.                 end)
  1019.        
  1020.                 self.gamepadConnectedConn = UserInputService.GamepadDisconnected:connect(function(gamepadEnum)
  1021.                         if self.activeGamepad ~= gamepadEnum then return end
  1022.                         self.activeGamepad = nil
  1023.                         self:AssignActivateGamepad()
  1024.                 end)
  1025.        
  1026.                 self.gamepadDisconnectedConn = UserInputService.GamepadConnected:connect(function(gamepadEnum)
  1027.                         if self.activeGamepad == nil then
  1028.                                 self:AssignActivateGamepad()
  1029.                         end
  1030.                 end)
  1031.        
  1032.                 self:AssignActivateGamepad()
  1033.                 if not FFlagUserCameraToggle then
  1034.                         self:UpdateMouseBehavior()
  1035.                 end
  1036.         end
  1037.        
  1038.         function BaseCamera:BindContextActions()
  1039.                 self:BindGamepadInputActions()
  1040.                 self:BindKeyboardInputActions()
  1041.         end
  1042.        
  1043.         function BaseCamera:AssignActivateGamepad()
  1044.                 local connectedGamepads = UserInputService:GetConnectedGamepads()
  1045.                 if #connectedGamepads > 0 then
  1046.                         for i = 1, #connectedGamepads do
  1047.                                 if self.activeGamepad == nil then
  1048.                                         self.activeGamepad = connectedGamepads[i]
  1049.                                 elseif connectedGamepads[i].Value < self.activeGamepad.Value then
  1050.                                         self.activeGamepad = connectedGamepads[i]
  1051.                                 end
  1052.                         end
  1053.                 end
  1054.        
  1055.                 if self.activeGamepad == nil then -- nothing is connected, at least set up for gamepad1
  1056.                         self.activeGamepad = Enum.UserInputType.Gamepad1
  1057.                 end
  1058.         end
  1059.        
  1060.         function BaseCamera:DisconnectInputEvents()
  1061.                 if self.inputBeganConn then
  1062.                         self.inputBeganConn:Disconnect()
  1063.                         self.inputBeganConn = nil
  1064.                 end
  1065.                 if self.inputChangedConn then
  1066.                         self.inputChangedConn:Disconnect()
  1067.                         self.inputChangedConn = nil
  1068.                 end
  1069.                 if self.inputEndedConn then
  1070.                         self.inputEndedConn:Disconnect()
  1071.                         self.inputEndedConn = nil
  1072.                 end
  1073.         end
  1074.        
  1075.         function BaseCamera:UnbindContextActions()
  1076.                 for i = 1, #self.boundContextActions do
  1077.                         ContextActionService:UnbindAction(self.boundContextActions[i])
  1078.                 end
  1079.                 self.boundContextActions = {}
  1080.         end
  1081.        
  1082.         function BaseCamera:Cleanup()
  1083.                 if self.pointerActionConn then
  1084.                         self.pointerActionConn:Disconnect()
  1085.                         self.pointerActionConn = nil
  1086.                 end
  1087.                 if self.menuOpenedConn then
  1088.                         self.menuOpenedConn:Disconnect()
  1089.                         self.menuOpenedConn = nil
  1090.                 end
  1091.                 if self.mouseLockToggleConn then
  1092.                         self.mouseLockToggleConn:Disconnect()
  1093.                         self.mouseLockToggleConn = nil
  1094.                 end
  1095.                 if self.gamepadConnectedConn then
  1096.                         self.gamepadConnectedConn:Disconnect()
  1097.                         self.gamepadConnectedConn = nil
  1098.                 end
  1099.                 if self.gamepadDisconnectedConn then
  1100.                         self.gamepadDisconnectedConn:Disconnect()
  1101.                         self.gamepadDisconnectedConn = nil
  1102.                 end
  1103.                 if self.subjectStateChangedConn then
  1104.                         self.subjectStateChangedConn:Disconnect()
  1105.                         self.subjectStateChangedConn = nil
  1106.                 end
  1107.                 if self.viewportSizeChangedConn then
  1108.                         self.viewportSizeChangedConn:Disconnect()
  1109.                         self.viewportSizeChangedConn = nil
  1110.                 end
  1111.                 if self.touchActivateConn then
  1112.                         self.touchActivateConn:Disconnect()
  1113.                         self.touchActivateConn = nil
  1114.                 end
  1115.        
  1116.                 self.turningLeft = false
  1117.                 self.turningRight = false
  1118.                 self.lastCameraTransform = nil
  1119.                 self.lastSubjectCFrame = nil
  1120.                 self.userPanningTheCamera = false
  1121.                 self.rotateInput = Vector2.new()
  1122.                 self.gamepadPanningCamera = Vector2.new(0,0)
  1123.        
  1124.                 -- Reset input states
  1125.                 self.startPos = nil
  1126.                 self.lastPos = nil
  1127.                 self.panBeginLook = nil
  1128.                 self.isRightMouseDown = false
  1129.                 self.isMiddleMouseDown = false
  1130.        
  1131.                 self.fingerTouches = {}
  1132.                 self.dynamicTouchInput = nil
  1133.                 self.numUnsunkTouches = 0
  1134.        
  1135.                 self.startingDiff = nil
  1136.                 self.pinchBeginZoom = nil
  1137.        
  1138.                 -- Unlock mouse for example if right mouse button was being held down
  1139.                 if UserInputService.MouseBehavior ~= Enum.MouseBehavior.LockCenter then
  1140.                         UserInputService.MouseBehavior = Enum.MouseBehavior.Default
  1141.                 end
  1142.         end
  1143.        
  1144.         -- This is called when settings menu is opened
  1145.         function BaseCamera:ResetInputStates()
  1146.                 self.isRightMouseDown = false
  1147.                 self.isMiddleMouseDown = false
  1148.                 self:OnMousePanButtonReleased() -- this function doesn't seem to actually need parameters
  1149.        
  1150.                 if UserInputService.TouchEnabled then
  1151.                         --[[menu opening was causing serious touch issues
  1152.                         this should disable all active touch events if
  1153.                         they're active when menu opens.]]
  1154.                         for inputObject in pairs(self.fingerTouches) do
  1155.                                 self.fingerTouches[inputObject] = nil
  1156.                         end
  1157.                         self.dynamicTouchInput = nil
  1158.                         self.panBeginLook = nil
  1159.                         self.startPos = nil
  1160.                         self.lastPos = nil
  1161.                         self.userPanningTheCamera = false
  1162.                         self.startingDiff = nil
  1163.                         self.pinchBeginZoom = nil
  1164.                         self.numUnsunkTouches = 0
  1165.                 end
  1166.         end
  1167.        
  1168.         function BaseCamera:GetGamepadPan(name, state, input)
  1169.                 if input.UserInputType == self.activeGamepad and input.KeyCode == Enum.KeyCode.Thumbstick2 then
  1170.         --              if self.L3ButtonDown then
  1171.         --                      -- L3 Thumbstick is depressed, right stick controls dolly in/out
  1172.         --                      if (input.Position.Y > THUMBSTICK_DEADZONE) then
  1173.         --                              self.currentZoomSpeed = 0.96
  1174.         --                      elseif (input.Position.Y < -THUMBSTICK_DEADZONE) then
  1175.         --                              self.currentZoomSpeed = 1.04
  1176.         --                      else
  1177.         --                              self.currentZoomSpeed = 1.00
  1178.         --                      end
  1179.         --              else
  1180.                                 if state == Enum.UserInputState.Cancel then
  1181.                                         self.gamepadPanningCamera = ZERO_VECTOR2
  1182.                                         return
  1183.                                 end
  1184.        
  1185.                                 local inputVector = Vector2.new(input.Position.X, -input.Position.Y)
  1186.                                 if inputVector.magnitude > THUMBSTICK_DEADZONE then
  1187.                                         self.gamepadPanningCamera = Vector2.new(input.Position.X, -input.Position.Y)
  1188.                                 else
  1189.                                         self.gamepadPanningCamera = ZERO_VECTOR2
  1190.                                 end
  1191.                         --end
  1192.                         return Enum.ContextActionResult.Sink
  1193.                 end
  1194.                 return Enum.ContextActionResult.Pass
  1195.         end
  1196.        
  1197.         function BaseCamera:DoKeyboardPanTurn(name, state, input)
  1198.                 if not self.hasGameLoaded and VRService.VREnabled then
  1199.                         return Enum.ContextActionResult.Pass
  1200.                 end
  1201.        
  1202.                 if state == Enum.UserInputState.Cancel then
  1203.                         self.turningLeft = false
  1204.                         self.turningRight = false
  1205.                         return Enum.ContextActionResult.Sink
  1206.                 end
  1207.        
  1208.                 if self.panBeginLook == nil and self.keyPanEnabled then
  1209.                         if input.KeyCode == Enum.KeyCode.Left then
  1210.                                 self.turningLeft = state == Enum.UserInputState.Begin
  1211.                         elseif input.KeyCode == Enum.KeyCode.Right then
  1212.                                 self.turningRight = state == Enum.UserInputState.Begin
  1213.                         end
  1214.                         return Enum.ContextActionResult.Sink
  1215.                 end
  1216.                 return Enum.ContextActionResult.Pass
  1217.         end
  1218.        
  1219.         function BaseCamera:DoPanRotateCamera(rotateAngle)
  1220.                 local angle = Util.RotateVectorByAngleAndRound(self:GetCameraLookVector() * Vector3.new(1,0,1), rotateAngle, math.pi*0.25)
  1221.                 if angle ~= 0 then
  1222.                         self.rotateInput = self.rotateInput + Vector2.new(angle, 0)
  1223.                         self.lastUserPanCamera = tick()
  1224.                         self.lastCameraTransform = nil
  1225.                 end
  1226.         end
  1227.        
  1228.         function BaseCamera:DoGamepadZoom(name, state, input)
  1229.                 if input.UserInputType == self.activeGamepad then
  1230.                         if input.KeyCode == Enum.KeyCode.ButtonR3 then
  1231.                                 if state == Enum.UserInputState.Begin then
  1232.                                         if self.distanceChangeEnabled then
  1233.                                                 local dist = self:GetCameraToSubjectDistance()
  1234.        
  1235.                                                 if dist > (GAMEPAD_ZOOM_STEP_2 + GAMEPAD_ZOOM_STEP_3)/2 then
  1236.                                                         self:SetCameraToSubjectDistance(GAMEPAD_ZOOM_STEP_2)
  1237.                                                 elseif dist > (GAMEPAD_ZOOM_STEP_1 + GAMEPAD_ZOOM_STEP_2)/2 then
  1238.                                                         self:SetCameraToSubjectDistance(GAMEPAD_ZOOM_STEP_1)
  1239.                                                 else
  1240.                                                         self:SetCameraToSubjectDistance(GAMEPAD_ZOOM_STEP_3)
  1241.                                                 end
  1242.                                         end
  1243.                                 end
  1244.                         elseif input.KeyCode == Enum.KeyCode.DPadLeft then
  1245.                                 self.dpadLeftDown = (state == Enum.UserInputState.Begin)
  1246.                         elseif input.KeyCode == Enum.KeyCode.DPadRight then
  1247.                                 self.dpadRightDown = (state == Enum.UserInputState.Begin)
  1248.                         end
  1249.        
  1250.                         if self.dpadLeftDown then
  1251.                                 self.currentZoomSpeed = 1.04
  1252.                         elseif self.dpadRightDown then
  1253.                                 self.currentZoomSpeed = 0.96
  1254.                         else
  1255.                                 self.currentZoomSpeed = 1.00
  1256.                         end
  1257.                         return Enum.ContextActionResult.Sink
  1258.                 end
  1259.                 return Enum.ContextActionResult.Pass
  1260.         --      elseif input.UserInputType == self.activeGamepad and input.KeyCode == Enum.KeyCode.ButtonL3 then
  1261.         --              if (state == Enum.UserInputState.Begin) then
  1262.         --                      self.L3ButtonDown = true
  1263.         --              elseif (state == Enum.UserInputState.End) then
  1264.         --                      self.L3ButtonDown = false
  1265.         --                      self.currentZoomSpeed = 1.00
  1266.         --              end
  1267.         --      end
  1268.         end
  1269.        
  1270.         function BaseCamera:DoKeyboardZoom(name, state, input)
  1271.                 if not self.hasGameLoaded and VRService.VREnabled then
  1272.                         return Enum.ContextActionResult.Pass
  1273.                 end
  1274.        
  1275.                 if state ~= Enum.UserInputState.Begin then
  1276.                         return Enum.ContextActionResult.Pass
  1277.                 end
  1278.        
  1279.                 if self.distanceChangeEnabled and player.CameraMode ~= Enum.CameraMode.LockFirstPerson then
  1280.                         if input.KeyCode == Enum.KeyCode.I then
  1281.                                 self:SetCameraToSubjectDistance( self.currentSubjectDistance - 5 )
  1282.                         elseif input.KeyCode == Enum.KeyCode.O then
  1283.                                 self:SetCameraToSubjectDistance( self.currentSubjectDistance + 5 )
  1284.                         end
  1285.                         return Enum.ContextActionResult.Sink
  1286.                 end
  1287.                 return Enum.ContextActionResult.Pass
  1288.         end
  1289.        
  1290.         function BaseCamera:BindAction(actionName, actionFunc, createTouchButton, ...)
  1291.                 table.insert(self.boundContextActions, actionName)
  1292.                 ContextActionService:BindActionAtPriority(actionName, actionFunc, createTouchButton,
  1293.                         CAMERA_ACTION_PRIORITY, ...)
  1294.         end
  1295.        
  1296.         function BaseCamera:BindGamepadInputActions()
  1297.                 self:BindAction("BaseCameraGamepadPan", function(name, state, input) return self:GetGamepadPan(name, state, input) end,
  1298.                         false, Enum.KeyCode.Thumbstick2)
  1299.                 self:BindAction("BaseCameraGamepadZoom", function(name, state, input) return self:DoGamepadZoom(name, state, input) end,
  1300.                         false, Enum.KeyCode.DPadLeft, Enum.KeyCode.DPadRight, Enum.KeyCode.ButtonR3)
  1301.         end
  1302.        
  1303.         function BaseCamera:BindKeyboardInputActions()
  1304.                 self:BindAction("BaseCameraKeyboardPanArrowKeys", function(name, state, input) return self:DoKeyboardPanTurn(name, state, input) end,
  1305.                         false, Enum.KeyCode.Left, Enum.KeyCode.Right)
  1306.                 self:BindAction("BaseCameraKeyboardZoom", function(name, state, input) return self:DoKeyboardZoom(name, state, input) end,
  1307.                         false, Enum.KeyCode.I, Enum.KeyCode.O)
  1308.         end
  1309.        
  1310.         local function isInDynamicThumbstickArea(input)
  1311.                 local playerGui = player:FindFirstChildOfClass("PlayerGui")
  1312.                 local touchGui = playerGui and playerGui:FindFirstChild("TouchGui")
  1313.                 local touchFrame = touchGui and touchGui:FindFirstChild("TouchControlFrame")
  1314.                 local thumbstickFrame = touchFrame and touchFrame:FindFirstChild("DynamicThumbstickFrame")
  1315.        
  1316.                 if not thumbstickFrame then
  1317.                         return false
  1318.                 end
  1319.        
  1320.                 local frameCornerTopLeft = thumbstickFrame.AbsolutePosition
  1321.                 local frameCornerBottomRight = frameCornerTopLeft + thumbstickFrame.AbsoluteSize
  1322.                 if input.Position.X >= frameCornerTopLeft.X and input.Position.Y >= frameCornerTopLeft.Y then
  1323.                         if input.Position.X  0 then
  1324.                         local fractionAdjust = (currPitchAngle - TOUCH_ADJUST_AREA_DOWN)/(MIN_Y - TOUCH_ADJUST_AREA_DOWN)
  1325.                         fractionAdjust = 1 - (1 - fractionAdjust)^3
  1326.                         multiplierY = TOUCH_SENSITIVTY_ADJUST_MAX_Y - fractionAdjust * (
  1327.                                 TOUCH_SENSITIVTY_ADJUST_MAX_Y - TOUCH_SENSITIVTY_ADJUST_MIN_Y)
  1328.                 end
  1329.        
  1330.                 return Vector2.new(
  1331.                         sensitivity.X,
  1332.                         sensitivity.Y * multiplierY
  1333.                 )
  1334.         end
  1335.        
  1336.         function BaseCamera:OnTouchBegan(input, processed)
  1337.                 local canUseDynamicTouch = self.isDynamicThumbstickEnabled and not processed
  1338.                 if canUseDynamicTouch then
  1339.                         if self.dynamicTouchInput == nil and isInDynamicThumbstickArea(input) then
  1340.                                 -- First input in the dynamic thumbstick area should always be ignored for camera purposes
  1341.                                 -- Even if the dynamic thumbstick does not process it immediately
  1342.                                 self.dynamicTouchInput = input
  1343.                                 return
  1344.                         end
  1345.                         self.fingerTouches[input] = processed
  1346.                         self.inputStartPositions[input] = input.Position
  1347.                         self.inputStartTimes[input] = tick()
  1348.                         self.numUnsunkTouches = self.numUnsunkTouches + 1
  1349.                 end
  1350.         end
  1351.        
  1352.         function BaseCamera:OnTouchChanged(input, processed)
  1353.                 if self.fingerTouches[input] == nil then
  1354.                         if self.isDynamicThumbstickEnabled then
  1355.                                 return
  1356.                         end
  1357.                         self.fingerTouches[input] = processed
  1358.                         if not processed then
  1359.                                 self.numUnsunkTouches = self.numUnsunkTouches + 1
  1360.                         end
  1361.                 end
  1362.        
  1363.                 if self.numUnsunkTouches == 1 then
  1364.                         if self.fingerTouches[input] == false then
  1365.                                 self.panBeginLook = self.panBeginLook or self:GetCameraLookVector()
  1366.                                 self.startPos = self.startPos or input.Position
  1367.                                 self.lastPos = self.lastPos or self.startPos
  1368.                                 self.userPanningTheCamera = true
  1369.        
  1370.                                 local delta = input.Position - self.lastPos
  1371.                                 delta = Vector2.new(delta.X, delta.Y * UserGameSettings:GetCameraYInvertValue())
  1372.                                 if self.panEnabled then
  1373.                                         local adjustedTouchSensitivity = TOUCH_SENSITIVTY
  1374.                                         self:AdjustTouchSensitivity(delta, TOUCH_SENSITIVTY)
  1375.        
  1376.                                         local desiredXYVector = self:InputTranslationToCameraAngleChange(delta, adjustedTouchSensitivity)
  1377.                                         self.rotateInput = self.rotateInput + desiredXYVector
  1378.                                 end
  1379.                                 self.lastPos = input.Position
  1380.                         end
  1381.                 else
  1382.                         self.panBeginLook = nil
  1383.                         self.startPos = nil
  1384.                         self.lastPos = nil
  1385.                         self.userPanningTheCamera = false
  1386.                 end
  1387.                 if self.numUnsunkTouches == 2 then
  1388.                         local unsunkTouches = {}
  1389.                         for touch, wasSunk in pairs(self.fingerTouches) do
  1390.                                 if not wasSunk then
  1391.                                         table.insert(unsunkTouches, touch)
  1392.                                 end
  1393.                         end
  1394.                         if #unsunkTouches == 2 then
  1395.                                 local difference = (unsunkTouches[1].Position - unsunkTouches[2].Position).magnitude
  1396.                                 if self.startingDiff and self.pinchBeginZoom then
  1397.                                         local scale = difference / math.max(0.01, self.startingDiff)
  1398.                                         local clampedScale = math.clamp(scale, 0.1, 10)
  1399.                                         if self.distanceChangeEnabled then
  1400.                                                 self:SetCameraToSubjectDistance(self.pinchBeginZoom / clampedScale)
  1401.                                         end
  1402.                                 else
  1403.                                         self.startingDiff = difference
  1404.                                         self.pinchBeginZoom = self:GetCameraToSubjectDistance()
  1405.                                 end
  1406.                         end
  1407.                 else
  1408.                         self.startingDiff = nil
  1409.                         self.pinchBeginZoom = nil
  1410.                 end
  1411.         end
  1412.        
  1413.         function BaseCamera:OnTouchEnded(input, processed)
  1414.                 if input == self.dynamicTouchInput then
  1415.                         self.dynamicTouchInput = nil
  1416.                         return
  1417.                 end
  1418.        
  1419.                 if self.fingerTouches[input] == false then
  1420.                         if self.numUnsunkTouches == 1 then
  1421.                                 self.panBeginLook = nil
  1422.                                 self.startPos = nil
  1423.                                 self.lastPos = nil
  1424.                                 self.userPanningTheCamera = false
  1425.                         elseif self.numUnsunkTouches == 2 then
  1426.                                 self.startingDiff = nil
  1427.                                 self.pinchBeginZoom = nil
  1428.                         end
  1429.                 end
  1430.        
  1431.                 if self.fingerTouches[input] ~= nil and self.fingerTouches[input] == false then
  1432.                         self.numUnsunkTouches = self.numUnsunkTouches - 1
  1433.                 end
  1434.                 self.fingerTouches[input] = nil
  1435.                 self.inputStartPositions[input] = nil
  1436.                 self.inputStartTimes[input] = nil
  1437.         end
  1438.        
  1439.         function BaseCamera:OnMouse2Down(input, processed)
  1440.                 if processed then return end
  1441.        
  1442.                 self.isRightMouseDown = true
  1443.                 self:OnMousePanButtonPressed(input, processed)
  1444.         end
  1445.        
  1446.         function BaseCamera:OnMouse2Up(input, processed)
  1447.                 self.isRightMouseDown = false
  1448.                 self:OnMousePanButtonReleased(input, processed)
  1449.         end
  1450.        
  1451.         function BaseCamera:OnMouse3Down(input, processed)
  1452.                 if processed then return end
  1453.        
  1454.                 self.isMiddleMouseDown = true
  1455.                 self:OnMousePanButtonPressed(input, processed)
  1456.         end
  1457.        
  1458.         function BaseCamera:OnMouse3Up(input, processed)
  1459.                 self.isMiddleMouseDown = false
  1460.                 self:OnMousePanButtonReleased(input, processed)
  1461.         end
  1462.        
  1463.         function BaseCamera:OnMouseMoved(input, processed)
  1464.                 if not self.hasGameLoaded and VRService.VREnabled then
  1465.                         return
  1466.                 end
  1467.        
  1468.                 local inputDelta = input.Delta
  1469.                 inputDelta = Vector2.new(inputDelta.X, inputDelta.Y * UserGameSettings:GetCameraYInvertValue())
  1470.        
  1471.                 local isInputPanning = FFlagUserCameraToggle and CameraInput.getPanning()
  1472.                 local isBeginLook = self.startPos and self.lastPos and self.panBeginLook
  1473.                 local isPanning = isBeginLook or self.inFirstPerson or self.inMouseLockedMode or isInputPanning
  1474.        
  1475.                 if self.panEnabled and isPanning then
  1476.                         local desiredXYVector = self:InputTranslationToCameraAngleChange(inputDelta, MOUSE_SENSITIVITY)
  1477.                         self.rotateInput = self.rotateInput + desiredXYVector
  1478.                 end
  1479.        
  1480.                 if self.startPos and self.lastPos and self.panBeginLook then
  1481.                         self.lastPos = self.lastPos + input.Delta
  1482.                 end
  1483.         end
  1484.        
  1485.         function BaseCamera:OnMousePanButtonPressed(input, processed)
  1486.                 if processed then return end
  1487.                 if not FFlagUserCameraToggle then
  1488.                         self:UpdateMouseBehavior()
  1489.                 end
  1490.                 self.panBeginLook = self.panBeginLook or self:GetCameraLookVector()
  1491.                 self.startPos = self.startPos or input.Position
  1492.                 self.lastPos = self.lastPos or self.startPos
  1493.                 self.userPanningTheCamera = true
  1494.         end
  1495.        
  1496.         function BaseCamera:OnMousePanButtonReleased(input, processed)
  1497.                 if not FFlagUserCameraToggle then
  1498.                         self:UpdateMouseBehavior()
  1499.                 end
  1500.                 if not (self.isRightMouseDown or self.isMiddleMouseDown) then
  1501.                         self.panBeginLook = nil
  1502.                         self.startPos = nil
  1503.                         self.lastPos = nil
  1504.                         self.userPanningTheCamera = false
  1505.                 end
  1506.         end
  1507.        
  1508.         function BaseCamera:UpdateMouseBehavior()
  1509.                 if FFlagUserCameraToggle and self.isCameraToggle then
  1510.                         CameraUI.setCameraModeToastEnabled(true)
  1511.                         CameraInput.enableCameraToggleInput()
  1512.                         CameraToggleStateController(self.inFirstPerson)
  1513.                 else
  1514.                         if FFlagUserCameraToggle then
  1515.                                 CameraUI.setCameraModeToastEnabled(false)
  1516.                                 CameraInput.disableCameraToggleInput()
  1517.                         end
  1518.                         -- first time transition to first person mode or mouse-locked third person
  1519.                         if self.inFirstPerson or self.inMouseLockedMode then
  1520.                                 --UserGameSettings.RotationType = Enum.RotationType.CameraRelative
  1521.                                 UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
  1522.                         else
  1523.                                 UserGameSettings.RotationType = Enum.RotationType.MovementRelative
  1524.                                 if self.isRightMouseDown or self.isMiddleMouseDown then
  1525.                                         UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
  1526.                                 else
  1527.                                         UserInputService.MouseBehavior = Enum.MouseBehavior.Default
  1528.                                 end
  1529.                         end
  1530.                 end
  1531.         end
  1532.        
  1533.         function BaseCamera:UpdateForDistancePropertyChange()
  1534.                 -- Calling this setter with the current value will force checking that it is still
  1535.                 -- in range after a change to the min/max distance limits
  1536.                 self:SetCameraToSubjectDistance(self.currentSubjectDistance)
  1537.         end
  1538.        
  1539.         function BaseCamera:SetCameraToSubjectDistance(desiredSubjectDistance)
  1540.                 local lastSubjectDistance = self.currentSubjectDistance
  1541.        
  1542.                 -- By default, camera modules will respect LockFirstPerson and override the currentSubjectDistance with 0
  1543.                 -- regardless of what Player.CameraMinZoomDistance is set to, so that first person can be made
  1544.                 -- available by the developer without needing to allow players to mousewheel dolly into first person.
  1545.                 -- Some modules will override this function to remove or change first-person capability.
  1546.                 if player.CameraMode == Enum.CameraMode.LockFirstPerson then
  1547.                         self.currentSubjectDistance = 0.5
  1548.                         if not self.inFirstPerson then
  1549.                                 self:EnterFirstPerson()
  1550.                         end
  1551.                 else
  1552.                         local newSubjectDistance = math.clamp(desiredSubjectDistance, player.CameraMinZoomDistance, player.CameraMaxZoomDistance)
  1553.                         if newSubjectDistance < FIRST_PERSON_DISTANCE_THRESHOLD then
  1554.                                 self.currentSubjectDistance = 0.5
  1555.                                 if not self.inFirstPerson then
  1556.                                         self:EnterFirstPerson()
  1557.                                 end
  1558.                         else
  1559.                                 self.currentSubjectDistance = newSubjectDistance
  1560.                                 if self.inFirstPerson then
  1561.                                         self:LeaveFirstPerson()
  1562.                                 end
  1563.                         end
  1564.                 end
  1565.        
  1566.                 -- Pass target distance and zoom direction to the zoom controller
  1567.                 ZoomController.SetZoomParameters(self.currentSubjectDistance, math.sign(desiredSubjectDistance - lastSubjectDistance))
  1568.        
  1569.                 -- Returned only for convenience to the caller to know the outcome
  1570.                 return self.currentSubjectDistance
  1571.         end
  1572.        
  1573.         function BaseCamera:SetCameraType( cameraType )
  1574.                 --Used by derived classes
  1575.                 self.cameraType = cameraType
  1576.         end
  1577.        
  1578.         function BaseCamera:GetCameraType()
  1579.                 return self.cameraType
  1580.         end
  1581.        
  1582.         -- Movement mode standardized to Enum.ComputerCameraMovementMode values
  1583.         function BaseCamera:SetCameraMovementMode( cameraMovementMode )
  1584.                 self.cameraMovementMode = cameraMovementMode
  1585.         end
  1586.        
  1587.         function BaseCamera:GetCameraMovementMode()
  1588.                 return self.cameraMovementMode
  1589.         end
  1590.        
  1591.         function BaseCamera:SetIsMouseLocked(mouseLocked)
  1592.                 self.inMouseLockedMode = mouseLocked
  1593.                 if not FFlagUserCameraToggle then
  1594.                         self:UpdateMouseBehavior()
  1595.                 end
  1596.         end
  1597.        
  1598.         function BaseCamera:GetIsMouseLocked()
  1599.                 return self.inMouseLockedMode
  1600.         end
  1601.        
  1602.         function BaseCamera:SetMouseLockOffset(offsetVector)
  1603.                 self.mouseLockOffset = offsetVector
  1604.         end
  1605.        
  1606.         function BaseCamera:GetMouseLockOffset()
  1607.                 return self.mouseLockOffset
  1608.         end
  1609.        
  1610.         function BaseCamera:InFirstPerson()
  1611.                 return self.inFirstPerson
  1612.         end
  1613.        
  1614.         function BaseCamera:EnterFirstPerson()
  1615.                 -- Overridden in ClassicCamera, the only module which supports FirstPerson
  1616.         end
  1617.        
  1618.         function BaseCamera:LeaveFirstPerson()
  1619.                 -- Overridden in ClassicCamera, the only module which supports FirstPerson
  1620.         end
  1621.        
  1622.         -- Nominal distance, set by dollying in and out with the mouse wheel or equivalent, not measured distance
  1623.         function BaseCamera:GetCameraToSubjectDistance()
  1624.                 return self.currentSubjectDistance
  1625.         end
  1626.        
  1627.         -- Actual measured distance to the camera Focus point, which may be needed in special circumstances, but should
  1628.         -- never be used as the starting point for updating the nominal camera-to-subject distance (self.currentSubjectDistance)
  1629.         -- since that is a desired target value set only by mouse wheel (or equivalent) input, PopperCam, and clamped to min max camera distance
  1630.         function BaseCamera:GetMeasuredDistanceToFocus()
  1631.                 local camera = game.Workspace.CurrentCamera
  1632.                 if camera then
  1633.                         return (camera.CoordinateFrame.p - camera.Focus.p).magnitude
  1634.                 end
  1635.                 return nil
  1636.         end
  1637.        
  1638.         function BaseCamera:GetCameraLookVector()
  1639.                 return game.Workspace.CurrentCamera and game.Workspace.CurrentCamera.CFrame.lookVector or UNIT_Z
  1640.         end
  1641.        
  1642.         -- Replacements for RootCamera:RotateCamera() which did not actually rotate the camera
  1643.         -- suppliedLookVector is not normally passed in, it's used only by Watch camera
  1644.         function BaseCamera:CalculateNewLookCFrame(suppliedLookVector)
  1645.                 local currLookVector = suppliedLookVector or self:GetCameraLookVector()
  1646.                 local currPitchAngle = math.asin(currLookVector.y)
  1647.                 local yTheta = math.clamp(self.rotateInput.y, -MAX_Y + currPitchAngle, -MIN_Y + currPitchAngle)
  1648.                 local constrainedRotateInput = Vector2.new(self.rotateInput.x, yTheta)
  1649.                 local startCFrame = CFrame.new(ZERO_VECTOR3, currLookVector)
  1650.                 local newLookCFrame = CFrame.Angles(0, -constrainedRotateInput.x, 0) * startCFrame * CFrame.Angles(-constrainedRotateInput.y,0,0)
  1651.                 return newLookCFrame
  1652.         end
  1653.         function BaseCamera:CalculateNewLookVector(suppliedLookVector)
  1654.                 local newLookCFrame = self:CalculateNewLookCFrame(suppliedLookVector)
  1655.                 return newLookCFrame.lookVector
  1656.         end
  1657.        
  1658.         function BaseCamera:CalculateNewLookVectorVR()
  1659.                 local subjectPosition = self:GetSubjectPosition()
  1660.                 local vecToSubject = (subjectPosition - game.Workspace.CurrentCamera.CFrame.p)
  1661.                 local currLookVector = (vecToSubject * X1_Y0_Z1).unit
  1662.                 local vrRotateInput = Vector2.new(self.rotateInput.x, 0)
  1663.                 local startCFrame = CFrame.new(ZERO_VECTOR3, currLookVector)
  1664.                 local yawRotatedVector = (CFrame.Angles(0, -vrRotateInput.x, 0) * startCFrame * CFrame.Angles(-vrRotateInput.y,0,0)).lookVector
  1665.                 return (yawRotatedVector * X1_Y0_Z1).unit
  1666.         end
  1667.        
  1668.         function BaseCamera:GetHumanoid()
  1669.                 local character = player and player.Character
  1670.                 if character then
  1671.                         local resultHumanoid = self.humanoidCache[player]
  1672.                         if resultHumanoid and resultHumanoid.Parent == character then
  1673.                                 return resultHumanoid
  1674.                         else
  1675.                                 self.humanoidCache[player] = nil -- Bust Old Cache
  1676.                                 local humanoid = character:FindFirstChildOfClass("Humanoid")
  1677.                                 if humanoid then
  1678.                                         self.humanoidCache[player] = humanoid
  1679.                                 end
  1680.                                 return humanoid
  1681.                         end
  1682.                 end
  1683.                 return nil
  1684.         end
  1685.        
  1686.         function BaseCamera:GetHumanoidPartToFollow(humanoid, humanoidStateType)
  1687.                 if humanoidStateType == Enum.HumanoidStateType.Dead then
  1688.                         local character = humanoid.Parent
  1689.                         if character then
  1690.                                 return character:FindFirstChild("Head") or humanoid.Torso
  1691.                         else
  1692.                                 return humanoid.Torso
  1693.                         end
  1694.                 else
  1695.                         return humanoid.Torso
  1696.                 end
  1697.         end
  1698.        
  1699.         function BaseCamera:UpdateGamepad()
  1700.                 local gamepadPan = self.gamepadPanningCamera
  1701.                 if gamepadPan and (self.hasGameLoaded or not VRService.VREnabled) then
  1702.                         gamepadPan = Util.GamepadLinearToCurve(gamepadPan)
  1703.                         local currentTime = tick()
  1704.                         if gamepadPan.X ~= 0 or gamepadPan.Y ~= 0 then
  1705.                                 self.userPanningTheCamera = true
  1706.                         elseif gamepadPan == ZERO_VECTOR2 then
  1707.                                 self.lastThumbstickRotate = nil
  1708.                                 if self.lastThumbstickPos == ZERO_VECTOR2 then
  1709.                                         self.currentSpeed = 0
  1710.                                 end
  1711.                         end
  1712.        
  1713.                         local finalConstant = 0
  1714.        
  1715.                         if self.lastThumbstickRotate then
  1716.                                 if VRService.VREnabled then
  1717.                                         self.currentSpeed = self.vrMaxSpeed
  1718.                                 else
  1719.                                         local elapsedTime = (currentTime - self.lastThumbstickRotate) * 10
  1720.                                         self.currentSpeed = self.currentSpeed + (self.maxSpeed * ((elapsedTime*elapsedTime)/self.numOfSeconds))
  1721.        
  1722.                                         if self.currentSpeed > self.maxSpeed then self.currentSpeed = self.maxSpeed end
  1723.        
  1724.                                         if self.lastVelocity then
  1725.                                                 local velocity = (gamepadPan - self.lastThumbstickPos)/(currentTime - self.lastThumbstickRotate)
  1726.                                                 local velocityDeltaMag = (velocity - self.lastVelocity).magnitude
  1727.        
  1728.                                                 if velocityDeltaMag > 12 then
  1729.                                                         self.currentSpeed = self.currentSpeed * (20/velocityDeltaMag)
  1730.                                                         if self.currentSpeed > self.maxSpeed then self.currentSpeed = self.maxSpeed end
  1731.                                                 end
  1732.                                         end
  1733.                                 end
  1734.        
  1735.                                 finalConstant = UserGameSettings.GamepadCameraSensitivity * self.currentSpeed
  1736.                                 self.lastVelocity = (gamepadPan - self.lastThumbstickPos)/(currentTime - self.lastThumbstickRotate)
  1737.                         end
  1738.        
  1739.                         self.lastThumbstickPos = gamepadPan
  1740.                         self.lastThumbstickRotate = currentTime
  1741.        
  1742.                         return Vector2.new( gamepadPan.X * finalConstant, gamepadPan.Y * finalConstant * self.ySensitivity * UserGameSettings:GetCameraYInvertValue())
  1743.                 end
  1744.        
  1745.                 return ZERO_VECTOR2
  1746.         end
  1747.        
  1748.         -- [[ VR Support Section ]] --
  1749.        
  1750.         function BaseCamera:ApplyVRTransform()
  1751.                 if not VRService.VREnabled then
  1752.                         return
  1753.                 end
  1754.        
  1755.                 --we only want this to happen in first person VR
  1756.                 local rootJoint = self.humanoidRootPart and self.humanoidRootPart:FindFirstChild("RootJoint")
  1757.                 if not rootJoint then
  1758.                         return
  1759.                 end
  1760.        
  1761.                 local cameraSubject = game.Workspace.CurrentCamera.CameraSubject
  1762.                 local isInVehicle = cameraSubject and cameraSubject:IsA("VehicleSeat")
  1763.        
  1764.                 if self.inFirstPerson and not isInVehicle then
  1765.                         local vrFrame = VRService:GetUserCFrame(Enum.UserCFrame.Head)
  1766.                         local vrRotation = vrFrame - vrFrame.p
  1767.                         rootJoint.C0 = CFrame.new(vrRotation:vectorToObjectSpace(vrFrame.p)) * CFrame.new(0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0)
  1768.                 else
  1769.                         rootJoint.C0 = CFrame.new(0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0)
  1770.                 end
  1771.         end
  1772.        
  1773.         function BaseCamera:IsInFirstPerson()
  1774.                 return self.inFirstPerson
  1775.         end
  1776.        
  1777.         function BaseCamera:ShouldUseVRRotation()
  1778.                 if not VRService.VREnabled then
  1779.                         return false
  1780.                 end
  1781.        
  1782.                 if not self.VRRotationIntensityAvailable and tick() - self.lastVRRotationIntensityCheckTime < 1 then
  1783.                         return false
  1784.                 end
  1785.        
  1786.                 local success, vrRotationIntensity = pcall(function() return StarterGui:GetCore("VRRotationIntensity") end)
  1787.                 self.VRRotationIntensityAvailable = success and vrRotationIntensity ~= nil
  1788.                 self.lastVRRotationIntensityCheckTime = tick()
  1789.        
  1790.                 self.shouldUseVRRotation = success and vrRotationIntensity ~= nil and vrRotationIntensity ~= "Smooth"
  1791.        
  1792.                 return self.shouldUseVRRotation
  1793.         end
  1794.        
  1795.         function BaseCamera:GetVRRotationInput()
  1796.                 local vrRotateSum = ZERO_VECTOR2
  1797.                 local success, vrRotationIntensity = pcall(function() return StarterGui:GetCore("VRRotationIntensity") end)
  1798.        
  1799.                 if not success then
  1800.                         return
  1801.                 end
  1802.        
  1803.                 local vrGamepadRotation = self.GamepadPanningCamera or ZERO_VECTOR2
  1804.                 local delayExpired = (tick() - self.lastVRRotationTime) >= self:GetRepeatDelayValue(vrRotationIntensity)
  1805.        
  1806.                 if math.abs(vrGamepadRotation.x) >= self:GetActivateValue() then
  1807.                         if (delayExpired or not self.vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2]) then
  1808.                                 local sign = 1
  1809.                                 if vrGamepadRotation.x < 0 then
  1810.                                         sign = -1
  1811.                                 end
  1812.                                 vrRotateSum = vrRotateSum + self:GetRotateAmountValue(vrRotationIntensity) * sign
  1813.                                 self.vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2] = true
  1814.                         end
  1815.                 elseif math.abs(vrGamepadRotation.x) < self:GetActivateValue() - 0.1 then
  1816.                         self.vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2] = nil
  1817.                 end
  1818.                 if self.turningLeft then
  1819.                         if delayExpired or not self.vrRotateKeyCooldown[Enum.KeyCode.Left] then
  1820.                                 vrRotateSum = vrRotateSum - self:GetRotateAmountValue(vrRotationIntensity)
  1821.                                 self.vrRotateKeyCooldown[Enum.KeyCode.Left] = true
  1822.                         end
  1823.                 else
  1824.                         self.vrRotateKeyCooldown[Enum.KeyCode.Left] = nil
  1825.                 end
  1826.                 if self.turningRight then
  1827.                         if (delayExpired or not self.vrRotateKeyCooldown[Enum.KeyCode.Right]) then
  1828.                                 vrRotateSum = vrRotateSum + self:GetRotateAmountValue(vrRotationIntensity)
  1829.                                 self.vrRotateKeyCooldown[Enum.KeyCode.Right] = true
  1830.                         end
  1831.                 else
  1832.                         self.vrRotateKeyCooldown[Enum.KeyCode.Right] = nil
  1833.                 end
  1834.        
  1835.                 if vrRotateSum ~= ZERO_VECTOR2 then
  1836.                         self.lastVRRotationTime = tick()
  1837.                 end
  1838.        
  1839.                 return vrRotateSum
  1840.         end
  1841.        
  1842.         function BaseCamera:CancelCameraFreeze(keepConstraints)
  1843.                 if not keepConstraints then
  1844.                         self.cameraTranslationConstraints = Vector3.new(self.cameraTranslationConstraints.x, 1, self.cameraTranslationConstraints.z)
  1845.                 end
  1846.                 if self.cameraFrozen then
  1847.                         self.trackingHumanoid = nil
  1848.                         self.cameraFrozen = false
  1849.                 end
  1850.         end
  1851.        
  1852.         function BaseCamera:StartCameraFreeze(subjectPosition, humanoidToTrack)
  1853.                 if not self.cameraFrozen then
  1854.                         self.humanoidJumpOrigin = subjectPosition
  1855.                         self.trackingHumanoid = humanoidToTrack
  1856.                         self.cameraTranslationConstraints = Vector3.new(self.cameraTranslationConstraints.x, 0, self.cameraTranslationConstraints.z)
  1857.                         self.cameraFrozen = true
  1858.                 end
  1859.         end
  1860.        
  1861.         function BaseCamera:OnNewCameraSubject()
  1862.                 if self.subjectStateChangedConn then
  1863.                         self.subjectStateChangedConn:Disconnect()
  1864.                         self.subjectStateChangedConn = nil
  1865.                 end
  1866.        
  1867.                 local humanoid = workspace.CurrentCamera and workspace.CurrentCamera.CameraSubject
  1868.                 if self.trackingHumanoid ~= humanoid then
  1869.                         self:CancelCameraFreeze()
  1870.                 end
  1871.                 if humanoid and humanoid:IsA("Humanoid") then
  1872.                         self.subjectStateChangedConn = humanoid.StateChanged:Connect(function(oldState, newState)
  1873.                                 if VRService.VREnabled and newState == Enum.HumanoidStateType.Jumping and not self.inFirstPerson then
  1874.                                         self:StartCameraFreeze(self:GetSubjectPosition(), humanoid)
  1875.                                 elseif newState ~= Enum.HumanoidStateType.Jumping and newState ~= Enum.HumanoidStateType.Freefall then
  1876.                                         self:CancelCameraFreeze(true)
  1877.                                 end
  1878.                         end)
  1879.                 end
  1880.         end
  1881.        
  1882.         function BaseCamera:GetVRFocus(subjectPosition, timeDelta)
  1883.                 local lastFocus = self.LastCameraFocus or subjectPosition
  1884.                 if not self.cameraFrozen then
  1885.                         self.cameraTranslationConstraints = Vector3.new(self.cameraTranslationConstraints.x, math.min(1, self.cameraTranslationConstraints.y + 0.42 * timeDelta), self.cameraTranslationConstraints.z)
  1886.                 end
  1887.        
  1888.                 local newFocus
  1889.                 if self.cameraFrozen and self.humanoidJumpOrigin and self.humanoidJumpOrigin.y > lastFocus.y then
  1890.                         newFocus = CFrame.new(Vector3.new(subjectPosition.x, math.min(self.humanoidJumpOrigin.y, lastFocus.y + 5 * timeDelta), subjectPosition.z))
  1891.                 else
  1892.                         newFocus = CFrame.new(Vector3.new(subjectPosition.x, lastFocus.y, subjectPosition.z):lerp(subjectPosition, self.cameraTranslationConstraints.y))
  1893.                 end
  1894.        
  1895.                 if self.cameraFrozen then
  1896.                         -- No longer in 3rd person
  1897.                         if self.inFirstPerson then -- not VRService.VREnabled
  1898.                                 self:CancelCameraFreeze()
  1899.                         end
  1900.                         -- This case you jumped off a cliff and want to keep your character in view
  1901.                         -- 0.5 is to fix floating point error when not jumping off cliffs
  1902.                         if self.humanoidJumpOrigin and subjectPosition.y < (self.humanoidJumpOrigin.y - 0.5) then
  1903.                                 self:CancelCameraFreeze()
  1904.                         end
  1905.                 end
  1906.        
  1907.                 return newFocus
  1908.         end
  1909.        
  1910.         function BaseCamera:GetRotateAmountValue(vrRotationIntensity)
  1911.                 vrRotationIntensity = vrRotationIntensity or StarterGui:GetCore("VRRotationIntensity")
  1912.                 if vrRotationIntensity then
  1913.                         if vrRotationIntensity == "Low" then
  1914.                                 return VR_LOW_INTENSITY_ROTATION
  1915.                         elseif vrRotationIntensity == "High" then
  1916.                                 return VR_HIGH_INTENSITY_ROTATION
  1917.                         end
  1918.                 end
  1919.                 return ZERO_VECTOR2
  1920.         end
  1921.        
  1922.         function BaseCamera:GetRepeatDelayValue(vrRotationIntensity)
  1923.                 vrRotationIntensity = vrRotationIntensity or StarterGui:GetCore("VRRotationIntensity")
  1924.                 if vrRotationIntensity then
  1925.                         if vrRotationIntensity == "Low" then
  1926.                                 return VR_LOW_INTENSITY_REPEAT
  1927.                         elseif vrRotationIntensity == "High" then
  1928.                                 return VR_HIGH_INTENSITY_REPEAT
  1929.                         end
  1930.                 end
  1931.                 return 0
  1932.         end
  1933.        
  1934.         function BaseCamera:Update(dt)
  1935.                 error("BaseCamera:Update() This is a virtual function that should never be getting called.", 2)
  1936.         end
  1937.        
  1938.         BaseCamera.UpCFrame = CFrame.new()
  1939.        
  1940.         function BaseCamera:UpdateUpCFrame(cf)
  1941.                 self.UpCFrame = cf
  1942.         end
  1943.         local ZERO = Vector3.new(0, 0, 0)
  1944.         function BaseCamera:CalculateNewLookCFrame(suppliedLookVector)
  1945.                 local currLookVector = suppliedLookVector or self:GetCameraLookVector()
  1946.                 currLookVector = self.UpCFrame:VectorToObjectSpace(currLookVector)
  1947.                
  1948.                 local currPitchAngle = math.asin(currLookVector.y)
  1949.                 local yTheta = math.clamp(self.rotateInput.y, -MAX_Y + currPitchAngle, -MIN_Y + currPitchAngle)
  1950.                 local constrainedRotateInput = Vector2.new(self.rotateInput.x, yTheta)
  1951.                 local startCFrame = CFrame.new(ZERO, currLookVector)
  1952.                 local newLookCFrame = CFrame.Angles(0, -constrainedRotateInput.x, 0) * startCFrame * CFrame.Angles(-constrainedRotateInput.y,0,0)
  1953.                
  1954.                 return newLookCFrame
  1955.         end
  1956.        
  1957.         return BaseCamera
  1958. end
  1959.  
  1960. function _BaseOcclusion()
  1961.         --[[ The Module ]]--
  1962.         local BaseOcclusion = {}
  1963.         BaseOcclusion.__index = BaseOcclusion
  1964.         setmetatable(BaseOcclusion, {
  1965.                 __call = function(_, ...)
  1966.                         return BaseOcclusion.new(...)
  1967.                 end
  1968.         })
  1969.        
  1970.         function BaseOcclusion.new()
  1971.                 local self = setmetatable({}, BaseOcclusion)
  1972.                 return self
  1973.         end
  1974.        
  1975.         -- Called when character is added
  1976.         function BaseOcclusion:CharacterAdded(char, player)
  1977.         end
  1978.        
  1979.         -- Called when character is about to be removed
  1980.         function BaseOcclusion:CharacterRemoving(char, player)
  1981.         end
  1982.        
  1983.         function BaseOcclusion:OnCameraSubjectChanged(newSubject)
  1984.         end
  1985.        
  1986.         --[[ Derived classes are required to override and implement all of the following functions ]]--
  1987.         function BaseOcclusion:GetOcclusionMode()
  1988.                 -- Must be overridden in derived classes to return an Enum.DevCameraOcclusionMode value
  1989.                 warn("BaseOcclusion GetOcclusionMode must be overridden by derived classes")
  1990.                 return nil
  1991.         end
  1992.        
  1993.         function BaseOcclusion:Enable(enabled)
  1994.                 warn("BaseOcclusion Enable must be overridden by derived classes")
  1995.         end
  1996.        
  1997.         function BaseOcclusion:Update(dt, desiredCameraCFrame, desiredCameraFocus)
  1998.                 warn("BaseOcclusion Update must be overridden by derived classes")
  1999.                 return desiredCameraCFrame, desiredCameraFocus
  2000.         end
  2001.        
  2002.         return BaseOcclusion
  2003. end
  2004.  
  2005. function _Popper()
  2006.        
  2007.         local Players = game:GetService("Players")
  2008.        
  2009.         local camera = game.Workspace.CurrentCamera
  2010.        
  2011.         local min = math.min
  2012.         local tan = math.tan
  2013.         local rad = math.rad
  2014.         local inf = math.huge
  2015.         local ray = Ray.new
  2016.        
  2017.         local function getTotalTransparency(part)
  2018.                 return 1 - (1 - part.Transparency)*(1 - part.LocalTransparencyModifier)
  2019.         end
  2020.        
  2021.         local function eraseFromEnd(t, toSize)
  2022.                 for i = #t, toSize + 1, -1 do
  2023.                         t[i] = nil
  2024.                 end
  2025.         end
  2026.        
  2027.         local nearPlaneZ, projX, projY do
  2028.                 local function updateProjection()
  2029.                         local fov = rad(camera.FieldOfView)
  2030.                         local view = camera.ViewportSize
  2031.                         local ar = view.X/view.Y
  2032.        
  2033.                         projY = 2*tan(fov/2)
  2034.                         projX = ar*projY
  2035.                 end
  2036.        
  2037.                 camera:GetPropertyChangedSignal("FieldOfView"):Connect(updateProjection)
  2038.                 camera:GetPropertyChangedSignal("ViewportSize"):Connect(updateProjection)
  2039.        
  2040.                 updateProjection()
  2041.        
  2042.                 nearPlaneZ = camera.NearPlaneZ
  2043.                 camera:GetPropertyChangedSignal("NearPlaneZ"):Connect(function()
  2044.                         nearPlaneZ = camera.NearPlaneZ
  2045.                 end)
  2046.         end
  2047.        
  2048.         local blacklist = {} do
  2049.                 local charMap = {}
  2050.        
  2051.                 local function refreshIgnoreList()
  2052.                         local n = 1
  2053.                         blacklist = {}
  2054.                         for _, character in pairs(charMap) do
  2055.                                 blacklist[n] = character
  2056.                                 n = n + 1
  2057.                         end
  2058.                 end
  2059.        
  2060.                 local function playerAdded(player)
  2061.                         local function characterAdded(character)
  2062.                                 charMap[player] = character
  2063.                                 refreshIgnoreList()
  2064.                         end
  2065.                         local function characterRemoving()
  2066.                                 charMap[player] = nil
  2067.                                 refreshIgnoreList()
  2068.                         end
  2069.        
  2070.                         player.CharacterAdded:Connect(characterAdded)
  2071.                         player.CharacterRemoving:Connect(characterRemoving)
  2072.                         if player.Character then
  2073.                                 characterAdded(player.Character)
  2074.                         end
  2075.                 end
  2076.        
  2077.                 local function playerRemoving(player)
  2078.                         charMap[player] = nil
  2079.                         refreshIgnoreList()
  2080.                 end
  2081.        
  2082.                 Players.PlayerAdded:Connect(playerAdded)
  2083.                 Players.PlayerRemoving:Connect(playerRemoving)
  2084.        
  2085.                 for _, player in ipairs(Players:GetPlayers()) do
  2086.                         playerAdded(player)
  2087.                 end
  2088.                 refreshIgnoreList()
  2089.         end
  2090.        
  2091.         --------------------------------------------------------------------------------------------
  2092.         -- Popper uses the level geometry find an upper bound on subject-to-camera distance.
  2093.         --
  2094.         -- Hard limits are applied immediately and unconditionally. They are generally caused
  2095.         -- when level geometry intersects with the near plane (with exceptions, see below).
  2096.         --
  2097.         -- Soft limits are only applied under certain conditions.
  2098.         -- They are caused when level geometry occludes the subject without actually intersecting
  2099.         -- with the near plane at the target distance.
  2100.         --
  2101.         -- Soft limits can be promoted to hard limits and hard limits can be demoted to soft limits.
  2102.         -- We usually don"t want the latter to happen.
  2103.         --
  2104.         -- A soft limit will be promoted to a hard limit if an obstruction
  2105.         -- lies between the current and target camera positions.
  2106.         --------------------------------------------------------------------------------------------
  2107.        
  2108.         local subjectRoot
  2109.         local subjectPart
  2110.        
  2111.         camera:GetPropertyChangedSignal("CameraSubject"):Connect(function()
  2112.                 local subject = camera.CameraSubject
  2113.                 if subject:IsA("Humanoid") then
  2114.                         subjectPart = subject.RootPart
  2115.                 elseif subject:IsA("BasePart") then
  2116.                         subjectPart = subject
  2117.                 else
  2118.                         subjectPart = nil
  2119.                 end
  2120.         end)
  2121.        
  2122.         local function canOcclude(part)
  2123.                 -- Occluders must be:
  2124.                 -- 1. Opaque
  2125.                 -- 2. Interactable
  2126.                 -- 3. Not in the same assembly as the subject
  2127.        
  2128.                 return
  2129.                         getTotalTransparency(part) < 0.25 and
  2130.                         part.CanCollide and
  2131.                         subjectRoot ~= (part:GetRootPart() or part) and
  2132.                         not part:IsA("TrussPart")
  2133.         end
  2134.        
  2135.         -- Offsets for the volume visibility test
  2136.         local SCAN_SAMPLE_OFFSETS = {
  2137.                 Vector2.new( 0.4, 0.0),
  2138.                 Vector2.new(-0.4, 0.0),
  2139.                 Vector2.new( 0.0,-0.4),
  2140.                 Vector2.new( 0.0, 0.4),
  2141.                 Vector2.new( 0.0, 0.2),
  2142.         }
  2143.        
  2144.         --------------------------------------------------------------------------------
  2145.         -- Piercing raycasts
  2146.        
  2147.         local function getCollisionPoint(origin, dir)
  2148.                 local originalSize = #blacklist
  2149.                 repeat
  2150.                         local hitPart, hitPoint = workspace:FindPartOnRayWithIgnoreList(
  2151.                                 ray(origin, dir), blacklist, false, true
  2152.                         )
  2153.        
  2154.                         if hitPart then
  2155.                                 if hitPart.CanCollide then
  2156.                                         eraseFromEnd(blacklist, originalSize)
  2157.                                         return hitPoint, true
  2158.                                 end
  2159.                                 blacklist[#blacklist + 1] = hitPart
  2160.                         end
  2161.                 until not hitPart
  2162.        
  2163.                 eraseFromEnd(blacklist, originalSize)
  2164.                 return origin + dir, false
  2165.         end
  2166.        
  2167.         --------------------------------------------------------------------------------
  2168.        
  2169.         local function queryPoint(origin, unitDir, dist, lastPos)
  2170.                 debug.profilebegin("queryPoint")
  2171.        
  2172.                 local originalSize = #blacklist
  2173.        
  2174.                 dist = dist + nearPlaneZ
  2175.                 local target = origin + unitDir*dist
  2176.        
  2177.                 local softLimit = inf
  2178.                 local hardLimit = inf
  2179.                 local movingOrigin = origin
  2180.        
  2181.                 repeat
  2182.                         local entryPart, entryPos = workspace:FindPartOnRayWithIgnoreList(ray(movingOrigin, target - movingOrigin), blacklist, false, true)
  2183.        
  2184.                         if entryPart then
  2185.                                 if canOcclude(entryPart) then
  2186.                                         local wl = {entryPart}
  2187.                                         local exitPart = workspace:FindPartOnRayWithWhitelist(ray(target, entryPos - target), wl, true)
  2188.        
  2189.                                         local lim = (entryPos - origin).Magnitude
  2190.        
  2191.                                         if exitPart then
  2192.                                                 local promote = false
  2193.                                                 if lastPos then
  2194.                                                         promote =
  2195.                                                                 workspace:FindPartOnRayWithWhitelist(ray(lastPos, target - lastPos), wl, true) or
  2196.                                                                 workspace:FindPartOnRayWithWhitelist(ray(target, lastPos - target), wl, true)
  2197.                                                 end
  2198.        
  2199.                                                 if promote then
  2200.                                                         -- Ostensibly a soft limit, but the camera has passed through it in the last frame, so promote to a hard limit.
  2201.                                                         hardLimit = lim
  2202.                                                 elseif dist < softLimit then
  2203.                                                         -- Trivial soft limit
  2204.                                                         softLimit = lim
  2205.                                                 end
  2206.                                         else
  2207.                                                 -- Trivial hard limit
  2208.                                                 hardLimit = lim
  2209.                                         end
  2210.                                 end
  2211.        
  2212.                                 blacklist[#blacklist + 1] = entryPart
  2213.                                 movingOrigin = entryPos - unitDir*1e-3
  2214.                         end
  2215.                 until hardLimit < inf or not entryPart
  2216.        
  2217.                 eraseFromEnd(blacklist, originalSize)
  2218.        
  2219.                 debug.profileend()
  2220.                 return softLimit - nearPlaneZ, hardLimit - nearPlaneZ
  2221.         end
  2222.        
  2223.         local function queryViewport(focus, dist)
  2224.                 debug.profilebegin("queryViewport")
  2225.        
  2226.                 local fP =  focus.p
  2227.                 local fX =  focus.rightVector
  2228.                 local fY =  focus.upVector
  2229.                 local fZ = -focus.lookVector
  2230.        
  2231.                 local viewport = camera.ViewportSize
  2232.        
  2233.                 local hardBoxLimit = inf
  2234.                 local softBoxLimit = inf
  2235.        
  2236.                 -- Center the viewport on the PoI, sweep points on the edge towards the target, and take the minimum limits
  2237.                 for viewX = 0, 1 do
  2238.                         local worldX = fX*((viewX - 0.5)*projX)
  2239.        
  2240.                         for viewY = 0, 1 do
  2241.                                 local worldY = fY*((viewY - 0.5)*projY)
  2242.        
  2243.                                 local origin = fP + nearPlaneZ*(worldX + worldY)
  2244.                                 local lastPos = camera:ViewportPointToRay(
  2245.                                         viewport.x*viewX,
  2246.                                         viewport.y*viewY
  2247.                                 ).Origin
  2248.        
  2249.                                 local softPointLimit, hardPointLimit = queryPoint(origin, fZ, dist, lastPos)
  2250.        
  2251.                                 if hardPointLimit < hardBoxLimit then
  2252.                                         hardBoxLimit = hardPointLimit
  2253.                                 end
  2254.                                 if softPointLimit < softBoxLimit then
  2255.                                         softBoxLimit = softPointLimit
  2256.                                 end
  2257.                         end
  2258.                 end
  2259.                 debug.profileend()
  2260.        
  2261.                 return softBoxLimit, hardBoxLimit
  2262.         end
  2263.        
  2264.         local function testPromotion(focus, dist, focusExtrapolation)
  2265.                 debug.profilebegin("testPromotion")
  2266.        
  2267.                 local fP = focus.p
  2268.                 local fX = focus.rightVector
  2269.                 local fY = focus.upVector
  2270.                 local fZ = -focus.lookVector
  2271.        
  2272.                 do
  2273.                         -- Dead reckoning the camera rotation and focus
  2274.                         debug.profilebegin("extrapolate")
  2275.        
  2276.                         local SAMPLE_DT = 0.0625
  2277.                         local SAMPLE_MAX_T = 1.25
  2278.        
  2279.                         local maxDist = (getCollisionPoint(fP, focusExtrapolation.posVelocity*SAMPLE_MAX_T) - fP).Magnitude
  2280.                         -- Metric that decides how many samples to take
  2281.                         local combinedSpeed = focusExtrapolation.posVelocity.magnitude
  2282.        
  2283.                         for dt = 0, min(SAMPLE_MAX_T, focusExtrapolation.rotVelocity.magnitude + maxDist/combinedSpeed), SAMPLE_DT do
  2284.                                 local cfDt = focusExtrapolation.extrapolate(dt) -- Extrapolated CFrame at time dt
  2285.        
  2286.                                 if queryPoint(cfDt.p, -cfDt.lookVector, dist) >= dist then
  2287.                                         return false
  2288.                                 end
  2289.                         end
  2290.        
  2291.                         debug.profileend()
  2292.                 end
  2293.        
  2294.                 do
  2295.                         -- Test screen-space offsets from the focus for the presence of soft limits
  2296.                         debug.profilebegin("testOffsets")
  2297.        
  2298.                         for _, offset in ipairs(SCAN_SAMPLE_OFFSETS) do
  2299.                                 local scaledOffset = offset
  2300.                                 local pos = getCollisionPoint(fP, fX*scaledOffset.x + fY*scaledOffset.y)
  2301.                                 if queryPoint(pos, (fP + fZ*dist - pos).Unit, dist) == inf then
  2302.                                         return false
  2303.                                 end
  2304.                         end
  2305.        
  2306.                         debug.profileend()
  2307.                 end
  2308.        
  2309.                 debug.profileend()
  2310.                 return true
  2311.         end
  2312.        
  2313.         local function Popper(focus, targetDist, focusExtrapolation)
  2314.                 debug.profilebegin("popper")
  2315.        
  2316.                 subjectRoot = subjectPart and subjectPart:GetRootPart() or subjectPart
  2317.        
  2318.                 local dist = targetDist
  2319.                 local soft, hard = queryViewport(focus, targetDist)
  2320.                 if hard < dist then
  2321.                         dist = hard
  2322.                 end
  2323.                 if soft < dist and testPromotion(focus, targetDist, focusExtrapolation) then
  2324.                         dist = soft
  2325.                 end
  2326.        
  2327.                 subjectRoot = nil
  2328.        
  2329.                 debug.profileend()
  2330.                 return dist
  2331.         end
  2332.        
  2333.         return Popper
  2334. end
  2335.  
  2336. function _ZoomController()
  2337.         local ZOOM_STIFFNESS = 4.5
  2338.         local ZOOM_DEFAULT = 12.5
  2339.         local ZOOM_ACCELERATION = 0.0375
  2340.        
  2341.         local MIN_FOCUS_DIST = 0.5
  2342.         local DIST_OPAQUE = 1
  2343.        
  2344.         local Popper = _Popper()
  2345.        
  2346.         local clamp = math.clamp
  2347.         local exp = math.exp
  2348.         local min = math.min
  2349.         local max = math.max
  2350.         local pi = math.pi
  2351.        
  2352.         local cameraMinZoomDistance, cameraMaxZoomDistance do
  2353.                 local Player = game:GetService("Players").LocalPlayer
  2354.        
  2355.                 local function updateBounds()
  2356.                         cameraMinZoomDistance = Player.CameraMinZoomDistance
  2357.                         cameraMaxZoomDistance = Player.CameraMaxZoomDistance
  2358.                 end
  2359.        
  2360.                 updateBounds()
  2361.        
  2362.                 Player:GetPropertyChangedSignal("CameraMinZoomDistance"):Connect(updateBounds)
  2363.                 Player:GetPropertyChangedSignal("CameraMaxZoomDistance"):Connect(updateBounds)
  2364.         end
  2365.        
  2366.         local ConstrainedSpring = {} do
  2367.                 ConstrainedSpring.__index = ConstrainedSpring
  2368.        
  2369.                 function ConstrainedSpring.new(freq, x, minValue, maxValue)
  2370.                         x = clamp(x, minValue, maxValue)
  2371.                         return setmetatable({
  2372.                                 freq = freq, -- Undamped frequency (Hz)
  2373.                                 x = x, -- Current position
  2374.                                 v = 0, -- Current velocity
  2375.                                 minValue = minValue, -- Minimum bound
  2376.                                 maxValue = maxValue, -- Maximum bound
  2377.                                 goal = x, -- Goal position
  2378.                         }, ConstrainedSpring)
  2379.                 end
  2380.        
  2381.                 function ConstrainedSpring:Step(dt)
  2382.                         local freq = self.freq*2*pi -- Convert from Hz to rad/s
  2383.                         local x = self.x
  2384.                         local v = self.v
  2385.                         local minValue = self.minValue
  2386.                         local maxValue = self.maxValue
  2387.                         local goal = self.goal
  2388.        
  2389.                         -- Solve the spring ODE for position and velocity after time t, assuming critical damping:
  2390.                         --   2*f*x'[t] + x''[t] = f^2*(g - x[t])
  2391.                         -- Knowns are x[0] and x'[0].
  2392.                         -- Solve for x[t] and x'[t].
  2393.        
  2394.                         local offset = goal - x
  2395.                         local step = freq*dt
  2396.                         local decay = exp(-step)
  2397.        
  2398.                         local x1 = goal + (v*dt - offset*(step + 1))*decay
  2399.                         local v1 = ((offset*freq - v)*step + v)*decay
  2400.        
  2401.                         -- Constrain
  2402.                         if x1 < minValue then
  2403.                                 x1 = minValue
  2404.                                 v1 = 0
  2405.                         elseif x1 > maxValue then
  2406.                                 x1 = maxValue
  2407.                                 v1 = 0
  2408.                         end
  2409.        
  2410.                         self.x = x1
  2411.                         self.v = v1
  2412.        
  2413.                         return x1
  2414.                 end
  2415.         end
  2416.        
  2417.         local zoomSpring = ConstrainedSpring.new(ZOOM_STIFFNESS, ZOOM_DEFAULT, MIN_FOCUS_DIST, cameraMaxZoomDistance)
  2418.        
  2419.         local function stepTargetZoom(z, dz, zoomMin, zoomMax)
  2420.                 z = clamp(z + dz*(1 + z*ZOOM_ACCELERATION), zoomMin, zoomMax)
  2421.                 if z < DIST_OPAQUE then
  2422.                         z = dz  DIST_OPAQUE then
  2423.                                 -- Make a pessimistic estimate of zoom distance for this step without accounting for poppercam
  2424.                                 local maxPossibleZoom = max(
  2425.                                         zoomSpring.x,
  2426.                                         stepTargetZoom(zoomSpring.goal, zoomDelta, cameraMinZoomDistance, cameraMaxZoomDistance)
  2427.                                 )
  2428.        
  2429.                                 -- Run the Popper algorithm on the feasible zoom range, [MIN_FOCUS_DIST, maxPossibleZoom]
  2430.                                 poppedZoom = Popper(
  2431.                                         focus*CFrame.new(0, 0, MIN_FOCUS_DIST),
  2432.                                         maxPossibleZoom - MIN_FOCUS_DIST,
  2433.                                         extrapolation
  2434.                                 ) + MIN_FOCUS_DIST
  2435.                         end
  2436.        
  2437.                         zoomSpring.minValue = MIN_FOCUS_DIST
  2438.                         zoomSpring.maxValue = min(cameraMaxZoomDistance, poppedZoom)
  2439.        
  2440.                         return zoomSpring:Step(renderDt)
  2441.                 end
  2442.        
  2443.                 function Zoom.SetZoomParameters(targetZoom, newZoomDelta)
  2444.                         zoomSpring.goal = targetZoom
  2445.                         zoomDelta = newZoomDelta
  2446.                 end
  2447.         end
  2448.        
  2449.         return Zoom
  2450. end
  2451.  
  2452. function _MouseLockController()
  2453.         --[[ Constants ]]--
  2454.         local DEFAULT_MOUSE_LOCK_CURSOR = "rbxasset://textures/MouseLockedCursor.png"
  2455.        
  2456.         local CONTEXT_ACTION_NAME = "MouseLockSwitchAction"
  2457.         local MOUSELOCK_ACTION_PRIORITY = Enum.ContextActionPriority.Default.Value
  2458.        
  2459.         --[[ Services ]]--
  2460.         local PlayersService = game:GetService("Players")
  2461.         local ContextActionService = game:GetService("ContextActionService")
  2462.         local Settings = UserSettings() -- ignore warning
  2463.         local GameSettings = Settings.GameSettings
  2464.         local Mouse = PlayersService.LocalPlayer:GetMouse()
  2465.        
  2466.         --[[ The Module ]]--
  2467.         local MouseLockController = {}
  2468.         MouseLockController.__index = MouseLockController
  2469.        
  2470.         function MouseLockController.new()
  2471.                 local self = setmetatable({}, MouseLockController)
  2472.        
  2473.                 self.isMouseLocked = false
  2474.                 self.savedMouseCursor = nil
  2475.                 self.boundKeys = {Enum.KeyCode.LeftShift, Enum.KeyCode.RightShift} -- defaults
  2476.        
  2477.                 self.mouseLockToggledEvent = Instance.new("BindableEvent")
  2478.        
  2479.                 local boundKeysObj = script:FindFirstChild("BoundKeys")
  2480.                 if (not boundKeysObj) or (not boundKeysObj:IsA("StringValue")) then
  2481.                         -- If object with correct name was found, but it's not a StringValue, destroy and replace
  2482.                         if boundKeysObj then
  2483.                                 boundKeysObj:Destroy()
  2484.                         end
  2485.        
  2486.                         boundKeysObj = Instance.new("StringValue")
  2487.                         boundKeysObj.Name = "BoundKeys"
  2488.                         boundKeysObj.Value = "LeftShift,RightShift"
  2489.                         boundKeysObj.Parent = script
  2490.                 end
  2491.        
  2492.                 if boundKeysObj then
  2493.                         boundKeysObj.Changed:Connect(function(value)
  2494.                                 self:OnBoundKeysObjectChanged(value)
  2495.                         end)
  2496.                         self:OnBoundKeysObjectChanged(boundKeysObj.Value) -- Initial setup call
  2497.                 end
  2498.        
  2499.                 -- Watch for changes to user's ControlMode and ComputerMovementMode settings and update the feature availability accordingly
  2500.                 GameSettings.Changed:Connect(function(property)
  2501.                         if property == "ControlMode" or property == "ComputerMovementMode" then
  2502.                                 self:UpdateMouseLockAvailability()
  2503.                         end
  2504.                 end)
  2505.        
  2506.                 -- Watch for changes to DevEnableMouseLock and update the feature availability accordingly
  2507.                 PlayersService.LocalPlayer:GetPropertyChangedSignal("DevEnableMouseLock"):Connect(function()
  2508.                         self:UpdateMouseLockAvailability()
  2509.                 end)
  2510.        
  2511.                 -- Watch for changes to DevEnableMouseLock and update the feature availability accordingly
  2512.                 PlayersService.LocalPlayer:GetPropertyChangedSignal("DevComputerMovementMode"):Connect(function()
  2513.                         self:UpdateMouseLockAvailability()
  2514.                 end)
  2515.        
  2516.                 self:UpdateMouseLockAvailability()
  2517.        
  2518.                 return self
  2519.         end
  2520.        
  2521.         function MouseLockController:GetIsMouseLocked()
  2522.                 return self.isMouseLocked
  2523.         end
  2524.        
  2525.         function MouseLockController:GetBindableToggleEvent()
  2526.                 return self.mouseLockToggledEvent.Event
  2527.         end
  2528.        
  2529.         function MouseLockController:GetMouseLockOffset()
  2530.                 local offsetValueObj = script:FindFirstChild("CameraOffset")
  2531.                 if offsetValueObj and offsetValueObj:IsA("Vector3Value") then
  2532.                         return offsetValueObj.Value
  2533.                 else
  2534.                         -- If CameraOffset object was found but not correct type, destroy
  2535.                         if offsetValueObj then
  2536.                                 offsetValueObj:Destroy()
  2537.                         end
  2538.                         offsetValueObj = Instance.new("Vector3Value")
  2539.                         offsetValueObj.Name = "CameraOffset"
  2540.                         offsetValueObj.Value = Vector3.new(1.75,0,0) -- Legacy Default Value
  2541.                         offsetValueObj.Parent = script
  2542.                 end
  2543.        
  2544.                 if offsetValueObj and offsetValueObj.Value then
  2545.                         return offsetValueObj.Value
  2546.                 end
  2547.        
  2548.                 return Vector3.new(1.75,0,0)
  2549.         end
  2550.        
  2551.         function MouseLockController:UpdateMouseLockAvailability()
  2552.                 local devAllowsMouseLock = PlayersService.LocalPlayer.DevEnableMouseLock
  2553.                 local devMovementModeIsScriptable = PlayersService.LocalPlayer.DevComputerMovementMode == Enum.DevComputerMovementMode.Scriptable
  2554.                 local userHasMouseLockModeEnabled = GameSettings.ControlMode == Enum.ControlMode.MouseLockSwitch
  2555.                 local userHasClickToMoveEnabled =  GameSettings.ComputerMovementMode == Enum.ComputerMovementMode.ClickToMove
  2556.                 local MouseLockAvailable = devAllowsMouseLock and userHasMouseLockModeEnabled and not userHasClickToMoveEnabled and not devMovementModeIsScriptable
  2557.        
  2558.                 if MouseLockAvailable~=self.enabled then
  2559.                         self:EnableMouseLock(MouseLockAvailable)
  2560.                 end
  2561.         end
  2562.        
  2563.         function MouseLockController:OnBoundKeysObjectChanged(newValue)
  2564.                 self.boundKeys = {} -- Overriding defaults, note: possibly with nothing at all if boundKeysObj.Value is "" or contains invalid values
  2565.                 for token in string.gmatch(newValue,"[^%s,]+") do
  2566.                         for _, keyEnum in pairs(Enum.KeyCode:GetEnumItems()) do
  2567.                                 if token == keyEnum.Name then
  2568.                                         self.boundKeys[#self.boundKeys+1] = keyEnum
  2569.                                         break
  2570.                                 end
  2571.                         end
  2572.                 end
  2573.                 self:UnbindContextActions()
  2574.                 self:BindContextActions()
  2575.         end
  2576.        
  2577.         --[[ Local Functions ]]--
  2578.         function MouseLockController:OnMouseLockToggled()
  2579.                 self.isMouseLocked = not self.isMouseLocked
  2580.        
  2581.                 if self.isMouseLocked then
  2582.                         local cursorImageValueObj = script:FindFirstChild("CursorImage")
  2583.                         if cursorImageValueObj and cursorImageValueObj:IsA("StringValue") and cursorImageValueObj.Value then
  2584.                                 self.savedMouseCursor = Mouse.Icon
  2585.                                 Mouse.Icon = cursorImageValueObj.Value
  2586.                         else
  2587.                                 if cursorImageValueObj then
  2588.                                         cursorImageValueObj:Destroy()
  2589.                                 end
  2590.                                 cursorImageValueObj = Instance.new("StringValue")
  2591.                                 cursorImageValueObj.Name = "CursorImage"
  2592.                                 cursorImageValueObj.Value = DEFAULT_MOUSE_LOCK_CURSOR
  2593.                                 cursorImageValueObj.Parent = script
  2594.                                 self.savedMouseCursor = Mouse.Icon
  2595.                                 Mouse.Icon = DEFAULT_MOUSE_LOCK_CURSOR
  2596.                         end
  2597.                 else
  2598.                         if self.savedMouseCursor then
  2599.                                 Mouse.Icon = self.savedMouseCursor
  2600.                                 self.savedMouseCursor = nil
  2601.                         end
  2602.                 end
  2603.        
  2604.                 self.mouseLockToggledEvent:Fire()
  2605.         end
  2606.        
  2607.         function MouseLockController:DoMouseLockSwitch(name, state, input)
  2608.                 if state == Enum.UserInputState.Begin then
  2609.                         self:OnMouseLockToggled()
  2610.                         return Enum.ContextActionResult.Sink
  2611.                 end
  2612.                 return Enum.ContextActionResult.Pass
  2613.         end
  2614.        
  2615.         function MouseLockController:BindContextActions()
  2616.                 ContextActionService:BindActionAtPriority(CONTEXT_ACTION_NAME, function(name, state, input)
  2617.                         return self:DoMouseLockSwitch(name, state, input)
  2618.                 end, false, MOUSELOCK_ACTION_PRIORITY, unpack(self.boundKeys))
  2619.         end
  2620.        
  2621.         function MouseLockController:UnbindContextActions()
  2622.                 ContextActionService:UnbindAction(CONTEXT_ACTION_NAME)
  2623.         end
  2624.        
  2625.         function MouseLockController:IsMouseLocked()
  2626.                 return self.enabled and self.isMouseLocked
  2627.         end
  2628.        
  2629.         function MouseLockController:EnableMouseLock(enable)
  2630.                 if enable ~= self.enabled then
  2631.        
  2632.                         self.enabled = enable
  2633.        
  2634.                         if self.enabled then
  2635.                                 -- Enabling the mode
  2636.                                 self:BindContextActions()
  2637.                         else
  2638.                                 -- Disabling
  2639.                                 -- Restore mouse cursor
  2640.                                 if Mouse.Icon~="" then
  2641.                                         Mouse.Icon = ""
  2642.                                 end
  2643.        
  2644.                                 self:UnbindContextActions()
  2645.        
  2646.                                 -- If the mode is disabled while being used, fire the event to toggle it off
  2647.                                 if self.isMouseLocked then
  2648.                                         self.mouseLockToggledEvent:Fire()
  2649.                                 end
  2650.        
  2651.                                 self.isMouseLocked = false
  2652.                         end
  2653.        
  2654.                 end
  2655.         end
  2656.        
  2657.         return MouseLockController
  2658. end
  2659.  
  2660. function _TransparencyController()
  2661.        
  2662.         local MAX_TWEEN_RATE = 2.8 -- per second
  2663.        
  2664.         local Util = _CameraUtils()
  2665.        
  2666.         --[[ The Module ]]--
  2667.         local TransparencyController = {}
  2668.         TransparencyController.__index = TransparencyController
  2669.        
  2670.         function TransparencyController.new()
  2671.                 local self = setmetatable({}, TransparencyController)
  2672.        
  2673.                 self.lastUpdate = tick()
  2674.                 self.transparencyDirty = false
  2675.                 self.enabled = false
  2676.                 self.lastTransparency = nil
  2677.        
  2678.                 self.descendantAddedConn, self.descendantRemovingConn = nil, nil
  2679.                 self.toolDescendantAddedConns = {}
  2680.                 self.toolDescendantRemovingConns = {}
  2681.                 self.cachedParts = {}
  2682.        
  2683.                 return self
  2684.         end
  2685.        
  2686.        
  2687.         function TransparencyController:HasToolAncestor(object)
  2688.                 if object.Parent == nil then return false end
  2689.                 return object.Parent:IsA('Tool') or self:HasToolAncestor(object.Parent)
  2690.         end
  2691.        
  2692.         function TransparencyController:IsValidPartToModify(part)
  2693.                 if part:IsA('BasePart') or part:IsA('Decal') then
  2694.                         return not self:HasToolAncestor(part)
  2695.                 end
  2696.                 return false
  2697.         end
  2698.        
  2699.         function TransparencyController:CachePartsRecursive(object)
  2700.                 if object then
  2701.                         if self:IsValidPartToModify(object) then
  2702.                                 self.cachedParts[object] = true
  2703.                                 self.transparencyDirty = true
  2704.                         end
  2705.                         for _, child in pairs(object:GetChildren()) do
  2706.                                 self:CachePartsRecursive(child)
  2707.                         end
  2708.                 end
  2709.         end
  2710.        
  2711.         function TransparencyController:TeardownTransparency()
  2712.                 for child, _ in pairs(self.cachedParts) do
  2713.                         child.LocalTransparencyModifier = 0
  2714.                 end
  2715.                 self.cachedParts = {}
  2716.                 self.transparencyDirty = true
  2717.                 self.lastTransparency = nil
  2718.        
  2719.                 if self.descendantAddedConn then
  2720.                         self.descendantAddedConn:disconnect()
  2721.                         self.descendantAddedConn = nil
  2722.                 end
  2723.                 if self.descendantRemovingConn then
  2724.                         self.descendantRemovingConn:disconnect()
  2725.                         self.descendantRemovingConn = nil
  2726.                 end
  2727.                 for object, conn in pairs(self.toolDescendantAddedConns) do
  2728.                         conn:Disconnect()
  2729.                         self.toolDescendantAddedConns[object] = nil
  2730.                 end
  2731.                 for object, conn in pairs(self.toolDescendantRemovingConns) do
  2732.                         conn:Disconnect()
  2733.                         self.toolDescendantRemovingConns[object] = nil
  2734.                 end
  2735.         end
  2736.        
  2737.         function TransparencyController:SetupTransparency(character)
  2738.                 self:TeardownTransparency()
  2739.        
  2740.                 if self.descendantAddedConn then self.descendantAddedConn:disconnect() end
  2741.                 self.descendantAddedConn = character.DescendantAdded:Connect(function(object)
  2742.                         -- This is a part we want to invisify
  2743.                         if self:IsValidPartToModify(object) then
  2744.                                 self.cachedParts[object] = true
  2745.                                 self.transparencyDirty = true
  2746.                         -- There is now a tool under the character
  2747.                         elseif object:IsA('Tool') then
  2748.                                 if self.toolDescendantAddedConns[object] then self.toolDescendantAddedConns[object]:Disconnect() end
  2749.                                 self.toolDescendantAddedConns[object] = object.DescendantAdded:Connect(function(toolChild)
  2750.                                         self.cachedParts[toolChild] = nil
  2751.                                         if toolChild:IsA('BasePart') or toolChild:IsA('Decal') then
  2752.                                                 -- Reset the transparency
  2753.                                                 toolChild.LocalTransparencyModifier = 0
  2754.                                         end
  2755.                                 end)
  2756.                                 if self.toolDescendantRemovingConns[object] then self.toolDescendantRemovingConns[object]:disconnect() end
  2757.                                 self.toolDescendantRemovingConns[object] = object.DescendantRemoving:Connect(function(formerToolChild)
  2758.                                         wait() -- wait for new parent
  2759.                                         if character and formerToolChild and formerToolChild:IsDescendantOf(character) then
  2760.                                                 if self:IsValidPartToModify(formerToolChild) then
  2761.                                                         self.cachedParts[formerToolChild] = true
  2762.                                                         self.transparencyDirty = true
  2763.                                                 end
  2764.                                         end
  2765.                                 end)
  2766.                         end
  2767.                 end)
  2768.                 if self.descendantRemovingConn then self.descendantRemovingConn:disconnect() end
  2769.                 self.descendantRemovingConn = character.DescendantRemoving:connect(function(object)
  2770.                         if self.cachedParts[object] then
  2771.                                 self.cachedParts[object] = nil
  2772.                                 -- Reset the transparency
  2773.                                 object.LocalTransparencyModifier = 0
  2774.                         end
  2775.                 end)
  2776.                 self:CachePartsRecursive(character)
  2777.         end
  2778.        
  2779.        
  2780.         function TransparencyController:Enable(enable)
  2781.                 if self.enabled ~= enable then
  2782.                         self.enabled = enable
  2783.                         self:Update()
  2784.                 end
  2785.         end
  2786.        
  2787.         function TransparencyController:SetSubject(subject)
  2788.                 local character = nil
  2789.                 if subject and subject:IsA("Humanoid") then
  2790.                         character = subject.Parent
  2791.                 end
  2792.                 if subject and subject:IsA("VehicleSeat") and subject.Occupant then
  2793.                         character = subject.Occupant.Parent
  2794.                 end
  2795.                 if character then
  2796.                         self:SetupTransparency(character)
  2797.                 else
  2798.                         self:TeardownTransparency()
  2799.                 end
  2800.         end
  2801.        
  2802.         function TransparencyController:Update()
  2803.                 local instant = false
  2804.                 local now = tick()
  2805.                 local currentCamera = workspace.CurrentCamera
  2806.        
  2807.                 if currentCamera then
  2808.                         local transparency = 0
  2809.                         if not self.enabled then
  2810.                                 instant = true
  2811.                         else
  2812.                                 local distance = (currentCamera.Focus.p - currentCamera.CoordinateFrame.p).magnitude
  2813.                                 transparency = (distance 0 then
  2814.                                                 local ray = Ray.new(hprime, castPoint - hprime)
  2815.                                                 local hit, hitPoint, hitNormal = game.Workspace:FindPartOnRayWithIgnoreList(ray, {self.char}, false, false )
  2816.        
  2817.                                                 if hit then
  2818.                                                         local hprime2 = hitPoint + 0.1 * hitNormal.unit
  2819.                                                         castPoint = hprime2
  2820.                                                 end
  2821.                                         else
  2822.                                                 castPoint = hprime
  2823.                                         end
  2824.                                 else
  2825.                                         castPoint = hprime
  2826.                                 end
  2827.        
  2828.                                 local ray = Ray.new(torsoPoint, (castPoint - torsoPoint))
  2829.                                 local hit, hitPoint, hitNormal = game.Workspace:FindPartOnRayWithIgnoreList(ray, {self.char}, false, false )
  2830.        
  2831.                                 if hit then
  2832.                                         local castPoint2 = hitPoint - 0.1 * (castPoint - torsoPoint).unit
  2833.                                         castPoint = castPoint2
  2834.                                 end
  2835.                         end
  2836.        
  2837.                         castPoints[#castPoints + 1] = castPoint
  2838.                 end
  2839.         end
  2840.        
  2841.         function Invisicam:CheckTorsoReference()
  2842.                 if self.char then
  2843.                         self.torsoPart = self.char:FindFirstChild("Torso")
  2844.                         if not self.torsoPart then
  2845.                                 self.torsoPart = self.char:FindFirstChild("UpperTorso")
  2846.                                 if not self.torsoPart then
  2847.                                         self.torsoPart = self.char:FindFirstChild("HumanoidRootPart")
  2848.                                 end
  2849.                         end
  2850.        
  2851.                         self.headPart = self.char:FindFirstChild("Head")
  2852.                 end
  2853.         end
  2854.        
  2855.         function Invisicam:CharacterAdded(char, player)
  2856.                 -- We only want the LocalPlayer's character
  2857.                 if player~=PlayersService.LocalPlayer then return end
  2858.        
  2859.                 if self.childAddedConn then
  2860.                         self.childAddedConn:Disconnect()
  2861.                         self.childAddedConn = nil
  2862.                 end
  2863.                 if self.childRemovedConn then
  2864.                         self.childRemovedConn:Disconnect()
  2865.                         self.childRemovedConn = nil
  2866.                 end
  2867.        
  2868.                 self.char = char
  2869.        
  2870.                 self.trackedLimbs = {}
  2871.                 local function childAdded(child)
  2872.                         if child:IsA("BasePart") then
  2873.                                 if LIMB_TRACKING_SET[child.Name] then
  2874.                                         self.trackedLimbs[child] = true
  2875.                                 end
  2876.        
  2877.                                 if child.Name == "Torso" or child.Name == "UpperTorso" then
  2878.                                         self.torsoPart = child
  2879.                                 end
  2880.        
  2881.                                 if child.Name == "Head" then
  2882.                                         self.headPart = child
  2883.                                 end
  2884.                         end
  2885.                 end
  2886.        
  2887.                 local function childRemoved(child)
  2888.                         self.trackedLimbs[child] = nil
  2889.        
  2890.                         -- If removed/replaced part is 'Torso' or 'UpperTorso' double check that we still have a TorsoPart to use
  2891.                         self:CheckTorsoReference()
  2892.                 end
  2893.        
  2894.                 self.childAddedConn = char.ChildAdded:Connect(childAdded)
  2895.                 self.childRemovedConn = char.ChildRemoved:Connect(childRemoved)
  2896.                 for _, child in pairs(self.char:GetChildren()) do
  2897.                         childAdded(child)
  2898.                 end
  2899.         end
  2900.        
  2901.         function Invisicam:SetMode(newMode)
  2902.                 AssertTypes(newMode, 'number')
  2903.                 for _, modeNum in pairs(MODE) do
  2904.                         if modeNum == newMode then
  2905.                                 self.mode = newMode
  2906.                                 self.behaviorFunction = self.behaviors[self.mode]
  2907.                                 return
  2908.                         end
  2909.                 end
  2910.                 error("Invalid mode number")
  2911.         end
  2912.        
  2913.         function Invisicam:GetObscuredParts()
  2914.                 return self.savedHits
  2915.         end
  2916.        
  2917.         -- Want to turn off Invisicam? Be sure to call this after.
  2918.         function Invisicam:Cleanup()
  2919.                 for hit, originalFade in pairs(self.savedHits) do
  2920.                         hit.LocalTransparencyModifier = originalFade
  2921.                 end
  2922.         end
  2923.        
  2924.         function Invisicam:Update(dt, desiredCameraCFrame, desiredCameraFocus)
  2925.                 -- Bail if there is no Character
  2926.                 if not self.enabled or not self.char then
  2927.                         return desiredCameraCFrame, desiredCameraFocus
  2928.                 end
  2929.        
  2930.                 self.camera = game.Workspace.CurrentCamera
  2931.        
  2932.                 -- TODO: Move this to a GetHumanoidRootPart helper, probably combine with CheckTorsoReference
  2933.                 -- Make sure we still have a HumanoidRootPart
  2934.                 if not self.humanoidRootPart then
  2935.                         local humanoid = self.char:FindFirstChildOfClass("Humanoid")
  2936.                         if humanoid and humanoid.RootPart then
  2937.                                 self.humanoidRootPart = humanoid.RootPart
  2938.                         else
  2939.                                 -- Not set up with Humanoid? Try and see if there's one in the Character at all:
  2940.                                 self.humanoidRootPart = self.char:FindFirstChild("HumanoidRootPart")
  2941.                                 if not self.humanoidRootPart then
  2942.                                         -- Bail out, since we're relying on HumanoidRootPart existing
  2943.                                         return desiredCameraCFrame, desiredCameraFocus
  2944.                                 end
  2945.                         end
  2946.        
  2947.                         -- TODO: Replace this with something more sensible
  2948.                         local ancestryChangedConn
  2949.                         ancestryChangedConn = self.humanoidRootPart.AncestryChanged:Connect(function(child, parent)
  2950.                                 if child == self.humanoidRootPart and not parent then
  2951.                                         self.humanoidRootPart = nil
  2952.                                         if ancestryChangedConn and ancestryChangedConn.Connected then
  2953.                                                 ancestryChangedConn:Disconnect()
  2954.                                                 ancestryChangedConn = nil
  2955.                                         end
  2956.                                 end
  2957.                         end)
  2958.                 end
  2959.        
  2960.                 if not self.torsoPart then
  2961.                         self:CheckTorsoReference()
  2962.                         if not self.torsoPart then
  2963.                                 -- Bail out, since we're relying on Torso existing, should never happen since we fall back to using HumanoidRootPart as torso
  2964.                                 return desiredCameraCFrame, desiredCameraFocus
  2965.                         end
  2966.                 end
  2967.        
  2968.                 -- Make a list of world points to raycast to
  2969.                 local castPoints = {}
  2970.                 self.behaviorFunction(self, castPoints)
  2971.        
  2972.                 -- Cast to get a list of objects between the camera and the cast points
  2973.                 local currentHits = {}
  2974.                 local ignoreList = {self.char}
  2975.                 local function add(hit)
  2976.                         currentHits[hit] = true
  2977.                         if not self.savedHits[hit] then
  2978.                                 self.savedHits[hit] = hit.LocalTransparencyModifier
  2979.                         end
  2980.                 end
  2981.        
  2982.                 local hitParts
  2983.                 local hitPartCount = 0
  2984.        
  2985.                 -- Hash table to treat head-ray-hit parts differently than the rest of the hit parts hit by other rays
  2986.                 -- head/torso ray hit parts will be more transparent than peripheral parts when USE_STACKING_TRANSPARENCY is enabled
  2987.                 local headTorsoRayHitParts = {}
  2988.        
  2989.                 local perPartTransparencyHeadTorsoHits = TARGET_TRANSPARENCY
  2990.                 local perPartTransparencyOtherHits = TARGET_TRANSPARENCY
  2991.        
  2992.                 if USE_STACKING_TRANSPARENCY then
  2993.        
  2994.                         -- This first call uses head and torso rays to find out how many parts are stacked up
  2995.                         -- for the purpose of calculating required per-part transparency
  2996.                         local headPoint = self.headPart and self.headPart.CFrame.p or castPoints[1]
  2997.                         local torsoPoint = self.torsoPart and self.torsoPart.CFrame.p or castPoints[2]
  2998.                         hitParts = self.camera:GetPartsObscuringTarget({headPoint, torsoPoint}, ignoreList)
  2999.        
  3000.                         -- Count how many things the sample rays passed through, including decals. This should only
  3001.                         -- count decals facing the camera, but GetPartsObscuringTarget does not return surface normals,
  3002.                         -- so my compromise for now is to just let any decal increase the part count by 1. Only one
  3003.                         -- decal per part will be considered.
  3004.                         for i = 1, #hitParts do
  3005.                                 local hitPart = hitParts[i]
  3006.                                 hitPartCount = hitPartCount + 1 -- count the part itself
  3007.                                 headTorsoRayHitParts[hitPart] = true
  3008.                                 for _, child in pairs(hitPart:GetChildren()) do
  3009.                                         if child:IsA('Decal') or child:IsA('Texture') then
  3010.                                                 hitPartCount = hitPartCount + 1 -- count first decal hit, then break
  3011.                                                 break
  3012.                                         end
  3013.                                 end
  3014.                         end
  3015.        
  3016.                         if (hitPartCount > 0) then
  3017.                                 perPartTransparencyHeadTorsoHits = math.pow( ((0.5 * TARGET_TRANSPARENCY) + (0.5 * TARGET_TRANSPARENCY / hitPartCount)), 1 / hitPartCount )
  3018.                                 perPartTransparencyOtherHits = math.pow( ((0.5 * TARGET_TRANSPARENCY_PERIPHERAL) + (0.5 * TARGET_TRANSPARENCY_PERIPHERAL / hitPartCount)), 1 / hitPartCount )
  3019.                         end
  3020.                 end
  3021.        
  3022.                 -- Now get all the parts hit by all the rays
  3023.                 hitParts = self.camera:GetPartsObscuringTarget(castPoints, ignoreList)
  3024.        
  3025.                 local partTargetTransparency = {}
  3026.        
  3027.                 -- Include decals and textures
  3028.                 for i = 1, #hitParts do
  3029.                         local hitPart = hitParts[i]
  3030.        
  3031.                         partTargetTransparency[hitPart] =headTorsoRayHitParts[hitPart] and perPartTransparencyHeadTorsoHits or perPartTransparencyOtherHits
  3032.        
  3033.                         -- If the part is not already as transparent or more transparent than what invisicam requires, add it to the list of
  3034.                         -- parts to be modified by invisicam
  3035.                         if hitPart.Transparency < partTargetTransparency[hitPart] then
  3036.                                 add(hitPart)
  3037.                         end
  3038.        
  3039.                         -- Check all decals and textures on the part
  3040.                         for _, child in pairs(hitPart:GetChildren()) do
  3041.                                 if child:IsA('Decal') or child:IsA('Texture') then
  3042.                                         if (child.Transparency < partTargetTransparency[hitPart]) then
  3043.                                                 partTargetTransparency[child] = partTargetTransparency[hitPart]
  3044.                                                 add(child)
  3045.                                         end
  3046.                                 end
  3047.                         end
  3048.                 end
  3049.        
  3050.                 -- Invisibilize objects that are in the way, restore those that aren't anymore
  3051.                 for hitPart, originalLTM in pairs(self.savedHits) do
  3052.                         if currentHits[hitPart] then
  3053.                                 -- LocalTransparencyModifier gets whatever value is required to print the part's total transparency to equal perPartTransparency
  3054.                                 hitPart.LocalTransparencyModifier = (hitPart.Transparency < 1) and ((partTargetTransparency[hitPart] - hitPart.Transparency) / (1.0 - hitPart.Transparency)) or 0
  3055.                         else -- Restore original pre-invisicam value of LTM
  3056.                                 hitPart.LocalTransparencyModifier = originalLTM
  3057.                                 self.savedHits[hitPart] = nil
  3058.                         end
  3059.                 end
  3060.        
  3061.                 -- Invisicam does not change the camera values
  3062.                 return desiredCameraCFrame, desiredCameraFocus
  3063.         end
  3064.        
  3065.         return Invisicam
  3066. end
  3067.  
  3068. function _LegacyCamera()
  3069.        
  3070.         local ZERO_VECTOR2 = Vector2.new(0,0)
  3071.        
  3072.         local Util = _CameraUtils()
  3073.        
  3074.         --[[ Services ]]--
  3075.         local PlayersService = game:GetService('Players')
  3076.        
  3077.         --[[ The Module ]]--
  3078.         local BaseCamera = _BaseCamera()
  3079.         local LegacyCamera = setmetatable({}, BaseCamera)
  3080.         LegacyCamera.__index = LegacyCamera
  3081.        
  3082.         function LegacyCamera.new()
  3083.                 local self = setmetatable(BaseCamera.new(), LegacyCamera)
  3084.        
  3085.                 self.cameraType = Enum.CameraType.Fixed
  3086.                 self.lastUpdate = tick()
  3087.                 self.lastDistanceToSubject = nil
  3088.        
  3089.                 return self
  3090.         end
  3091.        
  3092.         function LegacyCamera:GetModuleName()
  3093.                 return "LegacyCamera"
  3094.         end
  3095.        
  3096.         --[[ Functions overridden from BaseCamera ]]--
  3097.         function LegacyCamera:SetCameraToSubjectDistance(desiredSubjectDistance)
  3098.                 return BaseCamera.SetCameraToSubjectDistance(self,desiredSubjectDistance)
  3099.         end
  3100.        
  3101.         function LegacyCamera:Update(dt)
  3102.        
  3103.                 -- Cannot update until cameraType has been set
  3104.                 if not self.cameraType then return end
  3105.        
  3106.                 local now = tick()
  3107.                 local timeDelta = (now - self.lastUpdate)
  3108.                 local camera =  workspace.CurrentCamera
  3109.                 local newCameraCFrame = camera.CFrame
  3110.                 local newCameraFocus = camera.Focus
  3111.                 local player = PlayersService.LocalPlayer
  3112.        
  3113.                 if self.lastUpdate == nil or timeDelta > 1 then
  3114.                         self.lastDistanceToSubject = nil
  3115.                 end
  3116.                 local subjectPosition = self:GetSubjectPosition()
  3117.        
  3118.                 if self.cameraType == Enum.CameraType.Fixed then
  3119.                         if self.lastUpdate then
  3120.                                 -- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from
  3121.                                 local delta = math.min(0.1, now - self.lastUpdate)
  3122.                                 local gamepadRotation = self:UpdateGamepad()
  3123.                                 self.rotateInput = self.rotateInput + (gamepadRotation * delta)
  3124.                         end
  3125.        
  3126.                         if subjectPosition and player and camera then
  3127.                                 local distanceToSubject = self:GetCameraToSubjectDistance()
  3128.                                 local newLookVector = self:CalculateNewLookVector()
  3129.                                 self.rotateInput = ZERO_VECTOR2
  3130.        
  3131.                                 newCameraFocus = camera.Focus -- Fixed camera does not change focus
  3132.                                 newCameraCFrame = CFrame.new(camera.CFrame.p, camera.CFrame.p + (distanceToSubject * newLookVector))
  3133.                         end
  3134.                 elseif self.cameraType == Enum.CameraType.Attach then
  3135.                         if subjectPosition and camera then
  3136.                                 local distanceToSubject = self:GetCameraToSubjectDistance()
  3137.                                 local humanoid = self:GetHumanoid()
  3138.                                 if self.lastUpdate and humanoid and humanoid.RootPart then
  3139.        
  3140.                                         -- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from
  3141.                                         local delta = math.min(0.1, now - self.lastUpdate)
  3142.                                         local gamepadRotation = self:UpdateGamepad()
  3143.                                         self.rotateInput = self.rotateInput + (gamepadRotation * delta)
  3144.        
  3145.                                         local forwardVector = humanoid.RootPart.CFrame.lookVector
  3146.        
  3147.                                         local y = Util.GetAngleBetweenXZVectors(forwardVector, self:GetCameraLookVector())
  3148.                                         if Util.IsFinite(y) then
  3149.                                                 -- Preserve vertical rotation from user input
  3150.                                                 self.rotateInput = Vector2.new(y, self.rotateInput.Y)
  3151.                                         end
  3152.                                 end
  3153.        
  3154.                                 local newLookVector = self:CalculateNewLookVector()
  3155.                                 self.rotateInput = ZERO_VECTOR2
  3156.        
  3157.                                 newCameraFocus = CFrame.new(subjectPosition)
  3158.                                 newCameraCFrame = CFrame.new(subjectPosition - (distanceToSubject * newLookVector), subjectPosition)
  3159.                         end
  3160.                 elseif self.cameraType == Enum.CameraType.Watch then
  3161.                         if subjectPosition and player and camera then
  3162.                                 local cameraLook = nil
  3163.        
  3164.                                 local humanoid = self:GetHumanoid()
  3165.                                 if humanoid and humanoid.RootPart then
  3166.                                         local diffVector = subjectPosition - camera.CFrame.p
  3167.                                         cameraLook = diffVector.unit
  3168.        
  3169.                                         if self.lastDistanceToSubject and self.lastDistanceToSubject == self:GetCameraToSubjectDistance() then
  3170.                                                 -- Don't clobber the zoom if they zoomed the camera
  3171.                                                 local newDistanceToSubject = diffVector.magnitude
  3172.                                                 self:SetCameraToSubjectDistance(newDistanceToSubject)
  3173.                                         end
  3174.                                 end
  3175.        
  3176.                                 local distanceToSubject = self:GetCameraToSubjectDistance()
  3177.                                 local newLookVector = self:CalculateNewLookVector(cameraLook)
  3178.                                 self.rotateInput = ZERO_VECTOR2
  3179.        
  3180.                                 newCameraFocus = CFrame.new(subjectPosition)
  3181.                                 newCameraCFrame = CFrame.new(subjectPosition - (distanceToSubject * newLookVector), subjectPosition)
  3182.        
  3183.                                 self.lastDistanceToSubject = distanceToSubject
  3184.                         end
  3185.                 else
  3186.                         -- Unsupported type, return current values unchanged
  3187.                         return camera.CFrame, camera.Focus
  3188.                 end
  3189.        
  3190.                 self.lastUpdate = now
  3191.                 return newCameraCFrame, newCameraFocus
  3192.         end
  3193.        
  3194.         return LegacyCamera
  3195. end
  3196.  
  3197. function _OrbitalCamera()
  3198.        
  3199.         -- Local private variables and constants
  3200.         local UNIT_Z = Vector3.new(0,0,1)
  3201.         local X1_Y0_Z1 = Vector3.new(1,0,1)     --Note: not a unit vector, used for projecting onto XZ plane
  3202.         local ZERO_VECTOR3 = Vector3.new(0,0,0)
  3203.         local ZERO_VECTOR2 = Vector2.new(0,0)
  3204.         local TAU = 2 * math.pi
  3205.        
  3206.         --[[ Gamepad Support ]]--
  3207.         local THUMBSTICK_DEADZONE = 0.2
  3208.        
  3209.         -- Do not edit these values, they are not the developer-set limits, they are limits
  3210.         -- to the values the camera system equations can correctly handle
  3211.         local MIN_ALLOWED_ELEVATION_DEG = -80
  3212.         local MAX_ALLOWED_ELEVATION_DEG = 80
  3213.        
  3214.         local externalProperties = {}
  3215.         externalProperties["InitialDistance"]  = 25
  3216.         externalProperties["MinDistance"]      = 10
  3217.         externalProperties["MaxDistance"]      = 100
  3218.         externalProperties["InitialElevation"] = 35
  3219.         externalProperties["MinElevation"]     = 35
  3220.         externalProperties["MaxElevation"]     = 35
  3221.         externalProperties["ReferenceAzimuth"] = -45    -- Angle around the Y axis where the camera starts. -45 offsets the camera in the -X and +Z directions equally
  3222.         externalProperties["CWAzimuthTravel"]  = 90     -- How many degrees the camera is allowed to rotate from the reference position, CW as seen from above
  3223.         externalProperties["CCWAzimuthTravel"] = 90     -- How many degrees the camera is allowed to rotate from the reference position, CCW as seen from above
  3224.         externalProperties["UseAzimuthLimits"] = false -- Full rotation around Y axis available by default
  3225.        
  3226.         local Util = _CameraUtils()
  3227.        
  3228.         --[[ Services ]]--
  3229.         local PlayersService = game:GetService('Players')
  3230.         local VRService = game:GetService("VRService")
  3231.        
  3232.         --[[ The Module ]]--
  3233.         local BaseCamera = _BaseCamera()
  3234.         local OrbitalCamera = setmetatable({}, BaseCamera)
  3235.         OrbitalCamera.__index = OrbitalCamera
  3236.        
  3237.        
  3238.         function OrbitalCamera.new()
  3239.                 local self = setmetatable(BaseCamera.new(), OrbitalCamera)
  3240.        
  3241.                 self.lastUpdate = tick()
  3242.        
  3243.                 -- OrbitalCamera-specific members
  3244.                 self.changedSignalConnections = {}
  3245.                 self.refAzimuthRad = nil
  3246.                 self.curAzimuthRad = nil
  3247.                 self.minAzimuthAbsoluteRad = nil
  3248.                 self.maxAzimuthAbsoluteRad = nil
  3249.                 self.useAzimuthLimits = nil
  3250.                 self.curElevationRad = nil
  3251.                 self.minElevationRad = nil
  3252.                 self.maxElevationRad = nil
  3253.                 self.curDistance = nil
  3254.                 self.minDistance = nil
  3255.                 self.maxDistance = nil
  3256.        
  3257.                 -- Gamepad
  3258.                 self.r3ButtonDown = false
  3259.                 self.l3ButtonDown = false
  3260.                 self.gamepadDollySpeedMultiplier = 1
  3261.        
  3262.                 self.lastUserPanCamera = tick()
  3263.        
  3264.                 self.externalProperties = {}
  3265.                 self.externalProperties["InitialDistance"]      = 25
  3266.                 self.externalProperties["MinDistance"]          = 10
  3267.                 self.externalProperties["MaxDistance"]          = 100
  3268.                 self.externalProperties["InitialElevation"]     = 35
  3269.                 self.externalProperties["MinElevation"]                 = 35
  3270.                 self.externalProperties["MaxElevation"]                 = 35
  3271.                 self.externalProperties["ReferenceAzimuth"]     = -45   -- Angle around the Y axis where the camera starts. -45 offsets the camera in the -X and +Z directions equally
  3272.                 self.externalProperties["CWAzimuthTravel"]      = 90    -- How many degrees the camera is allowed to rotate from the reference position, CW as seen from above
  3273.                 self.externalProperties["CCWAzimuthTravel"]     = 90    -- How many degrees the camera is allowed to rotate from the reference position, CCW as seen from above
  3274.                 self.externalProperties["UseAzimuthLimits"]     = false -- Full rotation around Y axis available by default
  3275.                 self:LoadNumberValueParameters()
  3276.        
  3277.                 return self
  3278.         end
  3279.        
  3280.         function OrbitalCamera:LoadOrCreateNumberValueParameter(name, valueType, updateFunction)
  3281.                 local valueObj = script:FindFirstChild(name)
  3282.        
  3283.                 if valueObj and valueObj:isA(valueType) then
  3284.                         -- Value object exists and is the correct type, use its value
  3285.                         self.externalProperties[name] = valueObj.Value
  3286.                 elseif self.externalProperties[name] ~= nil then
  3287.                         -- Create missing (or replace incorrectly-typed) valueObject with default value
  3288.                         valueObj = Instance.new(valueType)
  3289.                         valueObj.Name = name
  3290.                         valueObj.Parent = script
  3291.                         valueObj.Value = self.externalProperties[name]
  3292.                 else
  3293.                         print("externalProperties table has no entry for ",name)
  3294.                         return
  3295.                 end
  3296.        
  3297.                 if updateFunction then
  3298.                         if self.changedSignalConnections[name] then
  3299.                                 self.changedSignalConnections[name]:Disconnect()
  3300.                         end
  3301.                         self.changedSignalConnections[name] = valueObj.Changed:Connect(function(newValue)
  3302.                                 self.externalProperties[name] = newValue
  3303.                                 updateFunction(self)
  3304.                         end)
  3305.                 end
  3306.         end
  3307.        
  3308.         function OrbitalCamera:SetAndBoundsCheckAzimuthValues()
  3309.                 self.minAzimuthAbsoluteRad = math.rad(self.externalProperties["ReferenceAzimuth"]) - math.abs(math.rad(self.externalProperties["CWAzimuthTravel"]))
  3310.                 self.maxAzimuthAbsoluteRad = math.rad(self.externalProperties["ReferenceAzimuth"]) + math.abs(math.rad(self.externalProperties["CCWAzimuthTravel"]))
  3311.                 self.useAzimuthLimits = self.externalProperties["UseAzimuthLimits"]
  3312.                 if self.useAzimuthLimits then
  3313.                         self.curAzimuthRad = math.max(self.curAzimuthRad, self.minAzimuthAbsoluteRad)
  3314.                         self.curAzimuthRad = math.min(self.curAzimuthRad, self.maxAzimuthAbsoluteRad)
  3315.                 end
  3316.         end
  3317.        
  3318.         function OrbitalCamera:SetAndBoundsCheckElevationValues()
  3319.                 -- These degree values are the direct user input values. It is deliberate that they are
  3320.                 -- ranged checked only against the extremes, and not against each other. Any time one
  3321.                 -- is changed, both of the internal values in radians are recalculated. This allows for
  3322.                 -- A developer to change the values in any order and for the end results to be that the
  3323.                 -- internal values adjust to match intent as best as possible.
  3324.                 local minElevationDeg = math.max(self.externalProperties["MinElevation"], MIN_ALLOWED_ELEVATION_DEG)
  3325.                 local maxElevationDeg = math.min(self.externalProperties["MaxElevation"], MAX_ALLOWED_ELEVATION_DEG)
  3326.        
  3327.                 -- Set internal values in radians
  3328.                 self.minElevationRad = math.rad(math.min(minElevationDeg, maxElevationDeg))
  3329.                 self.maxElevationRad = math.rad(math.max(minElevationDeg, maxElevationDeg))
  3330.                 self.curElevationRad = math.max(self.curElevationRad, self.minElevationRad)
  3331.                 self.curElevationRad = math.min(self.curElevationRad, self.maxElevationRad)
  3332.         end
  3333.        
  3334.         function OrbitalCamera:SetAndBoundsCheckDistanceValues()
  3335.                 self.minDistance = self.externalProperties["MinDistance"]
  3336.                 self.maxDistance = self.externalProperties["MaxDistance"]
  3337.                 self.curDistance = math.max(self.curDistance, self.minDistance)
  3338.                 self.curDistance = math.min(self.curDistance, self.maxDistance)
  3339.         end
  3340.        
  3341.         -- This loads from, or lazily creates, NumberValue objects for exposed parameters
  3342.         function OrbitalCamera:LoadNumberValueParameters()
  3343.                 -- These initial values do not require change listeners since they are read only once
  3344.                 self:LoadOrCreateNumberValueParameter("InitialElevation", "NumberValue", nil)
  3345.                 self:LoadOrCreateNumberValueParameter("InitialDistance", "NumberValue", nil)
  3346.        
  3347.                 -- Note: ReferenceAzimuth is also used as an initial value, but needs a change listener because it is used in the calculation of the limits
  3348.                 self:LoadOrCreateNumberValueParameter("ReferenceAzimuth", "NumberValue", self.SetAndBoundsCheckAzimuthValue)
  3349.                 self:LoadOrCreateNumberValueParameter("CWAzimuthTravel", "NumberValue", self.SetAndBoundsCheckAzimuthValues)
  3350.                 self:LoadOrCreateNumberValueParameter("CCWAzimuthTravel", "NumberValue", self.SetAndBoundsCheckAzimuthValues)
  3351.                 self:LoadOrCreateNumberValueParameter("MinElevation", "NumberValue", self.SetAndBoundsCheckElevationValues)
  3352.                 self:LoadOrCreateNumberValueParameter("MaxElevation", "NumberValue", self.SetAndBoundsCheckElevationValues)
  3353.                 self:LoadOrCreateNumberValueParameter("MinDistance", "NumberValue", self.SetAndBoundsCheckDistanceValues)
  3354.                 self:LoadOrCreateNumberValueParameter("MaxDistance", "NumberValue", self.SetAndBoundsCheckDistanceValues)
  3355.                 self:LoadOrCreateNumberValueParameter("UseAzimuthLimits", "BoolValue", self.SetAndBoundsCheckAzimuthValues)
  3356.        
  3357.                 -- Internal values set (in radians, from degrees), plus sanitization
  3358.                 self.curAzimuthRad = math.rad(self.externalProperties["ReferenceAzimuth"])
  3359.                 self.curElevationRad = math.rad(self.externalProperties["InitialElevation"])
  3360.                 self.curDistance = self.externalProperties["InitialDistance"]
  3361.        
  3362.                 self:SetAndBoundsCheckAzimuthValues()
  3363.                 self:SetAndBoundsCheckElevationValues()
  3364.                 self:SetAndBoundsCheckDistanceValues()
  3365.         end
  3366.        
  3367.         function OrbitalCamera:GetModuleName()
  3368.                 return "OrbitalCamera"
  3369.         end
  3370.        
  3371.         function OrbitalCamera:SetInitialOrientation(humanoid)
  3372.                 if not humanoid or not humanoid.RootPart then
  3373.                         warn("OrbitalCamera could not set initial orientation due to missing humanoid")
  3374.                         return
  3375.                 end
  3376.                 local newDesiredLook = (humanoid.RootPart.CFrame.lookVector - Vector3.new(0,0.23,0)).unit
  3377.                 local horizontalShift = Util.GetAngleBetweenXZVectors(newDesiredLook, self:GetCameraLookVector())
  3378.                 local vertShift = math.asin(self:GetCameraLookVector().y) - math.asin(newDesiredLook.y)
  3379.                 if not Util.IsFinite(horizontalShift) then
  3380.                         horizontalShift = 0
  3381.                 end
  3382.                 if not Util.IsFinite(vertShift) then
  3383.                         vertShift = 0
  3384.                 end
  3385.                 self.rotateInput = Vector2.new(horizontalShift, vertShift)
  3386.         end
  3387.        
  3388.         --[[ Functions of BaseCamera that are overridden by OrbitalCamera ]]--
  3389.         function OrbitalCamera:GetCameraToSubjectDistance()
  3390.                 return self.curDistance
  3391.         end
  3392.        
  3393.         function OrbitalCamera:SetCameraToSubjectDistance(desiredSubjectDistance)
  3394.                 print("OrbitalCamera SetCameraToSubjectDistance ",desiredSubjectDistance)
  3395.                 local player = PlayersService.LocalPlayer
  3396.                 if player then
  3397.                         self.currentSubjectDistance = math.clamp(desiredSubjectDistance, self.minDistance, self.maxDistance)
  3398.        
  3399.                         -- OrbitalCamera is not allowed to go into the first-person range
  3400.                         self.currentSubjectDistance = math.max(self.currentSubjectDistance, self.FIRST_PERSON_DISTANCE_THRESHOLD)
  3401.                 end
  3402.                 self.inFirstPerson = false
  3403.                 self:UpdateMouseBehavior()
  3404.                 return self.currentSubjectDistance
  3405.         end
  3406.        
  3407.         function OrbitalCamera:CalculateNewLookVector(suppliedLookVector, xyRotateVector)
  3408.                 local currLookVector = suppliedLookVector or self:GetCameraLookVector()
  3409.                 local currPitchAngle = math.asin(currLookVector.y)
  3410.                 local yTheta = math.clamp(xyRotateVector.y, currPitchAngle - math.rad(MAX_ALLOWED_ELEVATION_DEG), currPitchAngle - math.rad(MIN_ALLOWED_ELEVATION_DEG))
  3411.                 local constrainedRotateInput = Vector2.new(xyRotateVector.x, yTheta)
  3412.                 local startCFrame = CFrame.new(ZERO_VECTOR3, currLookVector)
  3413.                 local newLookVector = (CFrame.Angles(0, -constrainedRotateInput.x, 0) * startCFrame * CFrame.Angles(-constrainedRotateInput.y,0,0)).lookVector
  3414.                 return newLookVector
  3415.         end
  3416.        
  3417.         function OrbitalCamera:GetGamepadPan(name, state, input)
  3418.                 if input.UserInputType == self.activeGamepad and input.KeyCode == Enum.KeyCode.Thumbstick2 then
  3419.                         if self.r3ButtonDown or self.l3ButtonDown then
  3420.                         -- R3 or L3 Thumbstick is depressed, right stick controls dolly in/out
  3421.                                 if (input.Position.Y > THUMBSTICK_DEADZONE) then
  3422.                                         self.gamepadDollySpeedMultiplier = 0.96
  3423.                                 elseif (input.Position.Y < -THUMBSTICK_DEADZONE) then
  3424.                                         self.gamepadDollySpeedMultiplier = 1.04
  3425.                                 else
  3426.                                         self.gamepadDollySpeedMultiplier = 1.00
  3427.                                 end
  3428.                         else
  3429.                                 if state == Enum.UserInputState.Cancel then
  3430.                                         self.gamepadPanningCamera = ZERO_VECTOR2
  3431.                                         return
  3432.                                 end
  3433.        
  3434.                                 local inputVector = Vector2.new(input.Position.X, -input.Position.Y)
  3435.                                 if inputVector.magnitude > THUMBSTICK_DEADZONE then
  3436.                                         self.gamepadPanningCamera = Vector2.new(input.Position.X, -input.Position.Y)
  3437.                                 else
  3438.                                         self.gamepadPanningCamera = ZERO_VECTOR2
  3439.                                 end
  3440.                         end
  3441.                         return Enum.ContextActionResult.Sink
  3442.                 end
  3443.                 return Enum.ContextActionResult.Pass
  3444.         end
  3445.        
  3446.         function OrbitalCamera:DoGamepadZoom(name, state, input)
  3447.                 if input.UserInputType == self.activeGamepad and (input.KeyCode == Enum.KeyCode.ButtonR3 or input.KeyCode == Enum.KeyCode.ButtonL3) then
  3448.                         if (state == Enum.UserInputState.Begin) then
  3449.                                 self.r3ButtonDown = input.KeyCode == Enum.KeyCode.ButtonR3
  3450.                                 self.l3ButtonDown = input.KeyCode == Enum.KeyCode.ButtonL3
  3451.                         elseif (state == Enum.UserInputState.End) then
  3452.                                 if (input.KeyCode == Enum.KeyCode.ButtonR3) then
  3453.                                         self.r3ButtonDown = false
  3454.                                 elseif (input.KeyCode == Enum.KeyCode.ButtonL3) then
  3455.                                         self.l3ButtonDown = false
  3456.                                 end
  3457.                                 if (not self.r3ButtonDown) and (not self.l3ButtonDown) then
  3458.                                         self.gamepadDollySpeedMultiplier = 1.00
  3459.                                 end
  3460.                         end
  3461.                         return Enum.ContextActionResult.Sink
  3462.                 end
  3463.                 return Enum.ContextActionResult.Pass
  3464.         end
  3465.        
  3466.         function OrbitalCamera:BindGamepadInputActions()
  3467.                 self:BindAction("OrbitalCamGamepadPan", function(name, state, input) return self:GetGamepadPan(name, state, input) end,
  3468.                         false, Enum.KeyCode.Thumbstick2)
  3469.                 self:BindAction("OrbitalCamGamepadZoom", function(name, state, input) return self:DoGamepadZoom(name, state, input) end,
  3470.                         false, Enum.KeyCode.ButtonR3, Enum.KeyCode.ButtonL3)
  3471.         end
  3472.        
  3473.        
  3474.         -- [[ Update ]]--
  3475.         function OrbitalCamera:Update(dt)
  3476.                 local now = tick()
  3477.                 local timeDelta = (now - self.lastUpdate)
  3478.                 local userPanningTheCamera = (self.UserPanningTheCamera == true)
  3479.                 local camera =  workspace.CurrentCamera
  3480.                 local newCameraCFrame = camera.CFrame
  3481.                 local newCameraFocus = camera.Focus
  3482.                 local player = PlayersService.LocalPlayer
  3483.                 local cameraSubject = camera and camera.CameraSubject
  3484.                 local isInVehicle = cameraSubject and cameraSubject:IsA('VehicleSeat')
  3485.                 local isOnASkateboard = cameraSubject and cameraSubject:IsA('SkateboardPlatform')
  3486.        
  3487.                 if self.lastUpdate == nil or timeDelta > 1 then
  3488.                         self.lastCameraTransform = nil
  3489.                 end
  3490.        
  3491.                 if self.lastUpdate then
  3492.                         local gamepadRotation = self:UpdateGamepad()
  3493.        
  3494.                         if self:ShouldUseVRRotation() then
  3495.                                 self.RotateInput = self.RotateInput + self:GetVRRotationInput()
  3496.                         else
  3497.                                 -- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from
  3498.                                 local delta = math.min(0.1, timeDelta)
  3499.        
  3500.                                 if gamepadRotation ~= ZERO_VECTOR2 then
  3501.                                         userPanningTheCamera = true
  3502.                                         self.rotateInput = self.rotateInput + (gamepadRotation * delta)
  3503.                                 end
  3504.        
  3505.                                 local angle = 0
  3506.                                 if not (isInVehicle or isOnASkateboard) then
  3507.                                         angle = angle + (self.TurningLeft and -120 or 0)
  3508.                                         angle = angle + (self.TurningRight and 120 or 0)
  3509.                                 end
  3510.        
  3511.                                 if angle ~= 0 then
  3512.                                         self.rotateInput = self.rotateInput +  Vector2.new(math.rad(angle * delta), 0)
  3513.                                         userPanningTheCamera = true
  3514.                                 end
  3515.                         end
  3516.                 end
  3517.        
  3518.                 -- Reset tween speed if user is panning
  3519.                 if userPanningTheCamera then
  3520.                         self.lastUserPanCamera = tick()
  3521.                 end
  3522.        
  3523.                 local subjectPosition = self:GetSubjectPosition()
  3524.        
  3525.                 if subjectPosition and player and camera then
  3526.        
  3527.                         -- Process any dollying being done by gamepad
  3528.                         -- TODO: Move this
  3529.                         if self.gamepadDollySpeedMultiplier ~= 1 then
  3530.                                 self:SetCameraToSubjectDistance(self.currentSubjectDistance * self.gamepadDollySpeedMultiplier)
  3531.                         end
  3532.        
  3533.                         local VREnabled = VRService.VREnabled
  3534.                         newCameraFocus = VREnabled and self:GetVRFocus(subjectPosition, timeDelta) or CFrame.new(subjectPosition)
  3535.        
  3536.                         local cameraFocusP = newCameraFocus.p
  3537.                         if VREnabled and not self:IsInFirstPerson() then
  3538.                                 local cameraHeight = self:GetCameraHeight()
  3539.                                 local vecToSubject = (subjectPosition - camera.CFrame.p)
  3540.                                 local distToSubject = vecToSubject.magnitude
  3541.        
  3542.                                 -- Only move the camera if it exceeded a maximum distance to the subject in VR
  3543.                                 if distToSubject > self.currentSubjectDistance or self.rotateInput.x ~= 0 then
  3544.                                         local desiredDist = math.min(distToSubject, self.currentSubjectDistance)
  3545.        
  3546.                                         -- Note that CalculateNewLookVector is overridden from BaseCamera
  3547.                                         vecToSubject = self:CalculateNewLookVector(vecToSubject.unit * X1_Y0_Z1, Vector2.new(self.rotateInput.x, 0)) * desiredDist
  3548.        
  3549.                                         local newPos = cameraFocusP - vecToSubject
  3550.                                         local desiredLookDir = camera.CFrame.lookVector
  3551.                                         if self.rotateInput.x ~= 0 then
  3552.                                                 desiredLookDir = vecToSubject
  3553.                                         end
  3554.                                         local lookAt = Vector3.new(newPos.x + desiredLookDir.x, newPos.y, newPos.z + desiredLookDir.z)
  3555.                                         self.RotateInput = ZERO_VECTOR2
  3556.        
  3557.                                         newCameraCFrame = CFrame.new(newPos, lookAt) + Vector3.new(0, cameraHeight, 0)
  3558.                                 end
  3559.                         else
  3560.                                 -- self.RotateInput is a Vector2 of mouse movement deltas since last update
  3561.                                 self.curAzimuthRad = self.curAzimuthRad - self.rotateInput.x
  3562.        
  3563.                                 if self.useAzimuthLimits then
  3564.                                         self.curAzimuthRad = math.clamp(self.curAzimuthRad, self.minAzimuthAbsoluteRad, self.maxAzimuthAbsoluteRad)
  3565.                                 else
  3566.                                         self.curAzimuthRad = (self.curAzimuthRad ~= 0) and (math.sign(self.curAzimuthRad) * (math.abs(self.curAzimuthRad) % TAU)) or 0
  3567.                                 end
  3568.        
  3569.                                 self.curElevationRad = math.clamp(self.curElevationRad + self.rotateInput.y, self.minElevationRad, self.maxElevationRad)
  3570.        
  3571.                                 local cameraPosVector = self.currentSubjectDistance * ( CFrame.fromEulerAnglesYXZ( -self.curElevationRad, self.curAzimuthRad, 0 ) * UNIT_Z )
  3572.                                 local camPos = subjectPosition + cameraPosVector
  3573.        
  3574.                                 newCameraCFrame = CFrame.new(camPos, subjectPosition)
  3575.        
  3576.                                 self.rotateInput = ZERO_VECTOR2
  3577.                         end
  3578.        
  3579.                         self.lastCameraTransform = newCameraCFrame
  3580.                         self.lastCameraFocus = newCameraFocus
  3581.                         if (isInVehicle or isOnASkateboard) and cameraSubject:IsA('BasePart') then
  3582.                                 self.lastSubjectCFrame = cameraSubject.CFrame
  3583.                         else
  3584.                                 self.lastSubjectCFrame = nil
  3585.                         end
  3586.                 end
  3587.        
  3588.                 self.lastUpdate = now
  3589.                 return newCameraCFrame, newCameraFocus
  3590.         end
  3591.        
  3592.         return OrbitalCamera
  3593. end
  3594.  
  3595. function _ClassicCamera()
  3596.        
  3597.         -- Local private variables and constants
  3598.         local ZERO_VECTOR2 = Vector2.new(0,0)
  3599.        
  3600.         local tweenAcceleration = math.rad(220)         --Radians/Second^2
  3601.         local tweenSpeed = math.rad(0)                          --Radians/Second
  3602.         local tweenMaxSpeed = math.rad(250)                     --Radians/Second
  3603.         local TIME_BEFORE_AUTO_ROTATE = 2.0             --Seconds, used when auto-aligning camera with vehicles
  3604.        
  3605.         local INITIAL_CAMERA_ANGLE = CFrame.fromOrientation(math.rad(-15), 0, 0)
  3606.        
  3607.         local FFlagUserCameraToggle do
  3608.                 local success, result = pcall(function()
  3609.                         return UserSettings():IsUserFeatureEnabled("UserCameraToggle")
  3610.                 end)
  3611.                 FFlagUserCameraToggle = success and result
  3612.         end
  3613.        
  3614.         --[[ Services ]]--
  3615.         local PlayersService = game:GetService('Players')
  3616.         local VRService = game:GetService("VRService")
  3617.        
  3618.         local CameraInput = _CameraInput()
  3619.         local Util = _CameraUtils()
  3620.        
  3621.         --[[ The Module ]]--
  3622.         local BaseCamera = _BaseCamera()
  3623.         local ClassicCamera = setmetatable({}, BaseCamera)
  3624.         ClassicCamera.__index = ClassicCamera
  3625.        
  3626.         function ClassicCamera.new()
  3627.                 local self = setmetatable(BaseCamera.new(), ClassicCamera)
  3628.        
  3629.                 self.isFollowCamera = false
  3630.                 self.isCameraToggle = false
  3631.                 self.lastUpdate = tick()
  3632.                 self.cameraToggleSpring = Util.Spring.new(5, 0)
  3633.        
  3634.                 return self
  3635.         end
  3636.        
  3637.         function ClassicCamera:GetCameraToggleOffset(dt)
  3638.                 assert(FFlagUserCameraToggle)
  3639.        
  3640.                 if self.isCameraToggle then
  3641.                         local zoom = self.currentSubjectDistance
  3642.        
  3643.                         if CameraInput.getTogglePan() then
  3644.                                 self.cameraToggleSpring.goal = math.clamp(Util.map(zoom, 0.5, self.FIRST_PERSON_DISTANCE_THRESHOLD, 0, 1), 0, 1)
  3645.                         else
  3646.                                 self.cameraToggleSpring.goal = 0
  3647.                         end
  3648.        
  3649.                         local distanceOffset = math.clamp(Util.map(zoom, 0.5, 64, 0, 1), 0, 1) + 1
  3650.                         return Vector3.new(0, self.cameraToggleSpring:step(dt)*distanceOffset, 0)
  3651.                 end
  3652.        
  3653.                 return Vector3.new()
  3654.         end
  3655.        
  3656.         -- Movement mode standardized to Enum.ComputerCameraMovementMode values
  3657.         function ClassicCamera:SetCameraMovementMode(cameraMovementMode)
  3658.                 BaseCamera.SetCameraMovementMode(self, cameraMovementMode)
  3659.        
  3660.                 self.isFollowCamera = cameraMovementMode == Enum.ComputerCameraMovementMode.Follow
  3661.                 self.isCameraToggle = cameraMovementMode == Enum.ComputerCameraMovementMode.CameraToggle
  3662.         end
  3663.        
  3664.         function ClassicCamera:Update()
  3665.                 local now = tick()
  3666.                 local timeDelta = now - self.lastUpdate
  3667.        
  3668.                 local camera = workspace.CurrentCamera
  3669.                 local newCameraCFrame = camera.CFrame
  3670.                 local newCameraFocus = camera.Focus
  3671.        
  3672.                 local overrideCameraLookVector = nil
  3673.                 if self.resetCameraAngle then
  3674.                         local rootPart = self:GetHumanoidRootPart()
  3675.                         if rootPart then
  3676.                                 overrideCameraLookVector = (rootPart.CFrame * INITIAL_CAMERA_ANGLE).lookVector
  3677.                         else
  3678.                                 overrideCameraLookVector = INITIAL_CAMERA_ANGLE.lookVector
  3679.                         end
  3680.                         self.resetCameraAngle = false
  3681.                 end
  3682.        
  3683.                 local player = PlayersService.LocalPlayer
  3684.                 local humanoid = self:GetHumanoid()
  3685.                 local cameraSubject = camera.CameraSubject
  3686.                 local isInVehicle = cameraSubject and cameraSubject:IsA('VehicleSeat')
  3687.                 local isOnASkateboard = cameraSubject and cameraSubject:IsA('SkateboardPlatform')
  3688.                 local isClimbing = humanoid and humanoid:GetState() == Enum.HumanoidStateType.Climbing
  3689.        
  3690.                 if self.lastUpdate == nil or timeDelta > 1 then
  3691.                         self.lastCameraTransform = nil
  3692.                 end
  3693.        
  3694.                 if self.lastUpdate then
  3695.                         local gamepadRotation = self:UpdateGamepad()
  3696.        
  3697.                         if self:ShouldUseVRRotation() then
  3698.                                 self.rotateInput = self.rotateInput + self:GetVRRotationInput()
  3699.                         else
  3700.                                 -- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from
  3701.                                 local delta = math.min(0.1, timeDelta)
  3702.        
  3703.                                 if gamepadRotation ~= ZERO_VECTOR2 then
  3704.                                         self.rotateInput = self.rotateInput + (gamepadRotation * delta)
  3705.                                 end
  3706.        
  3707.                                 local angle = 0
  3708.                                 if not (isInVehicle or isOnASkateboard) then
  3709.                                         angle = angle + (self.turningLeft and -120 or 0)
  3710.                                         angle = angle + (self.turningRight and 120 or 0)
  3711.                                 end
  3712.        
  3713.                                 if angle ~= 0 then
  3714.                                         self.rotateInput = self.rotateInput +  Vector2.new(math.rad(angle * delta), 0)
  3715.                                 end
  3716.                         end
  3717.                 end
  3718.        
  3719.                 local cameraHeight = self:GetCameraHeight()
  3720.        
  3721.                 -- Reset tween speed if user is panning
  3722.                 if self.userPanningTheCamera then
  3723.                         tweenSpeed = 0
  3724.                         self.lastUserPanCamera = tick()
  3725.                 end
  3726.        
  3727.                 local userRecentlyPannedCamera = now - self.lastUserPanCamera < TIME_BEFORE_AUTO_ROTATE
  3728.                 local subjectPosition = self:GetSubjectPosition()
  3729.        
  3730.                 if subjectPosition and player and camera then
  3731.                         local zoom = self:GetCameraToSubjectDistance()
  3732.                         if zoom < 0.5 then
  3733.                                 zoom = 0.5
  3734.                         end
  3735.        
  3736.                         if self:GetIsMouseLocked() and not self:IsInFirstPerson() then
  3737.                                 -- We need to use the right vector of the camera after rotation, not before
  3738.                                 local newLookCFrame = self:CalculateNewLookCFrame(overrideCameraLookVector)
  3739.        
  3740.                                 local offset = self:GetMouseLockOffset()
  3741.                                 local cameraRelativeOffset = offset.X * newLookCFrame.rightVector + offset.Y * newLookCFrame.upVector + offset.Z * newLookCFrame.lookVector
  3742.        
  3743.                                 --offset can be NAN, NAN, NAN if newLookVector has only y component
  3744.                                 if Util.IsFiniteVector3(cameraRelativeOffset) then
  3745.                                         subjectPosition = subjectPosition + cameraRelativeOffset
  3746.                                 end
  3747.                         else
  3748.                                 if not self.userPanningTheCamera and self.lastCameraTransform then
  3749.        
  3750.                                         local isInFirstPerson = self:IsInFirstPerson()
  3751.        
  3752.                                         if (isInVehicle or isOnASkateboard or (self.isFollowCamera and isClimbing)) and self.lastUpdate and humanoid and humanoid.Torso then
  3753.                                                 if isInFirstPerson then
  3754.                                                         if self.lastSubjectCFrame and (isInVehicle or isOnASkateboard) and cameraSubject:IsA('BasePart') then
  3755.                                                                 local y = -Util.GetAngleBetweenXZVectors(self.lastSubjectCFrame.lookVector, cameraSubject.CFrame.lookVector)
  3756.                                                                 if Util.IsFinite(y) then
  3757.                                                                         self.rotateInput = self.rotateInput + Vector2.new(y, 0)
  3758.                                                                 end
  3759.                                                                 tweenSpeed = 0
  3760.                                                         end
  3761.                                                 elseif not userRecentlyPannedCamera then
  3762.                                                         local forwardVector = humanoid.Torso.CFrame.lookVector
  3763.                                                         if isOnASkateboard then
  3764.                                                                 forwardVector = cameraSubject.CFrame.lookVector
  3765.                                                         end
  3766.        
  3767.                                                         tweenSpeed = math.clamp(tweenSpeed + tweenAcceleration * timeDelta, 0, tweenMaxSpeed)
  3768.        
  3769.                                                         local percent = math.clamp(tweenSpeed * timeDelta, 0, 1)
  3770.                                                         if self:IsInFirstPerson() and not (self.isFollowCamera and self.isClimbing) then
  3771.                                                                 percent = 1
  3772.                                                         end
  3773.        
  3774.                                                         local y = Util.GetAngleBetweenXZVectors(forwardVector, self:GetCameraLookVector())
  3775.                                                         if Util.IsFinite(y) and math.abs(y) > 0.0001 then
  3776.                                                                 self.rotateInput = self.rotateInput + Vector2.new(y * percent, 0)
  3777.                                                         end
  3778.                                                 end
  3779.        
  3780.                                         elseif self.isFollowCamera and (not (isInFirstPerson or userRecentlyPannedCamera) and not VRService.VREnabled) then
  3781.                                                 -- Logic that was unique to the old FollowCamera module
  3782.                                                 local lastVec = -(self.lastCameraTransform.p - subjectPosition)
  3783.        
  3784.                                                 local y = Util.GetAngleBetweenXZVectors(lastVec, self:GetCameraLookVector())
  3785.        
  3786.                                                 -- This cutoff is to decide if the humanoid's angle of movement,
  3787.                                                 -- relative to the camera's look vector, is enough that
  3788.                                                 -- we want the camera to be following them. The point is to provide
  3789.                                                 -- a sizable dead zone to allow more precise forward movements.
  3790.                                                 local thetaCutoff = 0.4
  3791.        
  3792.                                                 -- Check for NaNs
  3793.                                                 if Util.IsFinite(y) and math.abs(y) > 0.0001 and math.abs(y) > thetaCutoff * timeDelta then
  3794.                                                         self.rotateInput = self.rotateInput + Vector2.new(y, 0)
  3795.                                                 end
  3796.                                         end
  3797.                                 end
  3798.                         end
  3799.        
  3800.                         if not self.isFollowCamera then
  3801.                                 local VREnabled = VRService.VREnabled
  3802.        
  3803.                                 if VREnabled then
  3804.                                         newCameraFocus = self:GetVRFocus(subjectPosition, timeDelta)
  3805.                                 else
  3806.                                         newCameraFocus = CFrame.new(subjectPosition)
  3807.                                 end
  3808.        
  3809.                                 local cameraFocusP = newCameraFocus.p
  3810.                                 if VREnabled and not self:IsInFirstPerson() then
  3811.                                         local vecToSubject = (subjectPosition - camera.CFrame.p)
  3812.                                         local distToSubject = vecToSubject.magnitude
  3813.        
  3814.                                         -- Only move the camera if it exceeded a maximum distance to the subject in VR
  3815.                                         if distToSubject > zoom or self.rotateInput.x ~= 0 then
  3816.                                                 local desiredDist = math.min(distToSubject, zoom)
  3817.                                                 vecToSubject = self:CalculateNewLookVectorVR() * desiredDist
  3818.                                                 local newPos = cameraFocusP - vecToSubject
  3819.                                                 local desiredLookDir = camera.CFrame.lookVector
  3820.                                                 if self.rotateInput.x ~= 0 then
  3821.                                                         desiredLookDir = vecToSubject
  3822.                                                 end
  3823.                                                 local lookAt = Vector3.new(newPos.x + desiredLookDir.x, newPos.y, newPos.z + desiredLookDir.z)
  3824.                                                 self.rotateInput = ZERO_VECTOR2
  3825.        
  3826.                                                 newCameraCFrame = CFrame.new(newPos, lookAt) + Vector3.new(0, cameraHeight, 0)
  3827.                                         end
  3828.                                 else
  3829.                                         local newLookVector = self:CalculateNewLookVector(overrideCameraLookVector)
  3830.                                         self.rotateInput = ZERO_VECTOR2
  3831.                                         newCameraCFrame = CFrame.new(cameraFocusP - (zoom * newLookVector), cameraFocusP)
  3832.                                 end
  3833.                         else -- is FollowCamera
  3834.                                 local newLookVector = self:CalculateNewLookVector(overrideCameraLookVector)
  3835.                                 self.rotateInput = ZERO_VECTOR2
  3836.        
  3837.                                 if VRService.VREnabled then
  3838.                                         newCameraFocus = self:GetVRFocus(subjectPosition, timeDelta)
  3839.                                 else
  3840.                                         newCameraFocus = CFrame.new(subjectPosition)
  3841.                                 end
  3842.                                 newCameraCFrame = CFrame.new(newCameraFocus.p - (zoom * newLookVector), newCameraFocus.p) + Vector3.new(0, cameraHeight, 0)
  3843.                         end
  3844.        
  3845.                         if FFlagUserCameraToggle then
  3846.                                 local toggleOffset = self:GetCameraToggleOffset(timeDelta)
  3847.                                 newCameraFocus = newCameraFocus + toggleOffset
  3848.                                 newCameraCFrame = newCameraCFrame + toggleOffset
  3849.                         end
  3850.        
  3851.                         self.lastCameraTransform = newCameraCFrame
  3852.                         self.lastCameraFocus = newCameraFocus
  3853.                         if (isInVehicle or isOnASkateboard) and cameraSubject:IsA('BasePart') then
  3854.                                 self.lastSubjectCFrame = cameraSubject.CFrame
  3855.                         else
  3856.                                 self.lastSubjectCFrame = nil
  3857.                         end
  3858.                 end
  3859.        
  3860.                 self.lastUpdate = now
  3861.                 return newCameraCFrame, newCameraFocus
  3862.         end
  3863.        
  3864.         function ClassicCamera:EnterFirstPerson()
  3865.                 self.inFirstPerson = true
  3866.                 self:UpdateMouseBehavior()
  3867.         end
  3868.        
  3869.         function ClassicCamera:LeaveFirstPerson()
  3870.                 self.inFirstPerson = false
  3871.                 self:UpdateMouseBehavior()
  3872.         end
  3873.        
  3874.         return ClassicCamera
  3875. end
  3876.  
  3877. function _CameraUtils()
  3878.  
  3879.         local CameraUtils = {}
  3880.        
  3881.         local FFlagUserCameraToggle do
  3882.                 local success, result = pcall(function()
  3883.                         return UserSettings():IsUserFeatureEnabled("UserCameraToggle")
  3884.                 end)
  3885.                 FFlagUserCameraToggle = success and result
  3886.         end
  3887.        
  3888.         local function round(num)
  3889.                 return math.floor(num + 0.5)
  3890.         end
  3891.        
  3892.         -- Critically damped spring class for fluid motion effects
  3893.         local Spring = {} do
  3894.                 Spring.__index = Spring
  3895.        
  3896.                 -- Initialize to a given undamped frequency and default position
  3897.                 function Spring.new(freq, pos)
  3898.                         return setmetatable({
  3899.                                 freq = freq,
  3900.                                 goal = pos,
  3901.                                 pos = pos,
  3902.                                 vel = 0,
  3903.                         }, Spring)
  3904.                 end
  3905.        
  3906.                 -- Advance the spring simulation by `dt` seconds
  3907.                 function Spring:step(dt)
  3908.                         local f = self.freq*2*math.pi
  3909.                         local g = self.goal
  3910.                         local p0 = self.pos
  3911.                         local v0 = self.vel
  3912.        
  3913.                         local offset = p0 - g
  3914.                         local decay = math.exp(-f*dt)
  3915.        
  3916.                         local p1 = (offset*(1 + f*dt) + v0*dt)*decay + g
  3917.                         local v1 = (v0*(1 - f*dt) - offset*(f*f*dt))*decay
  3918.        
  3919.                         self.pos = p1
  3920.                         self.vel = v1
  3921.        
  3922.                         return p1
  3923.                 end
  3924.         end
  3925.        
  3926.         CameraUtils.Spring = Spring
  3927.        
  3928.         -- map a value from one range to another
  3929.         function CameraUtils.map(x, inMin, inMax, outMin, outMax)
  3930.                 return (x - inMin)*(outMax - outMin)/(inMax - inMin) + outMin
  3931.         end
  3932.        
  3933.         -- From TransparencyController
  3934.         function CameraUtils.Round(num, places)
  3935.                 local decimalPivot = 10^places
  3936.                 return math.floor(num * decimalPivot + 0.5) / decimalPivot
  3937.         end
  3938.        
  3939.         function CameraUtils.IsFinite(val)
  3940.                 return val == val and val ~= math.huge and val ~= -math.huge
  3941.         end
  3942.        
  3943.         function CameraUtils.IsFiniteVector3(vec3)
  3944.                 return CameraUtils.IsFinite(vec3.X) and CameraUtils.IsFinite(vec3.Y) and CameraUtils.IsFinite(vec3.Z)
  3945.         end
  3946.        
  3947.         -- Legacy implementation renamed
  3948.         function CameraUtils.GetAngleBetweenXZVectors(v1, v2)
  3949.                 return math.atan2(v2.X*v1.Z-v2.Z*v1.X, v2.X*v1.X+v2.Z*v1.Z)
  3950.         end
  3951.        
  3952.         function  CameraUtils.RotateVectorByAngleAndRound(camLook, rotateAngle, roundAmount)
  3953.                 if camLook.Magnitude > 0 then
  3954.                         camLook = camLook.unit
  3955.                         local currAngle = math.atan2(camLook.z, camLook.x)
  3956.                         local newAngle = round((math.atan2(camLook.z, camLook.x) + rotateAngle) / roundAmount) * roundAmount
  3957.                         return newAngle - currAngle
  3958.                 end
  3959.                 return 0
  3960.         end
  3961.        
  3962.         -- K is a tunable parameter that changes the shape of the S-curve
  3963.         -- the larger K is the more straight/linear the curve gets
  3964.         local k = 0.35
  3965.         local lowerK = 0.8
  3966.         local function SCurveTranform(t)
  3967.                 t = math.clamp(t, -1, 1)
  3968.                 if t >= 0 then
  3969.                         return (k*t) / (k - t + 1)
  3970.                 end
  3971.                 return -((lowerK*-t) / (lowerK + t + 1))
  3972.         end
  3973.        
  3974.         local DEADZONE = 0.1
  3975.         local function toSCurveSpace(t)
  3976.                 return (1 + DEADZONE) * (2*math.abs(t) - 1) - DEADZONE
  3977.         end
  3978.        
  3979.         local function fromSCurveSpace(t)
  3980.                 return t/2 + 0.5
  3981.         end
  3982.        
  3983.         function CameraUtils.GamepadLinearToCurve(thumbstickPosition)
  3984.                 local function onAxis(axisValue)
  3985.                         local sign = 1
  3986.                         if axisValue < 0 then
  3987.                                 sign = -1
  3988.                         end
  3989.                         local point = fromSCurveSpace(SCurveTranform(toSCurveSpace(math.abs(axisValue))))
  3990.                         point = point * sign
  3991.                         return math.clamp(point, -1, 1)
  3992.                 end
  3993.                 return Vector2.new(onAxis(thumbstickPosition.x), onAxis(thumbstickPosition.y))
  3994.         end
  3995.        
  3996.         -- This function converts 4 different, redundant enumeration types to one standard so the values can be compared
  3997.         function CameraUtils.ConvertCameraModeEnumToStandard(enumValue)
  3998.                 if enumValue == Enum.TouchCameraMovementMode.Default then
  3999.                         return Enum.ComputerCameraMovementMode.Follow
  4000.                 end
  4001.        
  4002.                 if enumValue == Enum.ComputerCameraMovementMode.Default then
  4003.                         return Enum.ComputerCameraMovementMode.Classic
  4004.                 end
  4005.        
  4006.                 if enumValue == Enum.TouchCameraMovementMode.Classic or
  4007.                         enumValue == Enum.DevTouchCameraMovementMode.Classic or
  4008.                         enumValue == Enum.DevComputerCameraMovementMode.Classic or
  4009.                         enumValue == Enum.ComputerCameraMovementMode.Classic then
  4010.                         return Enum.ComputerCameraMovementMode.Classic
  4011.                 end
  4012.        
  4013.                 if enumValue == Enum.TouchCameraMovementMode.Follow or
  4014.                         enumValue == Enum.DevTouchCameraMovementMode.Follow or
  4015.                         enumValue == Enum.DevComputerCameraMovementMode.Follow or
  4016.                         enumValue == Enum.ComputerCameraMovementMode.Follow then
  4017.                         return Enum.ComputerCameraMovementMode.Follow
  4018.                 end
  4019.        
  4020.                 if enumValue == Enum.TouchCameraMovementMode.Orbital or
  4021.                         enumValue == Enum.DevTouchCameraMovementMode.Orbital or
  4022.                         enumValue == Enum.DevComputerCameraMovementMode.Orbital or
  4023.                         enumValue == Enum.ComputerCameraMovementMode.Orbital then
  4024.                         return Enum.ComputerCameraMovementMode.Orbital
  4025.                 end
  4026.        
  4027.                 if FFlagUserCameraToggle then
  4028.                         if enumValue == Enum.ComputerCameraMovementMode.CameraToggle or
  4029.                                 enumValue == Enum.DevComputerCameraMovementMode.CameraToggle then
  4030.                                 return Enum.ComputerCameraMovementMode.CameraToggle
  4031.                         end
  4032.                 end
  4033.        
  4034.                 -- Note: Only the Dev versions of the Enums have UserChoice as an option
  4035.                 if enumValue == Enum.DevTouchCameraMovementMode.UserChoice or
  4036.                         enumValue == Enum.DevComputerCameraMovementMode.UserChoice then
  4037.                         return Enum.DevComputerCameraMovementMode.UserChoice
  4038.                 end
  4039.        
  4040.                 -- For any unmapped options return Classic camera
  4041.                 return Enum.ComputerCameraMovementMode.Classic
  4042.         end
  4043.        
  4044.         return CameraUtils
  4045. end
  4046.  
  4047. function _CameraModule()
  4048.         local CameraModule = {}
  4049.         CameraModule.__index = CameraModule
  4050.        
  4051.         local FFlagUserCameraToggle do
  4052.                 local success, result = pcall(function()
  4053.                         return UserSettings():IsUserFeatureEnabled("UserCameraToggle")
  4054.                 end)
  4055.                 FFlagUserCameraToggle = success and result
  4056.         end
  4057.        
  4058.         local FFlagUserRemoveTheCameraApi do
  4059.                 local success, result = pcall(function()
  4060.                         return UserSettings():IsUserFeatureEnabled("UserRemoveTheCameraApi")
  4061.                 end)
  4062.                 FFlagUserRemoveTheCameraApi = success and result
  4063.         end
  4064.        
  4065.         -- NOTICE: Player property names do not all match their StarterPlayer equivalents,
  4066.         -- with the differences noted in the comments on the right
  4067.         local PLAYER_CAMERA_PROPERTIES =
  4068.         {
  4069.                 "CameraMinZoomDistance",
  4070.                 "CameraMaxZoomDistance",
  4071.                 "CameraMode",
  4072.                 "DevCameraOcclusionMode",
  4073.                 "DevComputerCameraMode",                        -- Corresponds to StarterPlayer.DevComputerCameraMovementMode
  4074.                 "DevTouchCameraMode",                           -- Corresponds to StarterPlayer.DevTouchCameraMovementMode
  4075.        
  4076.                 -- Character movement mode
  4077.                 "DevComputerMovementMode",
  4078.                 "DevTouchMovementMode",
  4079.                 "DevEnableMouseLock",                           -- Corresponds to StarterPlayer.EnableMouseLockOption
  4080.         }
  4081.        
  4082.         local USER_GAME_SETTINGS_PROPERTIES =
  4083.         {
  4084.                 "ComputerCameraMovementMode",
  4085.                 "ComputerMovementMode",
  4086.                 "ControlMode",
  4087.                 "GamepadCameraSensitivity",
  4088.                 "MouseSensitivity",
  4089.                 "RotationType",
  4090.                 "TouchCameraMovementMode",
  4091.                 "TouchMovementMode",
  4092.         }
  4093.        
  4094.         --[[ Roblox Services ]]--
  4095.         local Players = game:GetService("Players")
  4096.         local RunService = game:GetService("RunService")
  4097.         local UserInputService = game:GetService("UserInputService")
  4098.         local UserGameSettings = UserSettings():GetService("UserGameSettings")
  4099.        
  4100.         -- Camera math utility library
  4101.         local CameraUtils = _CameraUtils()
  4102.        
  4103.         -- Load Roblox Camera Controller Modules
  4104.         local ClassicCamera = _ClassicCamera()
  4105.         local OrbitalCamera = _OrbitalCamera()
  4106.         local LegacyCamera = _LegacyCamera()
  4107.        
  4108.         -- Load Roblox Occlusion Modules
  4109.         local Invisicam = _Invisicam()
  4110.         local Poppercam = _Poppercam()
  4111.        
  4112.         -- Load the near-field character transparency controller and the mouse lock "shift lock" controller
  4113.         local TransparencyController = _TransparencyController()
  4114.         local MouseLockController = _MouseLockController()
  4115.        
  4116.         -- Table of camera controllers that have been instantiated. They are instantiated as they are used.
  4117.         local instantiatedCameraControllers = {}
  4118.         local instantiatedOcclusionModules = {}
  4119.        
  4120.         -- Management of which options appear on the Roblox User Settings screen
  4121.         do
  4122.                 local PlayerScripts = Players.LocalPlayer:WaitForChild("PlayerScripts")
  4123.        
  4124.                 PlayerScripts:RegisterTouchCameraMovementMode(Enum.TouchCameraMovementMode.Default)
  4125.                 PlayerScripts:RegisterTouchCameraMovementMode(Enum.TouchCameraMovementMode.Follow)
  4126.                 PlayerScripts:RegisterTouchCameraMovementMode(Enum.TouchCameraMovementMode.Classic)
  4127.        
  4128.                 PlayerScripts:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.Default)
  4129.                 PlayerScripts:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.Follow)
  4130.                 PlayerScripts:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.Classic)
  4131.                 if FFlagUserCameraToggle then
  4132.                         PlayerScripts:RegisterComputerCameraMovementMode(Enum.ComputerCameraMovementMode.CameraToggle)
  4133.                 end
  4134.         end
  4135.        
  4136.         CameraModule.FFlagUserCameraToggle = FFlagUserCameraToggle
  4137.        
  4138.        
  4139.         function CameraModule.new()
  4140.                 local self = setmetatable({},CameraModule)
  4141.        
  4142.                 -- Current active controller instances
  4143.                 self.activeCameraController = nil
  4144.                 self.activeOcclusionModule = nil
  4145.                 self.activeTransparencyController = nil
  4146.                 self.activeMouseLockController = nil
  4147.        
  4148.                 self.currentComputerCameraMovementMode = nil
  4149.        
  4150.                 -- Connections to events
  4151.                 self.cameraSubjectChangedConn = nil
  4152.                 self.cameraTypeChangedConn = nil
  4153.        
  4154.                 -- Adds CharacterAdded and CharacterRemoving event handlers for all current players
  4155.                 for _,player in pairs(Players:GetPlayers()) do
  4156.                         self:OnPlayerAdded(player)
  4157.                 end
  4158.        
  4159.                 -- Adds CharacterAdded and CharacterRemoving event handlers for all players who join in the future
  4160.                 Players.PlayerAdded:Connect(function(player)
  4161.                         self:OnPlayerAdded(player)
  4162.                 end)
  4163.        
  4164.                 self.activeTransparencyController = TransparencyController.new()
  4165.                 self.activeTransparencyController:Enable(true)
  4166.        
  4167.                 if not UserInputService.TouchEnabled then
  4168.                         self.activeMouseLockController = MouseLockController.new()
  4169.                         local toggleEvent = self.activeMouseLockController:GetBindableToggleEvent()
  4170.                         if toggleEvent then
  4171.                                 toggleEvent:Connect(function()
  4172.                                         self:OnMouseLockToggled()
  4173.                                 end)
  4174.                         end
  4175.                 end
  4176.        
  4177.                 self:ActivateCameraController(self:GetCameraControlChoice())
  4178.                 self:ActivateOcclusionModule(Players.LocalPlayer.DevCameraOcclusionMode)
  4179.                 self:OnCurrentCameraChanged() -- Does initializations and makes first camera controller
  4180.                 RunService:BindToRenderStep("cameraRenderUpdate", Enum.RenderPriority.Camera.Value, function(dt) self:Update(dt) end)
  4181.        
  4182.                 -- Connect listeners to camera-related properties
  4183.                 for _, propertyName in pairs(PLAYER_CAMERA_PROPERTIES) do
  4184.                         Players.LocalPlayer:GetPropertyChangedSignal(propertyName):Connect(function()
  4185.                                 self:OnLocalPlayerCameraPropertyChanged(propertyName)
  4186.                         end)
  4187.                 end
  4188.        
  4189.                 for _, propertyName in pairs(USER_GAME_SETTINGS_PROPERTIES) do
  4190.                         UserGameSettings:GetPropertyChangedSignal(propertyName):Connect(function()
  4191.                                 self:OnUserGameSettingsPropertyChanged(propertyName)
  4192.                         end)
  4193.                 end
  4194.                 game.Workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function()
  4195.                         self:OnCurrentCameraChanged()
  4196.                 end)
  4197.        
  4198.                 self.lastInputType = UserInputService:GetLastInputType()
  4199.                 UserInputService.LastInputTypeChanged:Connect(function(newLastInputType)
  4200.                         self.lastInputType = newLastInputType
  4201.                 end)
  4202.        
  4203.                 return self
  4204.         end
  4205.        
  4206.         function CameraModule:GetCameraMovementModeFromSettings()
  4207.                 local cameraMode = Players.LocalPlayer.CameraMode
  4208.        
  4209.                 -- Lock First Person trumps all other settings and forces ClassicCamera
  4210.                 if cameraMode == Enum.CameraMode.LockFirstPerson then
  4211.                         return CameraUtils.ConvertCameraModeEnumToStandard(Enum.ComputerCameraMovementMode.Classic)
  4212.                 end
  4213.        
  4214.                 local devMode, userMode
  4215.                 if UserInputService.TouchEnabled then
  4216.                         devMode = CameraUtils.ConvertCameraModeEnumToStandard(Players.LocalPlayer.DevTouchCameraMode)
  4217.                         userMode = CameraUtils.ConvertCameraModeEnumToStandard(UserGameSettings.TouchCameraMovementMode)
  4218.                 else
  4219.                         devMode = CameraUtils.ConvertCameraModeEnumToStandard(Players.LocalPlayer.DevComputerCameraMode)
  4220.                         userMode = CameraUtils.ConvertCameraModeEnumToStandard(UserGameSettings.ComputerCameraMovementMode)
  4221.                 end
  4222.        
  4223.                 if devMode == Enum.DevComputerCameraMovementMode.UserChoice then
  4224.                         -- Developer is allowing user choice, so user setting is respected
  4225.                         return userMode
  4226.                 end
  4227.        
  4228.                 return devMode
  4229.         end
  4230.        
  4231.         function CameraModule:ActivateOcclusionModule( occlusionMode )
  4232.                 local newModuleCreator
  4233.                 if occlusionMode == Enum.DevCameraOcclusionMode.Zoom then
  4234.                         newModuleCreator = Poppercam
  4235.                 elseif occlusionMode == Enum.DevCameraOcclusionMode.Invisicam then
  4236.                         newModuleCreator = Invisicam
  4237.                 else
  4238.                         warn("CameraScript ActivateOcclusionModule called with unsupported mode")
  4239.                         return
  4240.                 end
  4241.        
  4242.                 -- First check to see if there is actually a change. If the module being requested is already
  4243.                 -- the currently-active solution then just make sure it's enabled and exit early
  4244.                 if self.activeOcclusionModule and self.activeOcclusionModule:GetOcclusionMode() == occlusionMode then
  4245.                         if not self.activeOcclusionModule:GetEnabled() then
  4246.                                 self.activeOcclusionModule:Enable(true)
  4247.                         end
  4248.                         return
  4249.                 end
  4250.        
  4251.                 -- Save a reference to the current active module (may be nil) so that we can disable it if
  4252.                 -- we are successful in activating its replacement
  4253.                 local prevOcclusionModule = self.activeOcclusionModule
  4254.        
  4255.                 -- If there is no active module, see if the one we need has already been instantiated
  4256.                 self.activeOcclusionModule = instantiatedOcclusionModules[newModuleCreator]
  4257.        
  4258.                 -- If the module was not already instantiated and selected above, instantiate it
  4259.                 if not self.activeOcclusionModule then
  4260.                         self.activeOcclusionModule = newModuleCreator.new()
  4261.                         if self.activeOcclusionModule then
  4262.                                 instantiatedOcclusionModules[newModuleCreator] = self.activeOcclusionModule
  4263.                         end
  4264.                 end
  4265.        
  4266.                 -- If we were successful in either selecting or instantiating the module,
  4267.                 -- enable it if it's not already the currently-active enabled module
  4268.                 if self.activeOcclusionModule then
  4269.                         local newModuleOcclusionMode = self.activeOcclusionModule:GetOcclusionMode()
  4270.                         -- Sanity check that the module we selected or instantiated actually supports the desired occlusionMode
  4271.                         if newModuleOcclusionMode ~= occlusionMode then
  4272.                                 warn("CameraScript ActivateOcclusionModule mismatch: ",self.activeOcclusionModule:GetOcclusionMode(),"~=",occlusionMode)
  4273.                         end
  4274.        
  4275.                         -- Deactivate current module if there is one
  4276.                         if prevOcclusionModule then
  4277.                                 -- Sanity check that current module is not being replaced by itself (that should have been handled above)
  4278.                                 if prevOcclusionModule ~= self.activeOcclusionModule then
  4279.                                         prevOcclusionModule:Enable(false)
  4280.                                 else
  4281.                                         warn("CameraScript ActivateOcclusionModule failure to detect already running correct module")
  4282.                                 end
  4283.                         end
  4284.        
  4285.                         -- Occlusion modules need to be initialized with information about characters and cameraSubject
  4286.                         -- Invisicam needs the LocalPlayer's character
  4287.                         -- Poppercam needs all player characters and the camera subject
  4288.                         if occlusionMode == Enum.DevCameraOcclusionMode.Invisicam then
  4289.                                 -- Optimization to only send Invisicam what we know it needs
  4290.                                 if Players.LocalPlayer.Character then
  4291.                                         self.activeOcclusionModule:CharacterAdded(Players.LocalPlayer.Character, Players.LocalPlayer )
  4292.                                 end
  4293.                         else
  4294.                                 -- When Poppercam is enabled, we send it all existing player characters for its raycast ignore list
  4295.                                 for _, player in pairs(Players:GetPlayers()) do
  4296.                                         if player and player.Character then
  4297.                                                 self.activeOcclusionModule:CharacterAdded(player.Character, player)
  4298.                                         end
  4299.                                 end
  4300.                                 self.activeOcclusionModule:OnCameraSubjectChanged(game.Workspace.CurrentCamera.CameraSubject)
  4301.                         end
  4302.        
  4303.                         -- Activate new choice
  4304.                         self.activeOcclusionModule:Enable(true)
  4305.                 end
  4306.         end
  4307.        
  4308.         -- When supplied, legacyCameraType is used and cameraMovementMode is ignored (should be nil anyways)
  4309.         -- Next, if userCameraCreator is passed in, that is used as the cameraCreator
  4310.         function CameraModule:ActivateCameraController(cameraMovementMode, legacyCameraType)
  4311.                 local newCameraCreator = nil
  4312.        
  4313.                 if legacyCameraType~=nil then
  4314.                         --[[
  4315.                                 This function has been passed a CameraType enum value. Some of these map to the use of
  4316.                                 the LegacyCamera module, the value "Custom" will be translated to a movementMode enum
  4317.                                 value based on Dev and User settings, and "Scriptable" will disable the camera controller.
  4318.                         --]]
  4319.        
  4320.                         if legacyCameraType == Enum.CameraType.Scriptable then
  4321.                                 if self.activeCameraController then
  4322.                                         self.activeCameraController:Enable(false)
  4323.                                         self.activeCameraController = nil
  4324.                                         return
  4325.                                 end
  4326.                         elseif legacyCameraType == Enum.CameraType.Custom then
  4327.                                 cameraMovementMode = self:GetCameraMovementModeFromSettings()
  4328.        
  4329.                         elseif legacyCameraType == Enum.CameraType.Track then
  4330.                                 -- Note: The TrackCamera module was basically an older, less fully-featured
  4331.                                 -- version of ClassicCamera, no longer actively maintained, but it is re-implemented in
  4332.                                 -- case a game was dependent on its lack of ClassicCamera's extra functionality.
  4333.                                 cameraMovementMode = Enum.ComputerCameraMovementMode.Classic
  4334.        
  4335.                         elseif legacyCameraType == Enum.CameraType.Follow then
  4336.                                 cameraMovementMode = Enum.ComputerCameraMovementMode.Follow
  4337.        
  4338.                         elseif legacyCameraType == Enum.CameraType.Orbital then
  4339.                                 cameraMovementMode = Enum.ComputerCameraMovementMode.Orbital
  4340.        
  4341.                         elseif legacyCameraType == Enum.CameraType.Attach or
  4342.                                    legacyCameraType == Enum.CameraType.Watch or
  4343.                                    legacyCameraType == Enum.CameraType.Fixed then
  4344.                                 newCameraCreator = LegacyCamera
  4345.                         else
  4346.                                 warn("CameraScript encountered an unhandled Camera.CameraType value: ",legacyCameraType)
  4347.                         end
  4348.                 end
  4349.        
  4350.                 if not newCameraCreator then
  4351.                         if cameraMovementMode == Enum.ComputerCameraMovementMode.Classic or
  4352.                                 cameraMovementMode == Enum.ComputerCameraMovementMode.Follow or
  4353.                                 cameraMovementMode == Enum.ComputerCameraMovementMode.Default or
  4354.                                 (FFlagUserCameraToggle and cameraMovementMode == Enum.ComputerCameraMovementMode.CameraToggle) then
  4355.                                 newCameraCreator = ClassicCamera
  4356.                         elseif cameraMovementMode == Enum.ComputerCameraMovementMode.Orbital then
  4357.                                 newCameraCreator = OrbitalCamera
  4358.                         else
  4359.                                 warn("ActivateCameraController did not select a module.")
  4360.                                 return
  4361.                         end
  4362.                 end
  4363.        
  4364.                 -- Create the camera control module we need if it does not already exist in instantiatedCameraControllers
  4365.                 local newCameraController
  4366.                 if not instantiatedCameraControllers[newCameraCreator] then
  4367.                         newCameraController = newCameraCreator.new()
  4368.                         instantiatedCameraControllers[newCameraCreator] = newCameraController
  4369.                 else
  4370.                         newCameraController = instantiatedCameraControllers[newCameraCreator]
  4371.                 end
  4372.        
  4373.                 -- If there is a controller active and it's not the one we need, disable it,
  4374.                 -- if it is the one we need, make sure it's enabled
  4375.                 if self.activeCameraController then
  4376.                         if self.activeCameraController ~= newCameraController then
  4377.                                 self.activeCameraController:Enable(false)
  4378.                                 self.activeCameraController = newCameraController
  4379.                                 self.activeCameraController:Enable(true)
  4380.                         elseif not self.activeCameraController:GetEnabled() then
  4381.                                 self.activeCameraController:Enable(true)
  4382.                         end
  4383.                 elseif newCameraController ~= nil then
  4384.                         self.activeCameraController = newCameraController
  4385.                         self.activeCameraController:Enable(true)
  4386.                 end
  4387.        
  4388.                 if self.activeCameraController then
  4389.                         if cameraMovementMode~=nil then
  4390.                                 self.activeCameraController:SetCameraMovementMode(cameraMovementMode)
  4391.                         elseif legacyCameraType~=nil then
  4392.                                 -- Note that this is only called when legacyCameraType is not a type that
  4393.                                 -- was convertible to a ComputerCameraMovementMode value, i.e. really only applies to LegacyCamera
  4394.                                 self.activeCameraController:SetCameraType(legacyCameraType)
  4395.                         end
  4396.                 end
  4397.         end
  4398.        
  4399.         -- Note: The active transparency controller could be made to listen for this event itself.
  4400.         function CameraModule:OnCameraSubjectChanged()
  4401.                 if self.activeTransparencyController then
  4402.                         self.activeTransparencyController:SetSubject(game.Workspace.CurrentCamera.CameraSubject)
  4403.                 end
  4404.        
  4405.                 if self.activeOcclusionModule then
  4406.                         self.activeOcclusionModule:OnCameraSubjectChanged(game.Workspace.CurrentCamera.CameraSubject)
  4407.                 end
  4408.         end
  4409.        
  4410.         function CameraModule:OnCameraTypeChanged(newCameraType)
  4411.                 if newCameraType == Enum.CameraType.Scriptable then
  4412.                         if UserInputService.MouseBehavior == Enum.MouseBehavior.LockCenter then
  4413.                                 UserInputService.MouseBehavior = Enum.MouseBehavior.Default
  4414.                         end
  4415.                 end
  4416.        
  4417.                 -- Forward the change to ActivateCameraController to handle
  4418.                 self:ActivateCameraController(nil, newCameraType)
  4419.         end
  4420.        
  4421.         -- Note: Called whenever workspace.CurrentCamera changes, but also on initialization of this script
  4422.         function CameraModule:OnCurrentCameraChanged()
  4423.                 local currentCamera = game.Workspace.CurrentCamera
  4424.                 if not currentCamera then return end
  4425.        
  4426.                 if self.cameraSubjectChangedConn then
  4427.                         self.cameraSubjectChangedConn:Disconnect()
  4428.                 end
  4429.        
  4430.                 if self.cameraTypeChangedConn then
  4431.                         self.cameraTypeChangedConn:Disconnect()
  4432.                 end
  4433.        
  4434.                 self.cameraSubjectChangedConn = currentCamera:GetPropertyChangedSignal("CameraSubject"):Connect(function()
  4435.                         self:OnCameraSubjectChanged(currentCamera.CameraSubject)
  4436.                 end)
  4437.        
  4438.                 self.cameraTypeChangedConn = currentCamera:GetPropertyChangedSignal("CameraType"):Connect(function()
  4439.                         self:OnCameraTypeChanged(currentCamera.CameraType)
  4440.                 end)
  4441.        
  4442.                 self:OnCameraSubjectChanged(currentCamera.CameraSubject)
  4443.                 self:OnCameraTypeChanged(currentCamera.CameraType)
  4444.         end
  4445.        
  4446.         function CameraModule:OnLocalPlayerCameraPropertyChanged(propertyName)
  4447.                 if propertyName == "CameraMode" then
  4448.                         -- CameraMode is only used to turn on/off forcing the player into first person view. The
  4449.                         -- Note: The case "Classic" is used for all other views and does not correspond only to the ClassicCamera module
  4450.                         if Players.LocalPlayer.CameraMode == Enum.CameraMode.LockFirstPerson then
  4451.                                 -- Locked in first person, use ClassicCamera which supports this
  4452.                                 if not self.activeCameraController or self.activeCameraController:GetModuleName() ~= "ClassicCamera" then
  4453.                                         self:ActivateCameraController(CameraUtils.ConvertCameraModeEnumToStandard(Enum.DevComputerCameraMovementMode.Classic))
  4454.                                 end
  4455.        
  4456.                                 if self.activeCameraController then
  4457.                                         self.activeCameraController:UpdateForDistancePropertyChange()
  4458.                                 end
  4459.                         elseif Players.LocalPlayer.CameraMode == Enum.CameraMode.Classic then
  4460.                                 -- Not locked in first person view
  4461.                                 local cameraMovementMode =self: GetCameraMovementModeFromSettings()
  4462.                                 self:ActivateCameraController(CameraUtils.ConvertCameraModeEnumToStandard(cameraMovementMode))
  4463.                         else
  4464.                                 warn("Unhandled value for property player.CameraMode: ",Players.LocalPlayer.CameraMode)
  4465.                         end
  4466.        
  4467.                 elseif propertyName == "DevComputerCameraMode" or
  4468.                            propertyName == "DevTouchCameraMode" then
  4469.                         local cameraMovementMode = self:GetCameraMovementModeFromSettings()
  4470.                         self:ActivateCameraController(CameraUtils.ConvertCameraModeEnumToStandard(cameraMovementMode))
  4471.        
  4472.                 elseif propertyName == "DevCameraOcclusionMode" then
  4473.                         self:ActivateOcclusionModule(Players.LocalPlayer.DevCameraOcclusionMode)
  4474.        
  4475.                 elseif propertyName == "CameraMinZoomDistance" or propertyName == "CameraMaxZoomDistance" then
  4476.                         if self.activeCameraController then
  4477.                                 self.activeCameraController:UpdateForDistancePropertyChange()
  4478.                         end
  4479.                 elseif propertyName == "DevTouchMovementMode" then
  4480.                 elseif propertyName == "DevComputerMovementMode" then
  4481.                 elseif propertyName == "DevEnableMouseLock" then
  4482.                         -- This is the enabling/disabling of "Shift Lock" mode, not LockFirstPerson (which is a CameraMode)
  4483.                         -- Note: Enabling and disabling of MouseLock mode is normally only a publish-time choice made via
  4484.                         -- the corresponding EnableMouseLockOption checkbox of StarterPlayer, and this script does not have
  4485.                         -- support for changing the availability of MouseLock at runtime (this would require listening to
  4486.                         -- Player.DevEnableMouseLock changes)
  4487.                 end
  4488.         end
  4489.        
  4490.         function CameraModule:OnUserGameSettingsPropertyChanged(propertyName)
  4491.                 if propertyName ==      "ComputerCameraMovementMode" then
  4492.                         local cameraMovementMode = self:GetCameraMovementModeFromSettings()
  4493.                         self:ActivateCameraController(CameraUtils.ConvertCameraModeEnumToStandard(cameraMovementMode))
  4494.                 end
  4495.         end
  4496.        
  4497.         --[[
  4498.                 Main RenderStep Update. The camera controller and occlusion module both have opportunities
  4499.                 to set and modify (respectively) the CFrame and Focus before it is set once on CurrentCamera.
  4500.                 The camera and occlusion modules should only return CFrames, not set the CFrame property of
  4501.                 CurrentCamera directly.
  4502.         --]]
  4503.         function CameraModule:Update(dt)
  4504.                 if self.activeCameraController then
  4505.                         if FFlagUserCameraToggle then
  4506.                                 self.activeCameraController:UpdateMouseBehavior()
  4507.                         end
  4508.        
  4509.                         local newCameraCFrame, newCameraFocus = self.activeCameraController:Update(dt)
  4510.                         self.activeCameraController:ApplyVRTransform()
  4511.                         if self.activeOcclusionModule then
  4512.                                 newCameraCFrame, newCameraFocus = self.activeOcclusionModule:Update(dt, newCameraCFrame, newCameraFocus)
  4513.                         end
  4514.        
  4515.                         -- Here is where the new CFrame and Focus are set for this render frame
  4516.                         game.Workspace.CurrentCamera.CFrame = newCameraCFrame
  4517.                         game.Workspace.CurrentCamera.Focus = newCameraFocus
  4518.        
  4519.                         -- Update to character local transparency as needed based on camera-to-subject distance
  4520.                         if self.activeTransparencyController then
  4521.                                 self.activeTransparencyController:Update()
  4522.                         end
  4523.                 end
  4524.         end
  4525.        
  4526.         -- Formerly getCurrentCameraMode, this function resolves developer and user camera control settings to
  4527.         -- decide which camera control module should be instantiated. The old method of converting redundant enum types
  4528.         function CameraModule:GetCameraControlChoice()
  4529.                 local player = Players.LocalPlayer
  4530.        
  4531.                 if player then
  4532.                         if self.lastInputType == Enum.UserInputType.Touch or UserInputService.TouchEnabled then
  4533.                                 -- Touch
  4534.                                 if player.DevTouchCameraMode == Enum.DevTouchCameraMovementMode.UserChoice then
  4535.                                         return CameraUtils.ConvertCameraModeEnumToStandard( UserGameSettings.TouchCameraMovementMode )
  4536.                                 else
  4537.                                         return CameraUtils.ConvertCameraModeEnumToStandard( player.DevTouchCameraMode )
  4538.                                 end
  4539.                         else
  4540.                                 -- Computer
  4541.                                 if player.DevComputerCameraMode == Enum.DevComputerCameraMovementMode.UserChoice then
  4542.                                         local computerMovementMode = CameraUtils.ConvertCameraModeEnumToStandard(UserGameSettings.ComputerCameraMovementMode)
  4543.                                         return CameraUtils.ConvertCameraModeEnumToStandard(computerMovementMode)
  4544.                                 else
  4545.                                         return CameraUtils.ConvertCameraModeEnumToStandard(player.DevComputerCameraMode)
  4546.                                 end
  4547.                         end
  4548.                 end
  4549.         end
  4550.        
  4551.         function CameraModule:OnCharacterAdded(char, player)
  4552.                 if self.activeOcclusionModule then
  4553.                         self.activeOcclusionModule:CharacterAdded(char, player)
  4554.                 end
  4555.         end
  4556.        
  4557.         function CameraModule:OnCharacterRemoving(char, player)
  4558.                 if self.activeOcclusionModule then
  4559.                         self.activeOcclusionModule:CharacterRemoving(char, player)
  4560.                 end
  4561.         end
  4562.        
  4563.         function CameraModule:OnPlayerAdded(player)
  4564.                 player.CharacterAdded:Connect(function(char)
  4565.                         self:OnCharacterAdded(char, player)
  4566.                 end)
  4567.                 player.CharacterRemoving:Connect(function(char)
  4568.                         self:OnCharacterRemoving(char, player)
  4569.                 end)
  4570.         end
  4571.        
  4572.         function CameraModule:OnMouseLockToggled()
  4573.                 if self.activeMouseLockController then
  4574.                         local mouseLocked = self.activeMouseLockController:GetIsMouseLocked()
  4575.                         local mouseLockOffset = self.activeMouseLockController:GetMouseLockOffset()
  4576.                         if self.activeCameraController then
  4577.                                 self.activeCameraController:SetIsMouseLocked(mouseLocked)
  4578.                                 self.activeCameraController:SetMouseLockOffset(mouseLockOffset)
  4579.                         end
  4580.                 end
  4581.         end
  4582.         --begin edit
  4583.         local Camera = CameraModule
  4584.         local IDENTITYCF = CFrame.new()
  4585.         local lastUpCFrame = IDENTITYCF
  4586.        
  4587.         Camera.UpVector = Vector3.new(0, 1, 0)
  4588.         Camera.TransitionRate = 0.15
  4589.         Camera.UpCFrame = IDENTITYCF
  4590.        
  4591.         function Camera:GetUpVector(oldUpVector)
  4592.                 return oldUpVector
  4593.         end
  4594.         local function getRotationBetween(u, v, axis)
  4595.                 local dot, uxv = u:Dot(v), u:Cross(v)
  4596.                 if (dot < -0.99999) then return CFrame.fromAxisAngle(axis, math.pi) end
  4597.                 return CFrame.new(0, 0, 0, uxv.x, uxv.y, uxv.z, 1 + dot)
  4598.         end
  4599.         function Camera:CalculateUpCFrame()
  4600.                 local oldUpVector = self.UpVector
  4601.                 local newUpVector = self:GetUpVector(oldUpVector)
  4602.                
  4603.                 local backup = game.Workspace.CurrentCamera.CFrame.RightVector
  4604.                 local transitionCF = getRotationBetween(oldUpVector, newUpVector, backup)
  4605.                 local vecSlerpCF = IDENTITYCF:Lerp(transitionCF, self.TransitionRate)
  4606.                
  4607.                 self.UpVector = vecSlerpCF * oldUpVector
  4608.                 self.UpCFrame = vecSlerpCF * self.UpCFrame
  4609.                
  4610.                 lastUpCFrame = self.UpCFrame
  4611.         end
  4612.        
  4613.         function Camera:Update(dt)
  4614.                 if self.activeCameraController then
  4615.                         if Camera.FFlagUserCameraToggle then
  4616.                                 self.activeCameraController:UpdateMouseBehavior()
  4617.                         end
  4618.                        
  4619.                         local newCameraCFrame, newCameraFocus = self.activeCameraController:Update(dt)
  4620.                         self.activeCameraController:ApplyVRTransform()
  4621.                        
  4622.                         self:CalculateUpCFrame()
  4623.                         self.activeCameraController:UpdateUpCFrame(self.UpCFrame)
  4624.                        
  4625.                         -- undo shift-lock offset
  4626.        
  4627.                         local lockOffset = Vector3.new(0, 0, 0)
  4628.                         if (self.activeMouseLockController and self.activeMouseLockController:GetIsMouseLocked()) then
  4629.                                 lockOffset = self.activeMouseLockController:GetMouseLockOffset()
  4630.                         end
  4631.                        
  4632.                         local offset = newCameraFocus:ToObjectSpace(newCameraCFrame)
  4633.                         local camRotation = self.UpCFrame * offset
  4634.                         newCameraFocus = newCameraFocus - newCameraCFrame:VectorToWorldSpace(lockOffset) + camRotation:VectorToWorldSpace(lockOffset)
  4635.                         newCameraCFrame = newCameraFocus * camRotation
  4636.                        
  4637.                         --local offset = newCameraFocus:Inverse() * newCameraCFrame
  4638.                         --newCameraCFrame = newCameraFocus * self.UpCFrame * offset
  4639.                        
  4640.                         if (self.activeCameraController.lastCameraTransform) then
  4641.                                 self.activeCameraController.lastCameraTransform = newCameraCFrame
  4642.                                 self.activeCameraController.lastCameraFocus = newCameraFocus
  4643.                         end
  4644.                        
  4645.                         if self.activeOcclusionModule then
  4646.                                 newCameraCFrame, newCameraFocus = self.activeOcclusionModule:Update(dt, newCameraCFrame, newCameraFocus)
  4647.                         end
  4648.        
  4649.                         game.Workspace.CurrentCamera.CFrame = newCameraCFrame
  4650.                         game.Workspace.CurrentCamera.Focus = newCameraFocus
  4651.        
  4652.                         if self.activeTransparencyController then
  4653.                                 self.activeTransparencyController:Update()
  4654.                         end
  4655.                 end
  4656.         end
  4657.        
  4658.         function Camera:IsFirstPerson()
  4659.                 if self.activeCameraController then
  4660.                         return self.activeCameraController:InFirstPerson()
  4661.                 end
  4662.                 return false
  4663.         end
  4664.        
  4665.         function Camera:IsMouseLocked()
  4666.                 if self.activeCameraController then
  4667.                         return self.activeCameraController:GetIsMouseLocked()
  4668.                 end
  4669.                 return false
  4670.         end
  4671.         function Camera:IsToggleMode()
  4672.                 if self.activeCameraController then
  4673.                         return self.activeCameraController.isCameraToggle
  4674.                 end
  4675.                 return false
  4676.         end
  4677.         function Camera:IsCamRelative()
  4678.                 return self:IsMouseLocked() or self:IsFirstPerson()
  4679.                 --return self:IsToggleMode(), self:IsMouseLocked(), self:IsFirstPerson()
  4680.         end
  4681.         --
  4682.         local Utils = _CameraUtils()
  4683.         function Utils.GetAngleBetweenXZVectors(v1, v2)
  4684.                 local upCFrame = lastUpCFrame
  4685.                 v1 = upCFrame:VectorToObjectSpace(v1)
  4686.                 v2 = upCFrame:VectorToObjectSpace(v2)
  4687.                 return math.atan2(v2.X*v1.Z-v2.Z*v1.X, v2.X*v1.X+v2.Z*v1.Z)
  4688.         end
  4689.         --end edit
  4690.         local cameraModuleObject = CameraModule.new()
  4691.         local cameraApi = {}
  4692.         return cameraModuleObject
  4693. end
  4694.  
  4695. function _ClickToMoveDisplay()
  4696.         local ClickToMoveDisplay = {}
  4697.        
  4698.         local FAILURE_ANIMATION_ID = "rbxassetid://2874840706"
  4699.        
  4700.         local TrailDotIcon = "rbxasset://textures/ui/traildot.png"
  4701.         local EndWaypointIcon = "rbxasset://textures/ui/waypoint.png"
  4702.        
  4703.         local WaypointsAlwaysOnTop = false
  4704.        
  4705.         local WAYPOINT_INCLUDE_FACTOR = 2
  4706.         local LAST_DOT_DISTANCE = 3
  4707.        
  4708.         local WAYPOINT_BILLBOARD_SIZE = UDim2.new(0, 1.68 * 25, 0, 2 * 25)
  4709.        
  4710.         local ENDWAYPOINT_SIZE_OFFSET_MIN = Vector2.new(0, 0.5)
  4711.         local ENDWAYPOINT_SIZE_OFFSET_MAX = Vector2.new(0, 1)
  4712.        
  4713.         local FAIL_WAYPOINT_SIZE_OFFSET_CENTER = Vector2.new(0, 0.5)
  4714.         local FAIL_WAYPOINT_SIZE_OFFSET_LEFT = Vector2.new(0.1, 0.5)
  4715.         local FAIL_WAYPOINT_SIZE_OFFSET_RIGHT = Vector2.new(-0.1, 0.5)
  4716.        
  4717.         local FAILURE_TWEEN_LENGTH = 0.125
  4718.         local FAILURE_TWEEN_COUNT = 4
  4719.        
  4720.         local TWEEN_WAYPOINT_THRESHOLD = 5
  4721.        
  4722.         local TRAIL_DOT_PARENT_NAME = "ClickToMoveDisplay"
  4723.        
  4724.         local TrailDotSize = Vector2.new(1.5, 1.5)
  4725.        
  4726.         local TRAIL_DOT_MIN_SCALE = 1
  4727.         local TRAIL_DOT_MIN_DISTANCE = 10
  4728.         local TRAIL_DOT_MAX_SCALE = 2.5
  4729.         local TRAIL_DOT_MAX_DISTANCE = 100
  4730.        
  4731.         local PlayersService = game:GetService("Players")
  4732.         local TweenService = game:GetService("TweenService")
  4733.         local RunService = game:GetService("RunService")
  4734.         local Workspace = game:GetService("Workspace")
  4735.        
  4736.         local LocalPlayer = PlayersService.LocalPlayer
  4737.        
  4738.         local function CreateWaypointTemplates()
  4739.                 local TrailDotTemplate = Instance.new("Part")
  4740.                 TrailDotTemplate.Size = Vector3.new(1, 1, 1)
  4741.                 TrailDotTemplate.Anchored = true
  4742.                 TrailDotTemplate.CanCollide = false
  4743.                 TrailDotTemplate.Name = "TrailDot"
  4744.                 TrailDotTemplate.Transparency = 1
  4745.                 local TrailDotImage = Instance.new("ImageHandleAdornment")
  4746.                 TrailDotImage.Name = "TrailDotImage"
  4747.                 TrailDotImage.Size = TrailDotSize
  4748.                 TrailDotImage.SizeRelativeOffset = Vector3.new(0, 0, -0.1)
  4749.                 TrailDotImage.AlwaysOnTop = WaypointsAlwaysOnTop
  4750.                 TrailDotImage.Image = TrailDotIcon
  4751.                 TrailDotImage.Adornee = TrailDotTemplate
  4752.                 TrailDotImage.Parent = TrailDotTemplate
  4753.        
  4754.                 local EndWaypointTemplate = Instance.new("Part")
  4755.                 EndWaypointTemplate.Size = Vector3.new(2, 2, 2)
  4756.                 EndWaypointTemplate.Anchored = true
  4757.                 EndWaypointTemplate.CanCollide = false
  4758.                 EndWaypointTemplate.Name = "EndWaypoint"
  4759.                 EndWaypointTemplate.Transparency = 1
  4760.                 local EndWaypointImage = Instance.new("ImageHandleAdornment")
  4761.                 EndWaypointImage.Name = "TrailDotImage"
  4762.                 EndWaypointImage.Size = TrailDotSize
  4763.                 EndWaypointImage.SizeRelativeOffset = Vector3.new(0, 0, -0.1)
  4764.                 EndWaypointImage.AlwaysOnTop = WaypointsAlwaysOnTop
  4765.                 EndWaypointImage.Image = TrailDotIcon
  4766.                 EndWaypointImage.Adornee = EndWaypointTemplate
  4767.                 EndWaypointImage.Parent = EndWaypointTemplate
  4768.                 local EndWaypointBillboard = Instance.new("BillboardGui")
  4769.                 EndWaypointBillboard.Name = "EndWaypointBillboard"
  4770.                 EndWaypointBillboard.Size = WAYPOINT_BILLBOARD_SIZE
  4771.                 EndWaypointBillboard.LightInfluence = 0
  4772.                 EndWaypointBillboard.SizeOffset = ENDWAYPOINT_SIZE_OFFSET_MIN
  4773.                 EndWaypointBillboard.AlwaysOnTop = true
  4774.                 EndWaypointBillboard.Adornee = EndWaypointTemplate
  4775.                 EndWaypointBillboard.Parent = EndWaypointTemplate
  4776.                 local EndWaypointImageLabel = Instance.new("ImageLabel")
  4777.                 EndWaypointImageLabel.Image = EndWaypointIcon
  4778.                 EndWaypointImageLabel.BackgroundTransparency = 1
  4779.                 EndWaypointImageLabel.Size = UDim2.new(1, 0, 1, 0)
  4780.                 EndWaypointImageLabel.Parent = EndWaypointBillboard
  4781.        
  4782.        
  4783.                 local FailureWaypointTemplate = Instance.new("Part")
  4784.                 FailureWaypointTemplate.Size = Vector3.new(2, 2, 2)
  4785.                 FailureWaypointTemplate.Anchored = true
  4786.                 FailureWaypointTemplate.CanCollide = false
  4787.                 FailureWaypointTemplate.Name = "FailureWaypoint"
  4788.                 FailureWaypointTemplate.Transparency = 1
  4789.                 local FailureWaypointImage = Instance.new("ImageHandleAdornment")
  4790.                 FailureWaypointImage.Name = "TrailDotImage"
  4791.                 FailureWaypointImage.Size = TrailDotSize
  4792.                 FailureWaypointImage.SizeRelativeOffset = Vector3.new(0, 0, -0.1)
  4793.                 FailureWaypointImage.AlwaysOnTop = WaypointsAlwaysOnTop
  4794.                 FailureWaypointImage.Image = TrailDotIcon
  4795.                 FailureWaypointImage.Adornee = FailureWaypointTemplate
  4796.                 FailureWaypointImage.Parent = FailureWaypointTemplate
  4797.                 local FailureWaypointBillboard = Instance.new("BillboardGui")
  4798.                 FailureWaypointBillboard.Name = "FailureWaypointBillboard"
  4799.                 FailureWaypointBillboard.Size = WAYPOINT_BILLBOARD_SIZE
  4800.                 FailureWaypointBillboard.LightInfluence = 0
  4801.                 FailureWaypointBillboard.SizeOffset = FAIL_WAYPOINT_SIZE_OFFSET_CENTER
  4802.                 FailureWaypointBillboard.AlwaysOnTop = true
  4803.                 FailureWaypointBillboard.Adornee = FailureWaypointTemplate
  4804.                 FailureWaypointBillboard.Parent = FailureWaypointTemplate
  4805.                 local FailureWaypointFrame = Instance.new("Frame")
  4806.                 FailureWaypointFrame.BackgroundTransparency = 1
  4807.                 FailureWaypointFrame.Size = UDim2.new(0, 0, 0, 0)
  4808.                 FailureWaypointFrame.Position = UDim2.new(0.5, 0, 1, 0)
  4809.                 FailureWaypointFrame.Parent = FailureWaypointBillboard
  4810.                 local FailureWaypointImageLabel = Instance.new("ImageLabel")
  4811.                 FailureWaypointImageLabel.Image = EndWaypointIcon
  4812.                 FailureWaypointImageLabel.BackgroundTransparency = 1
  4813.                 FailureWaypointImageLabel.Position = UDim2.new(
  4814.                         0, -WAYPOINT_BILLBOARD_SIZE.X.Offset/2, 0, -WAYPOINT_BILLBOARD_SIZE.Y.Offset
  4815.                 )
  4816.                 FailureWaypointImageLabel.Size = WAYPOINT_BILLBOARD_SIZE
  4817.                 FailureWaypointImageLabel.Parent = FailureWaypointFrame
  4818.        
  4819.                 return TrailDotTemplate, EndWaypointTemplate, FailureWaypointTemplate
  4820.         end
  4821.        
  4822.         local TrailDotTemplate, EndWaypointTemplate, FailureWaypointTemplate = CreateWaypointTemplates()
  4823.        
  4824.         local function getTrailDotParent()
  4825.                 local camera = Workspace.CurrentCamera
  4826.                 local trailParent = camera:FindFirstChild(TRAIL_DOT_PARENT_NAME)
  4827.                 if not trailParent then
  4828.                         trailParent = Instance.new("Model")
  4829.                         trailParent.Name = TRAIL_DOT_PARENT_NAME
  4830.                         trailParent.Parent = camera
  4831.                 end
  4832.                 return trailParent
  4833.         end
  4834.        
  4835.         local function placePathWaypoint(waypointModel, position)
  4836.                 local ray = Ray.new(position + Vector3.new(0, 2.5, 0), Vector3.new(0, -10, 0))
  4837.                 local hitPart, hitPoint, hitNormal = Workspace:FindPartOnRayWithIgnoreList(
  4838.                         ray,
  4839.                         { Workspace.CurrentCamera, LocalPlayer.Character }
  4840.                 )
  4841.                 if hitPart then
  4842.                         waypointModel.CFrame = CFrame.new(hitPoint, hitPoint + hitNormal)
  4843.                         waypointModel.Parent = getTrailDotParent()
  4844.                 end
  4845.         end
  4846.        
  4847.         local TrailDot = {}
  4848.         TrailDot.__index = TrailDot
  4849.        
  4850.         function TrailDot:Destroy()
  4851.                 self.DisplayModel:Destroy()
  4852.         end
  4853.        
  4854.         function TrailDot:NewDisplayModel(position)
  4855.                 local newDisplayModel = TrailDotTemplate:Clone()
  4856.                 placePathWaypoint(newDisplayModel, position)
  4857.                 return newDisplayModel
  4858.         end
  4859.        
  4860.         function TrailDot.new(position, closestWaypoint)
  4861.                 local self = setmetatable({}, TrailDot)
  4862.        
  4863.                 self.DisplayModel = self:NewDisplayModel(position)
  4864.                 self.ClosestWayPoint = closestWaypoint
  4865.        
  4866.                 return self
  4867.         end
  4868.        
  4869.         local EndWaypoint = {}
  4870.         EndWaypoint.__index = EndWaypoint
  4871.        
  4872.         function EndWaypoint:Destroy()
  4873.                 self.Destroyed = true
  4874.                 self.Tween:Cancel()
  4875.                 self.DisplayModel:Destroy()
  4876.         end
  4877.        
  4878.         function EndWaypoint:NewDisplayModel(position)
  4879.                 local newDisplayModel = EndWaypointTemplate:Clone()
  4880.                 placePathWaypoint(newDisplayModel, position)
  4881.                 return newDisplayModel
  4882.         end
  4883.        
  4884.         function EndWaypoint:CreateTween()
  4885.                 local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, -1, true)
  4886.                 local tween = TweenService:Create(
  4887.                         self.DisplayModel.EndWaypointBillboard,
  4888.                         tweenInfo,
  4889.                         { SizeOffset = ENDWAYPOINT_SIZE_OFFSET_MAX }
  4890.                 )
  4891.                 tween:Play()
  4892.                 return tween
  4893.         end
  4894.        
  4895.         function EndWaypoint:TweenInFrom(originalPosition)
  4896.                 local currentPositon = self.DisplayModel.Position
  4897.                 local studsOffset = originalPosition - currentPositon
  4898.                 self.DisplayModel.EndWaypointBillboard.StudsOffset = Vector3.new(0, studsOffset.Y, 0)
  4899.                 local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)
  4900.                 local tween = TweenService:Create(
  4901.                         self.DisplayModel.EndWaypointBillboard,
  4902.                         tweenInfo,
  4903.                         { StudsOffset = Vector3.new(0, 0, 0) }
  4904.                 )
  4905.                 tween:Play()
  4906.                 return tween
  4907.         end
  4908.        
  4909.         function EndWaypoint.new(position, closestWaypoint, originalPosition)
  4910.                 local self = setmetatable({}, EndWaypoint)
  4911.        
  4912.                 self.DisplayModel = self:NewDisplayModel(position)
  4913.                 self.Destroyed = false
  4914.                 if originalPosition and (originalPosition - position).magnitude > TWEEN_WAYPOINT_THRESHOLD then
  4915.                         self.Tween = self:TweenInFrom(originalPosition)
  4916.                         coroutine.wrap(function()
  4917.                                 self.Tween.Completed:Wait()
  4918.                                 if not self.Destroyed then
  4919.                                         self.Tween = self:CreateTween()
  4920.                                 end
  4921.                         end)()
  4922.                 else
  4923.                         self.Tween = self:CreateTween()
  4924.                 end
  4925.                 self.ClosestWayPoint = closestWaypoint
  4926.        
  4927.                 return self
  4928.         end
  4929.        
  4930.         local FailureWaypoint = {}
  4931.         FailureWaypoint.__index = FailureWaypoint
  4932.        
  4933.         function FailureWaypoint:Hide()
  4934.                 self.DisplayModel.Parent = nil
  4935.         end
  4936.        
  4937.         function FailureWaypoint:Destroy()
  4938.                 self.DisplayModel:Destroy()
  4939.         end
  4940.        
  4941.         function FailureWaypoint:NewDisplayModel(position)
  4942.                 local newDisplayModel = FailureWaypointTemplate:Clone()
  4943.                 placePathWaypoint(newDisplayModel, position)
  4944.                 local ray = Ray.new(position + Vector3.new(0, 2.5, 0), Vector3.new(0, -10, 0))
  4945.                 local hitPart, hitPoint, hitNormal = Workspace:FindPartOnRayWithIgnoreList(
  4946.                         ray, { Workspace.CurrentCamera, LocalPlayer.Character }
  4947.                 )
  4948.                 if hitPart then
  4949.                         newDisplayModel.CFrame = CFrame.new(hitPoint, hitPoint + hitNormal)
  4950.                         newDisplayModel.Parent = getTrailDotParent()
  4951.                 end
  4952.                 return newDisplayModel
  4953.         end
  4954.        
  4955.         function FailureWaypoint:RunFailureTween()
  4956.                 wait(FAILURE_TWEEN_LENGTH) -- Delay one tween length betfore starting tweening
  4957.                 -- Tween out from center
  4958.                 local tweenInfo = TweenInfo.new(FAILURE_TWEEN_LENGTH/2, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)
  4959.                 local tweenLeft = TweenService:Create(self.DisplayModel.FailureWaypointBillboard, tweenInfo,
  4960.                         { SizeOffset = FAIL_WAYPOINT_SIZE_OFFSET_LEFT })
  4961.                 tweenLeft:Play()
  4962.        
  4963.                 local tweenLeftRoation = TweenService:Create(self.DisplayModel.FailureWaypointBillboard.Frame, tweenInfo,
  4964.                         { Rotation = 10 })
  4965.                 tweenLeftRoation:Play()
  4966.        
  4967.                 tweenLeft.Completed:wait()
  4968.        
  4969.                 -- Tween back and forth
  4970.                 tweenInfo = TweenInfo.new(FAILURE_TWEEN_LENGTH, Enum.EasingStyle.Sine, Enum.EasingDirection.Out,
  4971.                         FAILURE_TWEEN_COUNT - 1, true)
  4972.                 local tweenSideToSide = TweenService:Create(self.DisplayModel.FailureWaypointBillboard, tweenInfo,
  4973.                         { SizeOffset = FAIL_WAYPOINT_SIZE_OFFSET_RIGHT})
  4974.                 tweenSideToSide:Play()
  4975.        
  4976.                 -- Tween flash dark and roate left and right
  4977.                 tweenInfo = TweenInfo.new(FAILURE_TWEEN_LENGTH, Enum.EasingStyle.Sine, Enum.EasingDirection.Out,
  4978.                         FAILURE_TWEEN_COUNT - 1, true)
  4979.                 local tweenFlash = TweenService:Create(self.DisplayModel.FailureWaypointBillboard.Frame.ImageLabel, tweenInfo,
  4980.                         { ImageColor3 = Color3.new(0.75, 0.75, 0.75)})
  4981.                 tweenFlash:Play()
  4982.        
  4983.                 local tweenRotate = TweenService:Create(self.DisplayModel.FailureWaypointBillboard.Frame, tweenInfo,
  4984.                         { Rotation = -10 })
  4985.                 tweenRotate:Play()
  4986.        
  4987.                 tweenSideToSide.Completed:wait()
  4988.        
  4989.                 -- Tween back to center
  4990.                 tweenInfo = TweenInfo.new(FAILURE_TWEEN_LENGTH/2, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)
  4991.                 local tweenCenter = TweenService:Create(self.DisplayModel.FailureWaypointBillboard, tweenInfo,
  4992.                         { SizeOffset = FAIL_WAYPOINT_SIZE_OFFSET_CENTER })
  4993.                 tweenCenter:Play()
  4994.        
  4995.                 local tweenRoation = TweenService:Create(self.DisplayModel.FailureWaypointBillboard.Frame, tweenInfo,
  4996.                         { Rotation = 0 })
  4997.                 tweenRoation:Play()
  4998.        
  4999.                 tweenCenter.Completed:wait()
  5000.        
  5001.                 wait(FAILURE_TWEEN_LENGTH) -- Delay one tween length betfore removing
  5002.         end
  5003.        
  5004.         function FailureWaypoint.new(position)
  5005.                 local self = setmetatable({}, FailureWaypoint)
  5006.        
  5007.                 self.DisplayModel = self:NewDisplayModel(position)
  5008.        
  5009.                 return self
  5010.         end
  5011.        
  5012.         local failureAnimation = Instance.new("Animation")
  5013.         failureAnimation.AnimationId = FAILURE_ANIMATION_ID
  5014.        
  5015.         local lastHumanoid = nil
  5016.         local lastFailureAnimationTrack = nil
  5017.        
  5018.         local function getFailureAnimationTrack(myHumanoid)
  5019.                 if myHumanoid == lastHumanoid then
  5020.                         return lastFailureAnimationTrack
  5021.                 end
  5022.                 lastFailureAnimationTrack = myHumanoid:LoadAnimation(failureAnimation)
  5023.                 lastFailureAnimationTrack.Priority = Enum.AnimationPriority.Action
  5024.                 lastFailureAnimationTrack.Looped = false
  5025.                 return lastFailureAnimationTrack
  5026.         end
  5027.        
  5028.         local function findPlayerHumanoid()
  5029.                 local character = LocalPlayer.Character
  5030.                 if character then
  5031.                         return character:FindFirstChildOfClass("Humanoid")
  5032.                 end
  5033.         end
  5034.        
  5035.         local function createTrailDots(wayPoints, originalEndWaypoint)
  5036.                 local newTrailDots = {}
  5037.                 local count = 1
  5038.                 for i = 1, #wayPoints - 1 do
  5039.                         local closeToEnd = (wayPoints[i].Position - wayPoints[#wayPoints].Position).magnitude < LAST_DOT_DISTANCE
  5040.                         local includeWaypoint = i % WAYPOINT_INCLUDE_FACTOR == 0 and not closeToEnd
  5041.                         if includeWaypoint then
  5042.                                 local trailDot = TrailDot.new(wayPoints[i].Position, i)
  5043.                                 newTrailDots[count] = trailDot
  5044.                                 count = count + 1
  5045.                         end
  5046.                 end
  5047.        
  5048.                 local newEndWaypoint = EndWaypoint.new(wayPoints[#wayPoints].Position, #wayPoints, originalEndWaypoint)
  5049.                 table.insert(newTrailDots, newEndWaypoint)
  5050.        
  5051.                 local reversedTrailDots = {}
  5052.                 count = 1
  5053.                 for i = #newTrailDots, 1, -1 do
  5054.                         reversedTrailDots[count] = newTrailDots[i]
  5055.                         count = count + 1
  5056.                 end
  5057.                 return reversedTrailDots
  5058.         end
  5059.        
  5060.         local function getTrailDotScale(distanceToCamera, defaultSize)
  5061.                 local rangeLength = TRAIL_DOT_MAX_DISTANCE - TRAIL_DOT_MIN_DISTANCE
  5062.                 local inRangePoint = math.clamp(distanceToCamera - TRAIL_DOT_MIN_DISTANCE, 0, rangeLength)/rangeLength
  5063.                 local scale = TRAIL_DOT_MIN_SCALE + (TRAIL_DOT_MAX_SCALE - TRAIL_DOT_MIN_SCALE)*inRangePoint
  5064.                 return defaultSize * scale
  5065.         end
  5066.        
  5067.         local createPathCount = 0
  5068.         -- originalEndWaypoint is optional, causes the waypoint to tween from that position.
  5069.         function ClickToMoveDisplay.CreatePathDisplay(wayPoints, originalEndWaypoint)
  5070.                 createPathCount = createPathCount + 1
  5071.                 local trailDots = createTrailDots(wayPoints, originalEndWaypoint)
  5072.        
  5073.                 local function removePathBeforePoint(wayPointNumber)
  5074.                         -- kill all trailDots before and at wayPointNumber
  5075.                         for i = #trailDots, 1, -1 do
  5076.                                 local trailDot = trailDots[i]
  5077.                                 if trailDot.ClosestWayPoint  0 then
  5078.                                                 self.jumpButton.Visible = true
  5079.                                         end
  5080.                                 end
  5081.                         end
  5082.                 else
  5083.                         self.jumpButton.Visible = false
  5084.                         self.isJumping = false
  5085.                         self.jumpButton.ImageRectOffset = Vector2.new(1, 146)
  5086.                 end
  5087.         end
  5088.        
  5089.         function TouchJump:UpdateEnabled()
  5090.                 if self.jumpPower > 0 and self.jumpStateEnabled then
  5091.                         self:EnableButton(true)
  5092.                 else
  5093.                         self:EnableButton(false)
  5094.                 end
  5095.         end
  5096.        
  5097.         function TouchJump:HumanoidChanged(prop)
  5098.                 local humanoid = Players.LocalPlayer.Character and Players.LocalPlayer.Character:FindFirstChildOfClass("Humanoid")
  5099.                 if humanoid then
  5100.                         if prop == "JumpPower" then
  5101.                                 self.jumpPower =  humanoid.JumpPower
  5102.                                 self:UpdateEnabled()
  5103.                         elseif prop == "Parent" then
  5104.                                 if not humanoid.Parent then
  5105.                                         self.humanoidChangeConn:Disconnect()
  5106.                                 end
  5107.                         end
  5108.                 end
  5109.         end
  5110.        
  5111.         function TouchJump:HumanoidStateEnabledChanged(state, isEnabled)
  5112.                 if state == Enum.HumanoidStateType.Jumping then
  5113.                         self.jumpStateEnabled = isEnabled
  5114.                         self:UpdateEnabled()
  5115.                 end
  5116.         end
  5117.        
  5118.         function TouchJump:CharacterAdded(char)
  5119.                 if self.humanoidChangeConn then
  5120.                         self.humanoidChangeConn:Disconnect()
  5121.                         self.humanoidChangeConn = nil
  5122.                 end
  5123.        
  5124.                 self.humanoid = char:FindFirstChildOfClass("Humanoid")
  5125.                 while not self.humanoid do
  5126.                         char.ChildAdded:wait()
  5127.                         self.humanoid = char:FindFirstChildOfClass("Humanoid")
  5128.                 end
  5129.        
  5130.                 self.humanoidJumpPowerConn = self.humanoid:GetPropertyChangedSignal("JumpPower"):Connect(function()
  5131.                         self.jumpPower =  self.humanoid.JumpPower
  5132.                         self:UpdateEnabled()
  5133.                 end)
  5134.        
  5135.                 self.humanoidParentConn = self.humanoid:GetPropertyChangedSignal("Parent"):Connect(function()
  5136.                         if not self.humanoid.Parent then
  5137.                                 self.humanoidJumpPowerConn:Disconnect()
  5138.                                 self.humanoidJumpPowerConn = nil
  5139.                                 self.humanoidParentConn:Disconnect()
  5140.                                 self.humanoidParentConn = nil
  5141.                         end
  5142.                 end)
  5143.        
  5144.                 self.humanoidStateEnabledChangedConn = self.humanoid.StateEnabledChanged:Connect(function(state, enabled)
  5145.                         self:HumanoidStateEnabledChanged(state, enabled)
  5146.                 end)
  5147.        
  5148.                 self.jumpPower = self.humanoid.JumpPower
  5149.                 self.jumpStateEnabled = self.humanoid:GetStateEnabled(Enum.HumanoidStateType.Jumping)
  5150.                 self:UpdateEnabled()
  5151.         end
  5152.        
  5153.         function TouchJump:SetupCharacterAddedFunction()
  5154.                 self.characterAddedConn = Players.LocalPlayer.CharacterAdded:Connect(function(char)
  5155.                         self:CharacterAdded(char)
  5156.                 end)
  5157.                 if Players.LocalPlayer.Character then
  5158.                         self:CharacterAdded(Players.LocalPlayer.Character)
  5159.                 end
  5160.         end
  5161.        
  5162.         function TouchJump:Enable(enable, parentFrame)
  5163.                 if parentFrame then
  5164.                         self.parentUIFrame = parentFrame
  5165.                 end
  5166.                 self.externallyEnabled = enable
  5167.                 self:EnableButton(enable)
  5168.         end
  5169.        
  5170.         function TouchJump:Create()
  5171.                 if not self.parentUIFrame then
  5172.                         return
  5173.                 end
  5174.        
  5175.                 if self.jumpButton then
  5176.                         self.jumpButton:Destroy()
  5177.                         self.jumpButton = nil
  5178.                 end
  5179.        
  5180.                 local minAxis = math.min(self.parentUIFrame.AbsoluteSize.x, self.parentUIFrame.AbsoluteSize.y)
  5181.                 local isSmallScreen = minAxis  ALMOST_ZERO then
  5182.                                 this.CurrentWaypointPlaneNormal = this.CurrentWaypointPlaneNormal.Unit
  5183.                                 this.CurrentWaypointPlaneDistance = this.CurrentWaypointPlaneNormal:Dot(nextWaypoint.Position)
  5184.                         else
  5185.                                 -- Next waypoint is the same as current waypoint so no plane
  5186.                                 this.CurrentWaypointPlaneNormal = ZERO_VECTOR3
  5187.                                 this.CurrentWaypointPlaneDistance = 0
  5188.                         end
  5189.        
  5190.                         -- Should we jump
  5191.                         this.CurrentWaypointNeedsJump = nextWaypoint.Action == Enum.PathWaypointAction.Jump;
  5192.        
  5193.                         -- Remember next waypoint position
  5194.                         this.CurrentWaypointPosition = nextWaypoint.Position
  5195.        
  5196.                         -- Move to next point
  5197.                         this.CurrentPoint = nextWaypointIdx
  5198.        
  5199.                         -- Finally reset Timeout
  5200.                         this.Timeout = 0
  5201.                 end
  5202.        
  5203.                 function this:Start(overrideShowPath)
  5204.                         if not this.AgentCanFollowPath then
  5205.                                 this.PathFailed:Fire()
  5206.                                 return
  5207.                         end
  5208.        
  5209.                         if this.Started then return end
  5210.                         this.Started = true
  5211.        
  5212.                         ClickToMoveDisplay.CancelFailureAnimation()
  5213.        
  5214.                         if ShowPath then
  5215.                                 if overrideShowPath == nil or overrideShowPath then
  5216.                                         this.stopTraverseFunc, this.setPointFunc = ClickToMoveDisplay.CreatePathDisplay(this.pointList, this.OriginalTargetPoint)
  5217.                                 end
  5218.                         end
  5219.        
  5220.                         if #this.pointList > 0 then
  5221.                                 -- Determine the humanoid offset from the path's first point
  5222.                                 -- Offset of the first waypoint from the path's origin point
  5223.                                 this.HumanoidOffsetFromPath = Vector3.new(0, this.pointList[1].Position.Y - this.OriginPoint.Y, 0)
  5224.        
  5225.                                 -- As well as its current position and velocity
  5226.                                 this.CurrentHumanoidPosition = this.Humanoid.RootPart.Position + this.HumanoidOffsetFromPath
  5227.                                 this.CurrentHumanoidVelocity = this.Humanoid.RootPart.Velocity
  5228.        
  5229.                                 -- Connect to events
  5230.                                 this.SeatedConn = this.Humanoid.Seated:Connect(function(isSeated, seat) this:OnPathInterrupted() end)
  5231.                                 this.DiedConn = this.Humanoid.Died:Connect(function() this:OnPathInterrupted() end)
  5232.                                 this.TeleportedConn = this.Humanoid.RootPart:GetPropertyChangedSignal("CFrame"):Connect(function() this:OnPathInterrupted() end)
  5233.        
  5234.                                 -- Actually start
  5235.                                 this.CurrentPoint = 1 -- The first waypoint is always the start location. Skip it.
  5236.                                 this:OnPointReached(true) -- Move to first point
  5237.                         else
  5238.                                 this.PathFailed:Fire()
  5239.                                 if this.stopTraverseFunc then
  5240.                                         this.stopTraverseFunc()
  5241.                                 end
  5242.                         end
  5243.                 end
  5244.        
  5245.                 --We always raycast to the ground in the case that the user clicked a wall.
  5246.                 local offsetPoint = this.TargetPoint + this.TargetSurfaceNormal*1.5
  5247.                 local ray = Ray.new(offsetPoint, Vector3.new(0,-1,0)*50)
  5248.                 local newHitPart, newHitPos = Workspace:FindPartOnRayWithIgnoreList(ray, getIgnoreList())
  5249.                 if newHitPart then
  5250.                         this.TargetPoint = newHitPos
  5251.                 end
  5252.                 this:ComputePath()
  5253.        
  5254.                 return this
  5255.         end
  5256.        
  5257.         -------------------------------------------------------------------------
  5258.        
  5259.         local function CheckAlive()
  5260.                 local humanoid = findPlayerHumanoid(Player)
  5261.                 return humanoid ~= nil and humanoid.Health > 0
  5262.         end
  5263.        
  5264.         local function GetEquippedTool(character)
  5265.                 if character ~= nil then
  5266.                         for _, child in pairs(character:GetChildren()) do
  5267.                                 if child:IsA('Tool') then
  5268.                                         return child
  5269.                                 end
  5270.                         end
  5271.                 end
  5272.         end
  5273.        
  5274.         local ExistingPather = nil
  5275.         local ExistingIndicator = nil
  5276.         local PathCompleteListener = nil
  5277.         local PathFailedListener = nil
  5278.        
  5279.         local function CleanupPath()
  5280.                 if ExistingPather then
  5281.                         ExistingPather:Cancel()
  5282.                         ExistingPather = nil
  5283.                 end
  5284.                 if PathCompleteListener then
  5285.                         PathCompleteListener:Disconnect()
  5286.                         PathCompleteListener = nil
  5287.                 end
  5288.                 if PathFailedListener then
  5289.                         PathFailedListener:Disconnect()
  5290.                         PathFailedListener = nil
  5291.                 end
  5292.                 if ExistingIndicator then
  5293.                         ExistingIndicator:Destroy()
  5294.                 end
  5295.         end
  5296.        
  5297.         local function HandleMoveTo(thisPather, hitPt, hitChar, character, overrideShowPath)
  5298.                 if ExistingPather then
  5299.                         CleanupPath()
  5300.                 end
  5301.                 ExistingPather = thisPather
  5302.                 thisPather:Start(overrideShowPath)
  5303.        
  5304.                 PathCompleteListener = thisPather.Finished.Event:Connect(function()
  5305.                         CleanupPath()
  5306.                         if hitChar then
  5307.                                 local currentWeapon = GetEquippedTool(character)
  5308.                                 if currentWeapon then
  5309.                                         currentWeapon:Activate()
  5310.                                 end
  5311.                         end
  5312.                 end)
  5313.                 PathFailedListener = thisPather.PathFailed.Event:Connect(function()
  5314.                         CleanupPath()
  5315.                         if overrideShowPath == nil or overrideShowPath then
  5316.                                 local shouldPlayFailureAnim = PlayFailureAnimation and not (ExistingPather and ExistingPather:IsActive())
  5317.                                 if shouldPlayFailureAnim then
  5318.                                         ClickToMoveDisplay.PlayFailureAnimation()
  5319.                                 end
  5320.                                 ClickToMoveDisplay.DisplayFailureWaypoint(hitPt)
  5321.                         end
  5322.                 end)
  5323.         end
  5324.        
  5325.         local function ShowPathFailedFeedback(hitPt)
  5326.                 if ExistingPather and ExistingPather:IsActive() then
  5327.                         ExistingPather:Cancel()
  5328.                 end
  5329.                 if PlayFailureAnimation then
  5330.                         ClickToMoveDisplay.PlayFailureAnimation()
  5331.                 end
  5332.                 ClickToMoveDisplay.DisplayFailureWaypoint(hitPt)
  5333.         end
  5334.        
  5335.         function OnTap(tapPositions, goToPoint, wasTouchTap)
  5336.                 -- Good to remember if this is the latest tap event
  5337.                 local camera = Workspace.CurrentCamera
  5338.                 local character = Player.Character
  5339.        
  5340.                 if not CheckAlive() then return end
  5341.        
  5342.                 -- This is a path tap position
  5343.                 if #tapPositions == 1 or goToPoint then
  5344.                         if camera then
  5345.                                 local unitRay = camera:ScreenPointToRay(tapPositions[1].x, tapPositions[1].y)
  5346.                                 local ray = Ray.new(unitRay.Origin, unitRay.Direction*1000)
  5347.        
  5348.                                 local myHumanoid = findPlayerHumanoid(Player)
  5349.                                 local hitPart, hitPt, hitNormal = Utility.Raycast(ray, true, getIgnoreList())
  5350.        
  5351.                                 local hitChar, hitHumanoid = Utility.FindCharacterAncestor(hitPart)
  5352.                                 if wasTouchTap and hitHumanoid and StarterGui:GetCore("AvatarContextMenuEnabled") then
  5353.                                         local clickedPlayer = Players:GetPlayerFromCharacter(hitHumanoid.Parent)
  5354.                                         if clickedPlayer then
  5355.                                                 CleanupPath()
  5356.                                                 return
  5357.                                         end
  5358.                                 end
  5359.                                 if goToPoint then
  5360.                                         hitPt = goToPoint
  5361.                                         hitChar = nil
  5362.                                 end
  5363.                                 if hitPt and character then
  5364.                                         -- Clean up current path
  5365.                                         CleanupPath()
  5366.                                         local thisPather = Pather(hitPt, hitNormal)
  5367.                                         if thisPather:IsValidPath() then
  5368.                                                 HandleMoveTo(thisPather, hitPt, hitChar, character)
  5369.                                         else
  5370.                                                 -- Clean up
  5371.                                                 thisPather:Cleanup()
  5372.                                                 -- Feedback here for when we don't have a good path
  5373.                                                 ShowPathFailedFeedback(hitPt)
  5374.                                         end
  5375.                                 end
  5376.                         end
  5377.                 elseif #tapPositions >= 2 then
  5378.                         if camera then
  5379.                                 -- Do shoot
  5380.                                 local currentWeapon = GetEquippedTool(character)
  5381.                                 if currentWeapon then
  5382.                                         currentWeapon:Activate()
  5383.                                 end
  5384.                         end
  5385.                 end
  5386.         end
  5387.        
  5388.         local function DisconnectEvent(event)
  5389.                 if event then
  5390.                         event:Disconnect()
  5391.                 end
  5392.         end
  5393.        
  5394.         --[[ The ClickToMove Controller Class ]]--
  5395.         local KeyboardController = _Keyboard()
  5396.         local ClickToMove = setmetatable({}, KeyboardController)
  5397.         ClickToMove.__index = ClickToMove
  5398.        
  5399.         function ClickToMove.new(CONTROL_ACTION_PRIORITY)
  5400.                 local self = setmetatable(KeyboardController.new(CONTROL_ACTION_PRIORITY), ClickToMove)
  5401.        
  5402.                 self.fingerTouches = {}
  5403.                 self.numUnsunkTouches = 0
  5404.                 -- PC simulation
  5405.                 self.mouse1Down = tick()
  5406.                 self.mouse1DownPos = Vector2.new()
  5407.                 self.mouse2DownTime = tick()
  5408.                 self.mouse2DownPos = Vector2.new()
  5409.                 self.mouse2UpTime = tick()
  5410.        
  5411.                 self.keyboardMoveVector = ZERO_VECTOR3
  5412.        
  5413.                 self.tapConn = nil
  5414.                 self.inputBeganConn = nil
  5415.                 self.inputChangedConn = nil
  5416.                 self.inputEndedConn = nil
  5417.                 self.humanoidDiedConn = nil
  5418.                 self.characterChildAddedConn = nil
  5419.                 self.onCharacterAddedConn = nil
  5420.                 self.characterChildRemovedConn = nil
  5421.                 self.renderSteppedConn = nil
  5422.                 self.menuOpenedConnection = nil
  5423.        
  5424.                 self.running = false
  5425.        
  5426.                 self.wasdEnabled = false
  5427.        
  5428.                 return self
  5429.         end
  5430.        
  5431.         function ClickToMove:DisconnectEvents()
  5432.                 DisconnectEvent(self.tapConn)
  5433.                 DisconnectEvent(self.inputBeganConn)
  5434.                 DisconnectEvent(self.inputChangedConn)
  5435.                 DisconnectEvent(self.inputEndedConn)
  5436.                 DisconnectEvent(self.humanoidDiedConn)
  5437.                 DisconnectEvent(self.characterChildAddedConn)
  5438.                 DisconnectEvent(self.onCharacterAddedConn)
  5439.                 DisconnectEvent(self.renderSteppedConn)
  5440.                 DisconnectEvent(self.characterChildRemovedConn)
  5441.                 DisconnectEvent(self.menuOpenedConnection)
  5442.         end
  5443.        
  5444.         function ClickToMove:OnTouchBegan(input, processed)
  5445.                 if self.fingerTouches[input] == nil and not processed then
  5446.                         self.numUnsunkTouches = self.numUnsunkTouches + 1
  5447.                 end
  5448.                 self.fingerTouches[input] = processed
  5449.         end
  5450.        
  5451.         function ClickToMove:OnTouchChanged(input, processed)
  5452.                 if self.fingerTouches[input] == nil then
  5453.                         self.fingerTouches[input] = processed
  5454.                         if not processed then
  5455.                                 self.numUnsunkTouches = self.numUnsunkTouches + 1
  5456.                         end
  5457.                 end
  5458.         end
  5459.        
  5460.         function ClickToMove:OnTouchEnded(input, processed)
  5461.                 if self.fingerTouches[input] ~= nil and self.fingerTouches[input] == false then
  5462.                         self.numUnsunkTouches = self.numUnsunkTouches - 1
  5463.                 end
  5464.                 self.fingerTouches[input] = nil
  5465.         end
  5466.        
  5467.        
  5468.         function ClickToMove:OnCharacterAdded(character)
  5469.                 self:DisconnectEvents()
  5470.        
  5471.                 self.inputBeganConn = UserInputService.InputBegan:Connect(function(input, processed)
  5472.                         if input.UserInputType == Enum.UserInputType.Touch then
  5473.                                 self:OnTouchBegan(input, processed)
  5474.                         end
  5475.        
  5476.                         -- Cancel path when you use the keyboard controls if wasd is enabled.
  5477.                         if self.wasdEnabled and processed == false and input.UserInputType == Enum.UserInputType.Keyboard
  5478.                                 and movementKeys[input.KeyCode] then
  5479.                                 CleanupPath()
  5480.                                 ClickToMoveDisplay.CancelFailureAnimation()
  5481.                         end
  5482.                         if input.UserInputType == Enum.UserInputType.MouseButton1 then
  5483.                                 self.mouse1DownTime = tick()
  5484.                                 self.mouse1DownPos = input.Position
  5485.                         end
  5486.                         if input.UserInputType == Enum.UserInputType.MouseButton2 then
  5487.                                 self.mouse2DownTime = tick()
  5488.                                 self.mouse2DownPos = input.Position
  5489.                         end
  5490.                 end)
  5491.        
  5492.                 self.inputChangedConn = UserInputService.InputChanged:Connect(function(input, processed)
  5493.                         if input.UserInputType == Enum.UserInputType.Touch then
  5494.                                 self:OnTouchChanged(input, processed)
  5495.                         end
  5496.                 end)
  5497.        
  5498.                 self.inputEndedConn = UserInputService.InputEnded:Connect(function(input, processed)
  5499.                         if input.UserInputType == Enum.UserInputType.Touch then
  5500.                                 self:OnTouchEnded(input, processed)
  5501.                         end
  5502.        
  5503.                         if input.UserInputType == Enum.UserInputType.MouseButton2 then
  5504.                                 self.mouse2UpTime = tick()
  5505.                                 local currPos = input.Position
  5506.                                 -- We allow click to move during path following or if there is no keyboard movement
  5507.                                 local allowed = ExistingPather or self.keyboardMoveVector.Magnitude = frameCornerTopLeft.X and inputPosition.Y >= frameCornerTopLeft.Y then
  5508.                         if inputPosition.X  0 then
  5509.                                         self:DoMove(direction)
  5510.                                         self:MoveStick(inputObject.Position)
  5511.                                 end
  5512.                                 return Enum.ContextActionResult.Sink
  5513.                         end
  5514.                         return Enum.ContextActionResult.Pass
  5515.                 end
  5516.        
  5517.                 local function inputEnded(inputObject)
  5518.                         if inputObject == self.moveTouchObject then
  5519.                                 self:OnInputEnded()
  5520.                                 if self.moveTouchLockedIn then
  5521.                                         return Enum.ContextActionResult.Sink
  5522.                                 end
  5523.                         end
  5524.                         return Enum.ContextActionResult.Pass
  5525.                 end
  5526.        
  5527.                 local function handleInput(actionName, inputState, inputObject)
  5528.                         if inputState == Enum.UserInputState.Begin then
  5529.                                 return inputBegan(inputObject)
  5530.                         elseif inputState == Enum.UserInputState.Change then
  5531.                                 return inputChanged(inputObject)
  5532.                         elseif inputState == Enum.UserInputState.End then
  5533.                                 return inputEnded(inputObject)
  5534.                         elseif inputState == Enum.UserInputState.Cancel then
  5535.                                 self:OnInputEnded()
  5536.                         end
  5537.                 end
  5538.        
  5539.                 ContextActionService:BindActionAtPriority(
  5540.                         DYNAMIC_THUMBSTICK_ACTION_NAME,
  5541.                         handleInput,
  5542.                         false,
  5543.                         DYNAMIC_THUMBSTICK_ACTION_PRIORITY,
  5544.                         Enum.UserInputType.Touch)
  5545.         end
  5546.        
  5547.         function DynamicThumbstick:Create(parentFrame)
  5548.                 if self.thumbstickFrame then
  5549.                         self.thumbstickFrame:Destroy()
  5550.                         self.thumbstickFrame = nil
  5551.                         if self.onRenderSteppedConn then
  5552.                                 self.onRenderSteppedConn:Disconnect()
  5553.                                 self.onRenderSteppedConn = nil
  5554.                         end
  5555.                 end
  5556.        
  5557.                 self.thumbstickSize = 45
  5558.                 self.thumbstickRingSize = 20
  5559.                 self.middleSize = 10
  5560.                 self.middleSpacing = self.middleSize + 4
  5561.                 self.radiusOfDeadZone = 2
  5562.                 self.radiusOfMaxSpeed = 20
  5563.        
  5564.                 local screenSize = parentFrame.AbsoluteSize
  5565.                 local isBigScreen = math.min(screenSize.x, screenSize.y) > 500
  5566.                 if isBigScreen then
  5567.                         self.thumbstickSize = self.thumbstickSize * 2
  5568.                         self.thumbstickRingSize = self.thumbstickRingSize * 2
  5569.                         self.middleSize = self.middleSize * 2
  5570.                         self.middleSpacing = self.middleSpacing * 2
  5571.                         self.radiusOfDeadZone = self.radiusOfDeadZone * 2
  5572.                         self.radiusOfMaxSpeed = self.radiusOfMaxSpeed * 2
  5573.                 end
  5574.        
  5575.                 local function layoutThumbstickFrame(portraitMode)
  5576.                         if portraitMode then
  5577.                                 self.thumbstickFrame.Size = UDim2.new(1, 0, 0.4, 0)
  5578.                                 self.thumbstickFrame.Position = UDim2.new(0, 0, 0.6, 0)
  5579.                         else
  5580.                                 self.thumbstickFrame.Size = UDim2.new(0.4, 0, 2/3, 0)
  5581.                                 self.thumbstickFrame.Position = UDim2.new(0, 0, 1/3, 0)
  5582.                         end
  5583.                 end
  5584.        
  5585.                 self.thumbstickFrame = Instance.new("Frame")
  5586.                 self.thumbstickFrame.BorderSizePixel = 0
  5587.                 self.thumbstickFrame.Name = "DynamicThumbstickFrame"
  5588.                 self.thumbstickFrame.Visible = false
  5589.                 self.thumbstickFrame.BackgroundTransparency = 1.0
  5590.                 self.thumbstickFrame.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
  5591.                 self.thumbstickFrame.Active = false
  5592.                 layoutThumbstickFrame(false)
  5593.        
  5594.                 self.startImage = Instance.new("ImageLabel")
  5595.                 self.startImage.Name = "ThumbstickStart"
  5596.                 self.startImage.Visible = true
  5597.                 self.startImage.BackgroundTransparency = 1
  5598.                 self.startImage.Image = TOUCH_CONTROLS_SHEET
  5599.                 self.startImage.ImageRectOffset = Vector2.new(1,1)
  5600.                 self.startImage.ImageRectSize = Vector2.new(144, 144)
  5601.                 self.startImage.ImageColor3 = Color3.new(0, 0, 0)
  5602.                 self.startImage.AnchorPoint = Vector2.new(0.5, 0.5)
  5603.                 self.startImage.Position = UDim2.new(0, self.thumbstickRingSize * 3.3, 1, -self.thumbstickRingSize  * 2.8)
  5604.                 self.startImage.Size = UDim2.new(0, self.thumbstickRingSize  * 3.7, 0, self.thumbstickRingSize  * 3.7)
  5605.                 self.startImage.ZIndex = 10
  5606.                 self.startImage.Parent = self.thumbstickFrame
  5607.        
  5608.                 self.endImage = Instance.new("ImageLabel")
  5609.                 self.endImage.Name = "ThumbstickEnd"
  5610.                 self.endImage.Visible = true
  5611.                 self.endImage.BackgroundTransparency = 1
  5612.                 self.endImage.Image = TOUCH_CONTROLS_SHEET
  5613.                 self.endImage.ImageRectOffset = Vector2.new(1,1)
  5614.                 self.endImage.ImageRectSize =  Vector2.new(144, 144)
  5615.                 self.endImage.AnchorPoint = Vector2.new(0.5, 0.5)
  5616.                 self.endImage.Position = self.startImage.Position
  5617.                 self.endImage.Size = UDim2.new(0, self.thumbstickSize * 0.8, 0, self.thumbstickSize * 0.8)
  5618.                 self.endImage.ZIndex = 10
  5619.                 self.endImage.Parent = self.thumbstickFrame
  5620.        
  5621.                 for i = 1, NUM_MIDDLE_IMAGES do
  5622.                         self.middleImages[i] = Instance.new("ImageLabel")
  5623.                         self.middleImages[i].Name = "ThumbstickMiddle"
  5624.                         self.middleImages[i].Visible = false
  5625.                         self.middleImages[i].BackgroundTransparency = 1
  5626.                         self.middleImages[i].Image = TOUCH_CONTROLS_SHEET
  5627.                         self.middleImages[i].ImageRectOffset = Vector2.new(1,1)
  5628.                         self.middleImages[i].ImageRectSize = Vector2.new(144, 144)
  5629.                         self.middleImages[i].ImageTransparency = MIDDLE_TRANSPARENCIES[i]
  5630.                         self.middleImages[i].AnchorPoint = Vector2.new(0.5, 0.5)
  5631.                         self.middleImages[i].ZIndex = 9
  5632.                         self.middleImages[i].Parent = self.thumbstickFrame
  5633.                 end
  5634.        
  5635.                 local CameraChangedConn = nil
  5636.                 local function onCurrentCameraChanged()
  5637.                         if CameraChangedConn then
  5638.                                 CameraChangedConn:Disconnect()
  5639.                                 CameraChangedConn = nil
  5640.                         end
  5641.                         local newCamera = workspace.CurrentCamera
  5642.                         if newCamera then
  5643.                                 local function onViewportSizeChanged()
  5644.                                         local size = newCamera.ViewportSize
  5645.                                         local portraitMode = size.X < size.Y
  5646.                                         layoutThumbstickFrame(portraitMode)
  5647.                                 end
  5648.                                 CameraChangedConn = newCamera:GetPropertyChangedSignal("ViewportSize"):Connect(onViewportSizeChanged)
  5649.                                 onViewportSizeChanged()
  5650.                         end
  5651.                 end
  5652.                 workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(onCurrentCameraChanged)
  5653.                 if workspace.CurrentCamera then
  5654.                         onCurrentCameraChanged()
  5655.                 end
  5656.        
  5657.                 self.moveTouchStartPosition = nil
  5658.        
  5659.                 self.startImageFadeTween = nil
  5660.                 self.endImageFadeTween = nil
  5661.                 self.middleImageFadeTweens = {}
  5662.        
  5663.                 self.onRenderSteppedConn = RunService.RenderStepped:Connect(function()
  5664.                         if self.tweenInAlphaStart ~= nil then
  5665.                                 local delta = tick() - self.tweenInAlphaStart
  5666.                                 local fadeInTime = (self.fadeInAndOutHalfDuration * 2 * self.fadeInAndOutBalance)
  5667.                                 self.thumbstickFrame.BackgroundTransparency = 1 - FADE_IN_OUT_MAX_ALPHA*math.min(delta/fadeInTime, 1)
  5668.                                 if delta > fadeInTime then
  5669.                                         self.tweenOutAlphaStart = tick()
  5670.                                         self.tweenInAlphaStart = nil
  5671.                                 end
  5672.                         elseif self.tweenOutAlphaStart ~= nil then
  5673.                                 local delta = tick() - self.tweenOutAlphaStart
  5674.                                 local fadeOutTime = (self.fadeInAndOutHalfDuration * 2) - (self.fadeInAndOutHalfDuration * 2 * self.fadeInAndOutBalance)
  5675.                                 self.thumbstickFrame.BackgroundTransparency = 1 - FADE_IN_OUT_MAX_ALPHA + FADE_IN_OUT_MAX_ALPHA*math.min(delta/fadeOutTime, 1)
  5676.                                 if delta > fadeOutTime  then
  5677.                                         self.tweenOutAlphaStart = nil
  5678.                                 end
  5679.                         end
  5680.                 end)
  5681.        
  5682.                 self.onTouchEndedConn = UserInputService.TouchEnded:connect(function(inputObject)
  5683.                         if inputObject == self.moveTouchObject then
  5684.                                 self:OnInputEnded()
  5685.                         end
  5686.                 end)
  5687.        
  5688.                 GuiService.MenuOpened:connect(function()
  5689.                         if self.moveTouchObject then
  5690.                                 self:OnInputEnded()
  5691.                         end
  5692.                 end)
  5693.        
  5694.                 local playerGui = LocalPlayer:FindFirstChildOfClass("PlayerGui")
  5695.                 while not playerGui do
  5696.                         LocalPlayer.ChildAdded:wait()
  5697.                         playerGui = LocalPlayer:FindFirstChildOfClass("PlayerGui")
  5698.                 end
  5699.        
  5700.                 local playerGuiChangedConn = nil
  5701.                 local originalScreenOrientationWasLandscape =   playerGui.CurrentScreenOrientation == Enum.ScreenOrientation.LandscapeLeft or
  5702.                                                                                                                 playerGui.CurrentScreenOrientation == Enum.ScreenOrientation.LandscapeRight
  5703.        
  5704.                 local function longShowBackground()
  5705.                         self.fadeInAndOutHalfDuration = 2.5
  5706.                         self.fadeInAndOutBalance = 0.05
  5707.                         self.tweenInAlphaStart = tick()
  5708.                 end
  5709.        
  5710.                 playerGuiChangedConn = playerGui:GetPropertyChangedSignal("CurrentScreenOrientation"):Connect(function()
  5711.                         if (originalScreenOrientationWasLandscape and playerGui.CurrentScreenOrientation == Enum.ScreenOrientation.Portrait) or
  5712.                                 (not originalScreenOrientationWasLandscape and playerGui.CurrentScreenOrientation ~= Enum.ScreenOrientation.Portrait) then
  5713.        
  5714.                                 playerGuiChangedConn:disconnect()
  5715.                                 longShowBackground()
  5716.        
  5717.                                 if originalScreenOrientationWasLandscape then
  5718.                                         self.hasFadedBackgroundInPortrait = true
  5719.                                 else
  5720.                                         self.hasFadedBackgroundInLandscape = true
  5721.                                 end
  5722.                         end
  5723.                 end)
  5724.        
  5725.                 self.thumbstickFrame.Parent = parentFrame
  5726.        
  5727.                 if game:IsLoaded() then
  5728.                         longShowBackground()
  5729.                 else
  5730.                         coroutine.wrap(function()
  5731.                                 game.Loaded:Wait()
  5732.                                 longShowBackground()
  5733.                         end)()
  5734.                 end
  5735.         end
  5736.        
  5737.         return DynamicThumbstick
  5738. end
  5739.  
  5740. function _Gamepad()
  5741.         local UserInputService = game:GetService("UserInputService")
  5742.         local ContextActionService = game:GetService("ContextActionService")
  5743.        
  5744.         --[[ Constants ]]--
  5745.         local ZERO_VECTOR3 = Vector3.new(0,0,0)
  5746.         local NONE = Enum.UserInputType.None
  5747.         local thumbstickDeadzone = 0.2
  5748.        
  5749.         --[[ The Module ]]--
  5750.         local BaseCharacterController = _BaseCharacterController()
  5751.         local Gamepad = setmetatable({}, BaseCharacterController)
  5752.         Gamepad.__index = Gamepad
  5753.        
  5754.         function Gamepad.new(CONTROL_ACTION_PRIORITY)
  5755.                 local self = setmetatable(BaseCharacterController.new(), Gamepad)
  5756.        
  5757.                 self.CONTROL_ACTION_PRIORITY = CONTROL_ACTION_PRIORITY
  5758.        
  5759.                 self.forwardValue  = 0
  5760.                 self.backwardValue = 0
  5761.                 self.leftValue = 0
  5762.                 self.rightValue = 0
  5763.        
  5764.                 self.activeGamepad = NONE       -- Enum.UserInputType.Gamepad1, 2, 3...
  5765.                 self.gamepadConnectedConn = nil
  5766.                 self.gamepadDisconnectedConn = nil
  5767.                 return self
  5768.         end
  5769.        
  5770.         function Gamepad:Enable(enable)
  5771.                 if not UserInputService.GamepadEnabled then
  5772.                         return false
  5773.                 end
  5774.        
  5775.                 if enable == self.enabled then
  5776.                         -- Module is already in the state being requested. True is returned here since the module will be in the state
  5777.                         -- expected by the code that follows the Enable() call. This makes more sense than returning false to indicate
  5778.                         -- no action was necessary. False indicates failure to be in requested/expected state.
  5779.                         return true
  5780.                 end
  5781.        
  5782.                 self.forwardValue  = 0
  5783.                 self.backwardValue = 0
  5784.                 self.leftValue = 0
  5785.                 self.rightValue = 0
  5786.                 self.moveVector = ZERO_VECTOR3
  5787.                 self.isJumping = false
  5788.        
  5789.                 if enable then
  5790.                         self.activeGamepad = self:GetHighestPriorityGamepad()
  5791.                         if self.activeGamepad ~= NONE then
  5792.                                 self:BindContextActions()
  5793.                                 self:ConnectGamepadConnectionListeners()
  5794.                         else
  5795.                                 -- No connected gamepads, failure to enable
  5796.                                 return false
  5797.                         end
  5798.                 else
  5799.                         self:UnbindContextActions()
  5800.                         self:DisconnectGamepadConnectionListeners()
  5801.                         self.activeGamepad = NONE
  5802.                 end
  5803.        
  5804.                 self.enabled = enable
  5805.                 return true
  5806.         end
  5807.        
  5808.         -- This function selects the lowest number gamepad from the currently-connected gamepad
  5809.         -- and sets it as the active gamepad
  5810.         function Gamepad:GetHighestPriorityGamepad()
  5811.                 local connectedGamepads = UserInputService:GetConnectedGamepads()
  5812.                 local bestGamepad = NONE -- Note that this value is higher than all valid gamepad values
  5813.                 for _, gamepad in pairs(connectedGamepads) do
  5814.                         if gamepad.Value < bestGamepad.Value then
  5815.                                 bestGamepad = gamepad
  5816.                         end
  5817.                 end
  5818.                 return bestGamepad
  5819.         end
  5820.        
  5821.         function Gamepad:BindContextActions()
  5822.        
  5823.                 if self.activeGamepad == NONE then
  5824.                         -- There must be an active gamepad to set up bindings
  5825.                         return false
  5826.                 end
  5827.        
  5828.                 local handleJumpAction = function(actionName, inputState, inputObject)
  5829.                         self.isJumping = (inputState == Enum.UserInputState.Begin)
  5830.                         return Enum.ContextActionResult.Sink
  5831.                 end
  5832.        
  5833.                 local handleThumbstickInput = function(actionName, inputState, inputObject)
  5834.        
  5835.                         if inputState == Enum.UserInputState.Cancel then
  5836.                                 self.moveVector = ZERO_VECTOR3
  5837.                                 return Enum.ContextActionResult.Sink
  5838.                         end
  5839.        
  5840.                         if self.activeGamepad ~= inputObject.UserInputType then
  5841.                                 return Enum.ContextActionResult.Pass
  5842.                         end
  5843.                         if inputObject.KeyCode ~= Enum.KeyCode.Thumbstick1 then return end
  5844.        
  5845.                         if inputObject.Position.magnitude > thumbstickDeadzone then
  5846.                                 self.moveVector  =  Vector3.new(inputObject.Position.X, 0, -inputObject.Position.Y)
  5847.                         else
  5848.                                 self.moveVector = ZERO_VECTOR3
  5849.                         end
  5850.                         return Enum.ContextActionResult.Sink
  5851.                 end
  5852.        
  5853.                 ContextActionService:BindActivate(self.activeGamepad, Enum.KeyCode.ButtonR2)
  5854.                 ContextActionService:BindActionAtPriority("jumpAction", handleJumpAction, false,
  5855.                         self.CONTROL_ACTION_PRIORITY, Enum.KeyCode.ButtonA)
  5856.                 ContextActionService:BindActionAtPriority("moveThumbstick", handleThumbstickInput, false,
  5857.                         self.CONTROL_ACTION_PRIORITY, Enum.KeyCode.Thumbstick1)
  5858.        
  5859.                 return true
  5860.         end
  5861.        
  5862.         function Gamepad:UnbindContextActions()
  5863.                 if self.activeGamepad ~= NONE then
  5864.                         ContextActionService:UnbindActivate(self.activeGamepad, Enum.KeyCode.ButtonR2)
  5865.                 end
  5866.                 ContextActionService:UnbindAction("moveThumbstick")
  5867.                 ContextActionService:UnbindAction("jumpAction")
  5868.         end
  5869.        
  5870.         function Gamepad:OnNewGamepadConnected()
  5871.                 -- A new gamepad has been connected.
  5872.                 local bestGamepad = self:GetHighestPriorityGamepad()
  5873.        
  5874.                 if bestGamepad == self.activeGamepad then
  5875.                         -- A new gamepad was connected, but our active gamepad is not changing
  5876.                         return
  5877.                 end
  5878.        
  5879.                 if bestGamepad == NONE then
  5880.                         -- There should be an active gamepad when GamepadConnected fires, so this should not
  5881.                         -- normally be hit. If there is no active gamepad, unbind actions but leave
  5882.                         -- the module enabled and continue to listen for a new gamepad connection.
  5883.                         warn("Gamepad:OnNewGamepadConnected found no connected gamepads")
  5884.                         self:UnbindContextActions()
  5885.                         return
  5886.                 end
  5887.        
  5888.                 if self.activeGamepad ~= NONE then
  5889.                         -- Switching from one active gamepad to another
  5890.                         self:UnbindContextActions()
  5891.                 end
  5892.        
  5893.                 self.activeGamepad = bestGamepad
  5894.                 self:BindContextActions()
  5895.         end
  5896.        
  5897.         function Gamepad:OnCurrentGamepadDisconnected()
  5898.                 if self.activeGamepad ~= NONE then
  5899.                         ContextActionService:UnbindActivate(self.activeGamepad, Enum.KeyCode.ButtonR2)
  5900.                 end
  5901.        
  5902.                 local bestGamepad = self:GetHighestPriorityGamepad()
  5903.        
  5904.                 if self.activeGamepad ~= NONE and bestGamepad == self.activeGamepad then
  5905.                         warn("Gamepad:OnCurrentGamepadDisconnected found the supposedly disconnected gamepad in connectedGamepads.")
  5906.                         self:UnbindContextActions()
  5907.                         self.activeGamepad = NONE
  5908.                         return
  5909.                 end
  5910.        
  5911.                 if bestGamepad == NONE then
  5912.                         -- No active gamepad, unbinding actions but leaving gamepad connection listener active
  5913.                         self:UnbindContextActions()
  5914.                         self.activeGamepad = NONE
  5915.                 else
  5916.                         -- Set new gamepad as active and bind to tool activation
  5917.                         self.activeGamepad = bestGamepad
  5918.                         ContextActionService:BindActivate(self.activeGamepad, Enum.KeyCode.ButtonR2)
  5919.                 end
  5920.         end
  5921.        
  5922.         function Gamepad:ConnectGamepadConnectionListeners()
  5923.                 self.gamepadConnectedConn = UserInputService.GamepadConnected:Connect(function(gamepadEnum)
  5924.                         self:OnNewGamepadConnected()
  5925.                 end)
  5926.        
  5927.                 self.gamepadDisconnectedConn = UserInputService.GamepadDisconnected:Connect(function(gamepadEnum)
  5928.                         if self.activeGamepad == gamepadEnum then
  5929.                                 self:OnCurrentGamepadDisconnected()
  5930.                         end
  5931.                 end)
  5932.        
  5933.         end
  5934.        
  5935.         function Gamepad:DisconnectGamepadConnectionListeners()
  5936.                 if self.gamepadConnectedConn then
  5937.                         self.gamepadConnectedConn:Disconnect()
  5938.                         self.gamepadConnectedConn = nil
  5939.                 end
  5940.        
  5941.                 if self.gamepadDisconnectedConn then
  5942.                         self.gamepadDisconnectedConn:Disconnect()
  5943.                         self.gamepadDisconnectedConn = nil
  5944.                 end
  5945.         end
  5946.        
  5947.         return Gamepad
  5948. end
  5949.  
  5950. function _Keyboard()
  5951.        
  5952.         --[[ Roblox Services ]]--
  5953.         local UserInputService = game:GetService("UserInputService")
  5954.         local ContextActionService = game:GetService("ContextActionService")
  5955.        
  5956.         --[[ Constants ]]--
  5957.         local ZERO_VECTOR3 = Vector3.new(0,0,0)
  5958.        
  5959.         --[[ The Module ]]--
  5960.         local BaseCharacterController = _BaseCharacterController()
  5961.         local Keyboard = setmetatable({}, BaseCharacterController)
  5962.         Keyboard.__index = Keyboard
  5963.        
  5964.         function Keyboard.new(CONTROL_ACTION_PRIORITY)
  5965.                 local self = setmetatable(BaseCharacterController.new(), Keyboard)
  5966.        
  5967.                 self.CONTROL_ACTION_PRIORITY = CONTROL_ACTION_PRIORITY
  5968.        
  5969.                 self.textFocusReleasedConn = nil
  5970.                 self.textFocusGainedConn = nil
  5971.                 self.windowFocusReleasedConn = nil
  5972.        
  5973.                 self.forwardValue  = 0
  5974.                 self.backwardValue = 0
  5975.                 self.leftValue = 0
  5976.                 self.rightValue = 0
  5977.        
  5978.                 self.jumpEnabled = true
  5979.        
  5980.                 return self
  5981.         end
  5982.        
  5983.         function Keyboard:Enable(enable)
  5984.                 if not UserInputService.KeyboardEnabled then
  5985.                         return false
  5986.                 end
  5987.        
  5988.                 if enable == self.enabled then
  5989.                         -- Module is already in the state being requested. True is returned here since the module will be in the state
  5990.                         -- expected by the code that follows the Enable() call. This makes more sense than returning false to indicate
  5991.                         -- no action was necessary. False indicates failure to be in requested/expected state.
  5992.                         return true
  5993.                 end
  5994.        
  5995.                 self.forwardValue  = 0
  5996.                 self.backwardValue = 0
  5997.                 self.leftValue = 0
  5998.                 self.rightValue = 0
  5999.                 self.moveVector = ZERO_VECTOR3
  6000.                 self.jumpRequested = false
  6001.                 self:UpdateJump()
  6002.        
  6003.                 if enable then
  6004.                         self:BindContextActions()
  6005.                         self:ConnectFocusEventListeners()
  6006.                 else
  6007.                         self:UnbindContextActions()
  6008.                         self:DisconnectFocusEventListeners()
  6009.                 end
  6010.        
  6011.                 self.enabled = enable
  6012.                 return true
  6013.         end
  6014.        
  6015.         function Keyboard:UpdateMovement(inputState)
  6016.                 if inputState == Enum.UserInputState.Cancel then
  6017.                         self.moveVector = ZERO_VECTOR3
  6018.                 else
  6019.                         self.moveVector = Vector3.new(self.leftValue + self.rightValue, 0, self.forwardValue + self.backwardValue)
  6020.                 end
  6021.         end
  6022.        
  6023.         function Keyboard:UpdateJump()
  6024.                 self.isJumping = self.jumpRequested
  6025.         end
  6026.        
  6027.         function Keyboard:BindContextActions()
  6028.        
  6029.                 -- Note: In the previous version of this code, the movement values were not zeroed-out on UserInputState. Cancel, now they are,
  6030.                 -- which fixes them from getting stuck on.
  6031.                 -- We return ContextActionResult.Pass here for legacy reasons.
  6032.                 -- Many games rely on gameProcessedEvent being false on UserInputService.InputBegan for these control actions.
  6033.                 local handleMoveForward = function(actionName, inputState, inputObject)
  6034.                         self.forwardValue = (inputState == Enum.UserInputState.Begin) and -1 or 0
  6035.                         self:UpdateMovement(inputState)
  6036.                         return Enum.ContextActionResult.Pass
  6037.                 end
  6038.        
  6039.                 local handleMoveBackward = function(actionName, inputState, inputObject)
  6040.                         self.backwardValue = (inputState == Enum.UserInputState.Begin) and 1 or 0
  6041.                         self:UpdateMovement(inputState)
  6042.                         return Enum.ContextActionResult.Pass
  6043.                 end
  6044.        
  6045.                 local handleMoveLeft = function(actionName, inputState, inputObject)
  6046.                         self.leftValue = (inputState == Enum.UserInputState.Begin) and -1 or 0
  6047.                         self:UpdateMovement(inputState)
  6048.                         return Enum.ContextActionResult.Pass
  6049.                 end
  6050.        
  6051.                 local handleMoveRight = function(actionName, inputState, inputObject)
  6052.                         self.rightValue = (inputState == Enum.UserInputState.Begin) and 1 or 0
  6053.                         self:UpdateMovement(inputState)
  6054.                         return Enum.ContextActionResult.Pass
  6055.                 end
  6056.        
  6057.                 local handleJumpAction = function(actionName, inputState, inputObject)
  6058.                         self.jumpRequested = self.jumpEnabled and (inputState == Enum.UserInputState.Begin)
  6059.                         self:UpdateJump()
  6060.                         return Enum.ContextActionResult.Pass
  6061.                 end
  6062.        
  6063.                 -- TODO: Revert to KeyCode bindings so that in the future the abstraction layer from actual keys to
  6064.                 -- movement direction is done in Lua
  6065.                 ContextActionService:BindActionAtPriority("moveForwardAction", handleMoveForward, false,
  6066.                         self.CONTROL_ACTION_PRIORITY, Enum.PlayerActions.CharacterForward)
  6067.                 ContextActionService:BindActionAtPriority("moveBackwardAction", handleMoveBackward, false,
  6068.                         self.CONTROL_ACTION_PRIORITY, Enum.PlayerActions.CharacterBackward)
  6069.                 ContextActionService:BindActionAtPriority("moveLeftAction", handleMoveLeft, false,
  6070.                         self.CONTROL_ACTION_PRIORITY, Enum.PlayerActions.CharacterLeft)
  6071.                 ContextActionService:BindActionAtPriority("moveRightAction", handleMoveRight, false,
  6072.                         self.CONTROL_ACTION_PRIORITY, Enum.PlayerActions.CharacterRight)
  6073.                 ContextActionService:BindActionAtPriority("jumpAction", handleJumpAction, false,
  6074.                         self.CONTROL_ACTION_PRIORITY, Enum.PlayerActions.CharacterJump)
  6075.         end
  6076.        
  6077.         function Keyboard:UnbindContextActions()
  6078.                 ContextActionService:UnbindAction("moveForwardAction")
  6079.                 ContextActionService:UnbindAction("moveBackwardAction")
  6080.                 ContextActionService:UnbindAction("moveLeftAction")
  6081.                 ContextActionService:UnbindAction("moveRightAction")
  6082.                 ContextActionService:UnbindAction("jumpAction")
  6083.         end
  6084.        
  6085.         function Keyboard:ConnectFocusEventListeners()
  6086.                 local function onFocusReleased()
  6087.                         self.moveVector = ZERO_VECTOR3
  6088.                         self.forwardValue  = 0
  6089.                         self.backwardValue = 0
  6090.                         self.leftValue = 0
  6091.                         self.rightValue = 0
  6092.                         self.jumpRequested = false
  6093.                         self:UpdateJump()
  6094.                 end
  6095.        
  6096.                 local function onTextFocusGained(textboxFocused)
  6097.                         self.jumpRequested = false
  6098.                         self:UpdateJump()
  6099.                 end
  6100.        
  6101.                 self.textFocusReleasedConn = UserInputService.TextBoxFocusReleased:Connect(onFocusReleased)
  6102.                 self.textFocusGainedConn = UserInputService.TextBoxFocused:Connect(onTextFocusGained)
  6103.                 self.windowFocusReleasedConn = UserInputService.WindowFocused:Connect(onFocusReleased)
  6104.         end
  6105.        
  6106.         function Keyboard:DisconnectFocusEventListeners()
  6107.                 if self.textFocusReleasedCon then
  6108.                         self.textFocusReleasedCon:Disconnect()
  6109.                         self.textFocusReleasedCon = nil
  6110.                 end
  6111.                 if self.textFocusGainedConn then
  6112.                         self.textFocusGainedConn:Disconnect()
  6113.                         self.textFocusGainedConn = nil
  6114.                 end
  6115.                 if self.windowFocusReleasedConn then
  6116.                         self.windowFocusReleasedConn:Disconnect()
  6117.                         self.windowFocusReleasedConn = nil
  6118.                 end
  6119.         end
  6120.        
  6121.         return Keyboard
  6122. end
  6123.  
  6124. function _ControlModule()
  6125.         local ControlModule = {}
  6126.         ControlModule.__index = ControlModule
  6127.        
  6128.         --[[ Roblox Services ]]--
  6129.         local Players = game:GetService("Players")
  6130.         local RunService = game:GetService("RunService")
  6131.         local UserInputService = game:GetService("UserInputService")
  6132.         local Workspace = game:GetService("Workspace")
  6133.         local UserGameSettings = UserSettings():GetService("UserGameSettings")
  6134.        
  6135.         -- Roblox User Input Control Modules - each returns a new() constructor function used to create controllers as needed
  6136.         local Keyboard = _Keyboard()
  6137.         local Gamepad = _Gamepad()
  6138.         local DynamicThumbstick = _DynamicThumbstick()
  6139.        
  6140.         local FFlagUserMakeThumbstickDynamic do
  6141.                 local success, value = pcall(function()
  6142.                         return UserSettings():IsUserFeatureEnabled("UserMakeThumbstickDynamic")
  6143.                 end)
  6144.                 FFlagUserMakeThumbstickDynamic = success and value
  6145.         end
  6146.        
  6147.         local TouchThumbstick = FFlagUserMakeThumbstickDynamic and DynamicThumbstick or _TouchThumbstick()
  6148.        
  6149.         -- These controllers handle only walk/run movement, jumping is handled by the
  6150.         -- TouchJump controller if any of these are active
  6151.         local ClickToMove = _ClickToMoveController()
  6152.         local TouchJump = _TouchJump()
  6153.        
  6154.         local VehicleController = _VehicleController()
  6155.        
  6156.         local CONTROL_ACTION_PRIORITY = Enum.ContextActionPriority.Default.Value
  6157.        
  6158.         -- Mapping from movement mode and lastInputType enum values to control modules to avoid huge if elseif switching
  6159.         local movementEnumToModuleMap = {
  6160.                 [Enum.TouchMovementMode.DPad] = DynamicThumbstick,
  6161.                 [Enum.DevTouchMovementMode.DPad] = DynamicThumbstick,
  6162.                 [Enum.TouchMovementMode.Thumbpad] = DynamicThumbstick,
  6163.                 [Enum.DevTouchMovementMode.Thumbpad] = DynamicThumbstick,
  6164.                 [Enum.TouchMovementMode.Thumbstick] = TouchThumbstick,
  6165.                 [Enum.DevTouchMovementMode.Thumbstick] = TouchThumbstick,
  6166.                 [Enum.TouchMovementMode.DynamicThumbstick] = DynamicThumbstick,
  6167.                 [Enum.DevTouchMovementMode.DynamicThumbstick] = DynamicThumbstick,
  6168.                 [Enum.TouchMovementMode.ClickToMove] = ClickToMove,
  6169.                 [Enum.DevTouchMovementMode.ClickToMove] = ClickToMove,
  6170.        
  6171.                 -- Current default
  6172.                 [Enum.TouchMovementMode.Default] = DynamicThumbstick,
  6173.        
  6174.                 [Enum.ComputerMovementMode.Default] = Keyboard,
  6175.                 [Enum.ComputerMovementMode.KeyboardMouse] = Keyboard,
  6176.                 [Enum.DevComputerMovementMode.KeyboardMouse] = Keyboard,
  6177.                 [Enum.DevComputerMovementMode.Scriptable] = nil,
  6178.                 [Enum.ComputerMovementMode.ClickToMove] = ClickToMove,
  6179.                 [Enum.DevComputerMovementMode.ClickToMove] = ClickToMove,
  6180.         }
  6181.        
  6182.         -- Keyboard controller is really keyboard and mouse controller
  6183.         local computerInputTypeToModuleMap = {
  6184.                 [Enum.UserInputType.Keyboard] = Keyboard,
  6185.                 [Enum.UserInputType.MouseButton1] = Keyboard,
  6186.                 [Enum.UserInputType.MouseButton2] = Keyboard,
  6187.                 [Enum.UserInputType.MouseButton3] = Keyboard,
  6188.                 [Enum.UserInputType.MouseWheel] = Keyboard,
  6189.                 [Enum.UserInputType.MouseMovement] = Keyboard,
  6190.                 [Enum.UserInputType.Gamepad1] = Gamepad,
  6191.                 [Enum.UserInputType.Gamepad2] = Gamepad,
  6192.                 [Enum.UserInputType.Gamepad3] = Gamepad,
  6193.                 [Enum.UserInputType.Gamepad4] = Gamepad,
  6194.         }
  6195.        
  6196.         local lastInputType
  6197.        
  6198.         function ControlModule.new()
  6199.                 local self = setmetatable({},ControlModule)
  6200.        
  6201.                 -- The Modules above are used to construct controller instances as-needed, and this
  6202.                 -- table is a map from Module to the instance created from it
  6203.                 self.controllers = {}
  6204.        
  6205.                 self.activeControlModule = nil  -- Used to prevent unnecessarily expensive checks on each input event
  6206.                 self.activeController = nil
  6207.                 self.touchJumpController = nil
  6208.                 self.moveFunction = Players.LocalPlayer.Move
  6209.                 self.humanoid = nil
  6210.                 self.lastInputType = Enum.UserInputType.None
  6211.        
  6212.                 -- For Roblox self.vehicleController
  6213.                 self.humanoidSeatedConn = nil
  6214.                 self.vehicleController = nil
  6215.        
  6216.                 self.touchControlFrame = nil
  6217.        
  6218.                 self.vehicleController = VehicleController.new(CONTROL_ACTION_PRIORITY)
  6219.        
  6220.                 Players.LocalPlayer.CharacterAdded:Connect(function(char) self:OnCharacterAdded(char) end)
  6221.                 Players.LocalPlayer.CharacterRemoving:Connect(function(char) self:OnCharacterRemoving(char) end)
  6222.                 if Players.LocalPlayer.Character then
  6223.                         self:OnCharacterAdded(Players.LocalPlayer.Character)
  6224.                 end
  6225.        
  6226.                 RunService:BindToRenderStep("ControlScriptRenderstep", Enum.RenderPriority.Input.Value, function(dt)
  6227.                         self:OnRenderStepped(dt)
  6228.                 end)
  6229.        
  6230.                 UserInputService.LastInputTypeChanged:Connect(function(newLastInputType)
  6231.                         self:OnLastInputTypeChanged(newLastInputType)
  6232.                 end)
  6233.        
  6234.        
  6235.                 UserGameSettings:GetPropertyChangedSignal("TouchMovementMode"):Connect(function()
  6236.                         self:OnTouchMovementModeChange()
  6237.                 end)
  6238.                 Players.LocalPlayer:GetPropertyChangedSignal("DevTouchMovementMode"):Connect(function()
  6239.                         self:OnTouchMovementModeChange()
  6240.                 end)
  6241.        
  6242.                 UserGameSettings:GetPropertyChangedSignal("ComputerMovementMode"):Connect(function()
  6243.                         self:OnComputerMovementModeChange()
  6244.                 end)
  6245.                 Players.LocalPlayer:GetPropertyChangedSignal("DevComputerMovementMode"):Connect(function()
  6246.                         self:OnComputerMovementModeChange()
  6247.                 end)
  6248.        
  6249.                 --[[ Touch Device UI ]]--
  6250.                 self.playerGui = nil
  6251.                 self.touchGui = nil
  6252.                 self.playerGuiAddedConn = nil
  6253.        
  6254.                 if UserInputService.TouchEnabled then
  6255.                         self.playerGui = Players.LocalPlayer:FindFirstChildOfClass("PlayerGui")
  6256.                         if self.playerGui then
  6257.                                 self:CreateTouchGuiContainer()
  6258.                                 self:OnLastInputTypeChanged(UserInputService:GetLastInputType())
  6259.                         else
  6260.                                 self.playerGuiAddedConn = Players.LocalPlayer.ChildAdded:Connect(function(child)
  6261.                                         if child:IsA("PlayerGui") then
  6262.                                                 self.playerGui = child
  6263.                                                 self:CreateTouchGuiContainer()
  6264.                                                 self.playerGuiAddedConn:Disconnect()
  6265.                                                 self.playerGuiAddedConn = nil
  6266.                                                 self:OnLastInputTypeChanged(UserInputService:GetLastInputType())
  6267.                                         end
  6268.                                 end)
  6269.                         end
  6270.                 else
  6271.                         self:OnLastInputTypeChanged(UserInputService:GetLastInputType())
  6272.                 end
  6273.        
  6274.                 return self
  6275.         end
  6276.        
  6277.         -- Convenience function so that calling code does not have to first get the activeController
  6278.         -- and then call GetMoveVector on it. When there is no active controller, this function returns
  6279.         -- nil so that this case can be distinguished from no current movement (which returns zero vector).
  6280.         function ControlModule:GetMoveVector()
  6281.                 if self.activeController then
  6282.                         return self.activeController:GetMoveVector()
  6283.                 end
  6284.                 return Vector3.new(0,0,0)
  6285.         end
  6286.        
  6287.         function ControlModule:GetActiveController()
  6288.                 return self.activeController
  6289.         end
  6290.        
  6291.         function ControlModule:EnableActiveControlModule()
  6292.                 if self.activeControlModule == ClickToMove then
  6293.                         -- For ClickToMove, when it is the player's choice, we also enable the full keyboard controls.
  6294.                         -- When the developer is forcing click to move, the most keyboard controls (WASD) are not available, only jump.
  6295.                         self.activeController:Enable(
  6296.                                 true,
  6297.                                 Players.LocalPlayer.DevComputerMovementMode == Enum.DevComputerMovementMode.UserChoice,
  6298.                                 self.touchJumpController
  6299.                         )
  6300.                 elseif self.touchControlFrame then
  6301.                         self.activeController:Enable(true, self.touchControlFrame)
  6302.                 else
  6303.                         self.activeController:Enable(true)
  6304.                 end
  6305.         end
  6306.        
  6307.         function ControlModule:Enable(enable)
  6308.                 if not self.activeController then
  6309.                         return
  6310.                 end
  6311.        
  6312.                 if enable == nil then
  6313.                         enable = true
  6314.                 end
  6315.                 if enable then
  6316.                         self:EnableActiveControlModule()
  6317.                 else
  6318.                         self:Disable()
  6319.                 end
  6320.         end
  6321.        
  6322.         -- For those who prefer distinct functions
  6323.         function ControlModule:Disable()
  6324.                 if self.activeController then
  6325.                         self.activeController:Enable(false)
  6326.        
  6327.                         if self.moveFunction then
  6328.                                 self.moveFunction(Players.LocalPlayer, Vector3.new(0,0,0), true)
  6329.                         end
  6330.                 end
  6331.         end
  6332.        
  6333.        
  6334.         -- Returns module (possibly nil) and success code to differentiate returning nil due to error vs Scriptable
  6335.         function ControlModule:SelectComputerMovementModule()
  6336.                 if not (UserInputService.KeyboardEnabled or UserInputService.GamepadEnabled) then
  6337.                         return nil, false
  6338.                 end
  6339.        
  6340.                 local computerModule
  6341.                 local DevMovementMode = Players.LocalPlayer.DevComputerMovementMode
  6342.        
  6343.                 if DevMovementMode == Enum.DevComputerMovementMode.UserChoice then
  6344.                         computerModule = computerInputTypeToModuleMap[lastInputType]
  6345.                         if UserGameSettings.ComputerMovementMode == Enum.ComputerMovementMode.ClickToMove and computerModule == Keyboard then
  6346.                                 -- User has ClickToMove set in Settings, prefer ClickToMove controller for keyboard and mouse lastInputTypes
  6347.                                 computerModule = ClickToMove
  6348.                         end
  6349.                 else
  6350.                         -- Developer has selected a mode that must be used.
  6351.                         computerModule = movementEnumToModuleMap[DevMovementMode]
  6352.        
  6353.                         -- computerModule is expected to be nil here only when developer has selected Scriptable
  6354.                         if (not computerModule) and DevMovementMode ~= Enum.DevComputerMovementMode.Scriptable then
  6355.                                 warn("No character control module is associated with DevComputerMovementMode ", DevMovementMode)
  6356.                         end
  6357.                 end
  6358.        
  6359.                 if computerModule then
  6360.                         return computerModule, true
  6361.                 elseif DevMovementMode == Enum.DevComputerMovementMode.Scriptable then
  6362.                         -- Special case where nil is returned and we actually want to set self.activeController to nil for Scriptable
  6363.                         return nil, true
  6364.                 else
  6365.                         -- This case is for when computerModule is nil because of an error and no suitable control module could
  6366.                         -- be found.
  6367.                         return nil, false
  6368.                 end
  6369.         end
  6370.        
  6371.         -- Choose current Touch control module based on settings (user, dev)
  6372.         -- Returns module (possibly nil) and success code to differentiate returning nil due to error vs Scriptable
  6373.         function ControlModule:SelectTouchModule()
  6374.                 if not UserInputService.TouchEnabled then
  6375.                         return nil, false
  6376.                 end
  6377.                 local touchModule
  6378.                 local DevMovementMode = Players.LocalPlayer.DevTouchMovementMode
  6379.                 if DevMovementMode == Enum.DevTouchMovementMode.UserChoice then
  6380.                         touchModule = movementEnumToModuleMap[UserGameSettings.TouchMovementMode]
  6381.                 elseif DevMovementMode == Enum.DevTouchMovementMode.Scriptable then
  6382.                         return nil, true
  6383.                 else
  6384.                         touchModule = movementEnumToModuleMap[DevMovementMode]
  6385.                 end
  6386.                 return touchModule, true
  6387.         end
  6388.        
  6389.         local function calculateRawMoveVector(humanoid, cameraRelativeMoveVector)
  6390.                 local camera = Workspace.CurrentCamera
  6391.                 if not camera then
  6392.                         return cameraRelativeMoveVector
  6393.                 end
  6394.        
  6395.                 if humanoid:GetState() == Enum.HumanoidStateType.Swimming then
  6396.                         return camera.CFrame:VectorToWorldSpace(cameraRelativeMoveVector)
  6397.                 end
  6398.        
  6399.                 local c, s
  6400.                 local _, _, _, R00, R01, R02, _, _, R12, _, _, R22 = camera.CFrame:GetComponents()
  6401.                 if R12 < 1 and R12 > -1 then
  6402.                         -- X and Z components from back vector.
  6403.                         c = R22
  6404.                         s = R02
  6405.                 else
  6406.                         -- In this case the camera is looking straight up or straight down.
  6407.                         -- Use X components from right and up vectors.
  6408.                         c = R00
  6409.                         s = -R01*math.sign(R12)
  6410.                 end
  6411.                 local norm = math.sqrt(c*c + s*s)
  6412.                 return Vector3.new(
  6413.                         (c*cameraRelativeMoveVector.x + s*cameraRelativeMoveVector.z)/norm,
  6414.                         0,
  6415.                         (c*cameraRelativeMoveVector.z - s*cameraRelativeMoveVector.x)/norm
  6416.                 )
  6417.         end
  6418.        
  6419.         function ControlModule:OnRenderStepped(dt)
  6420.                 if self.activeController and self.activeController.enabled and self.humanoid then
  6421.                         -- Give the controller a chance to adjust its state
  6422.                         self.activeController:OnRenderStepped(dt)
  6423.        
  6424.                         -- Now retrieve info from the controller
  6425.                         local moveVector = self.activeController:GetMoveVector()
  6426.                         local cameraRelative = self.activeController:IsMoveVectorCameraRelative()
  6427.        
  6428.                         local clickToMoveController = self:GetClickToMoveController()
  6429.                         if self.activeController ~= clickToMoveController then
  6430.                                 if moveVector.magnitude > 0 then
  6431.                                         -- Clean up any developer started MoveTo path
  6432.                                         clickToMoveController:CleanupPath()
  6433.                                 else
  6434.                                         -- Get move vector for developer started MoveTo
  6435.                                         clickToMoveController:OnRenderStepped(dt)
  6436.                                         moveVector = clickToMoveController:GetMoveVector()
  6437.                                         cameraRelative = clickToMoveController:IsMoveVectorCameraRelative()
  6438.                                 end
  6439.                         end
  6440.        
  6441.                         -- Are we driving a vehicle ?
  6442.                         local vehicleConsumedInput = false
  6443.                         if self.vehicleController then
  6444.                                 moveVector, vehicleConsumedInput = self.vehicleController:Update(moveVector, cameraRelative, self.activeControlModule==Gamepad)
  6445.                         end
  6446.        
  6447.                         -- If not, move the player
  6448.                         -- Verification of vehicleConsumedInput is commented out to preserve legacy behavior,
  6449.                         -- in case some game relies on Humanoid.MoveDirection still being set while in a VehicleSeat
  6450.                         --if not vehicleConsumedInput then
  6451.                                 if cameraRelative then
  6452.                                         moveVector = calculateRawMoveVector(self.humanoid, moveVector)
  6453.                                 end
  6454.                                 self.moveFunction(Players.LocalPlayer, moveVector, false)
  6455.                         --end
  6456.        
  6457.                         -- And make them jump if needed
  6458.                         self.humanoid.Jump = self.activeController:GetIsJumping() or (self.touchJumpController and self.touchJumpController:GetIsJumping())
  6459.                 end
  6460.         end
  6461.        
  6462.         function ControlModule:OnHumanoidSeated(active, currentSeatPart)
  6463.                 if active then
  6464.                         if currentSeatPart and currentSeatPart:IsA("VehicleSeat") then
  6465.                                 if not self.vehicleController then
  6466.                                         self.vehicleController = self.vehicleController.new(CONTROL_ACTION_PRIORITY)
  6467.                                 end
  6468.                                 self.vehicleController:Enable(true, currentSeatPart)
  6469.                         end
  6470.                 else
  6471.                         if self.vehicleController then
  6472.                                 self.vehicleController:Enable(false, currentSeatPart)
  6473.                         end
  6474.                 end
  6475.         end
  6476.        
  6477.         function ControlModule:OnCharacterAdded(char)
  6478.                 self.humanoid = char:FindFirstChildOfClass("Humanoid")
  6479.                 while not self.humanoid do
  6480.                         char.ChildAdded:wait()
  6481.                         self.humanoid = char:FindFirstChildOfClass("Humanoid")
  6482.                 end
  6483.        
  6484.                 if self.touchGui then
  6485.                         self.touchGui.Enabled = true
  6486.                 end
  6487.        
  6488.                 if self.humanoidSeatedConn then
  6489.                         self.humanoidSeatedConn:Disconnect()
  6490.                         self.humanoidSeatedConn = nil
  6491.                 end
  6492.                 self.humanoidSeatedConn = self.humanoid.Seated:Connect(function(active, currentSeatPart)
  6493.                         self:OnHumanoidSeated(active, currentSeatPart)
  6494.                 end)
  6495.         end
  6496.        
  6497.         function ControlModule:OnCharacterRemoving(char)
  6498.                 self.humanoid = nil
  6499.        
  6500.                 if self.touchGui then
  6501.                         self.touchGui.Enabled = false
  6502.                 end
  6503.         end
  6504.        
  6505.         -- Helper function to lazily instantiate a controller if it does not yet exist,
  6506.         -- disable the active controller if it is different from the on being switched to,
  6507.         -- and then enable the requested controller. The argument to this function must be
  6508.         -- a reference to one of the control modules, i.e. Keyboard, Gamepad, etc.
  6509.         function ControlModule:SwitchToController(controlModule)
  6510.                 if not controlModule then
  6511.                         if self.activeController then
  6512.                                 self.activeController:Enable(false)
  6513.                         end
  6514.                         self.activeController = nil
  6515.                         self.activeControlModule = nil
  6516.                 else
  6517.                         if not self.controllers[controlModule] then
  6518.                                 self.controllers[controlModule] = controlModule.new(CONTROL_ACTION_PRIORITY)
  6519.                         end
  6520.        
  6521.                         if self.activeController ~= self.controllers[controlModule] then
  6522.                                 if self.activeController then
  6523.                                         self.activeController:Enable(false)
  6524.                                 end
  6525.                                 self.activeController = self.controllers[controlModule]
  6526.                                 self.activeControlModule = controlModule -- Only used to check if controller switch is necessary
  6527.        
  6528.                                 if self.touchControlFrame and (self.activeControlModule == ClickToMove
  6529.                                                         or self.activeControlModule == TouchThumbstick
  6530.                                                         or self.activeControlModule == DynamicThumbstick) then
  6531.                                         if not self.controllers[TouchJump] then
  6532.                                                 self.controllers[TouchJump] = TouchJump.new()
  6533.                                         end
  6534.                                         self.touchJumpController = self.controllers[TouchJump]
  6535.                                         self.touchJumpController:Enable(true, self.touchControlFrame)
  6536.                                 else
  6537.                                         if self.touchJumpController then
  6538.                                                 self.touchJumpController:Enable(false)
  6539.                                         end
  6540.                                 end
  6541.        
  6542.                                 self:EnableActiveControlModule()
  6543.                         end
  6544.                 end
  6545.         end
  6546.        
  6547.         function ControlModule:OnLastInputTypeChanged(newLastInputType)
  6548.                 if lastInputType == newLastInputType then
  6549.                         warn("LastInputType Change listener called with current type.")
  6550.                 end
  6551.                 lastInputType = newLastInputType
  6552.        
  6553.                 if lastInputType == Enum.UserInputType.Touch then
  6554.                         -- TODO: Check if touch module already active
  6555.                         local touchModule, success = self:SelectTouchModule()
  6556.                         if success then
  6557.                                 while not self.touchControlFrame do
  6558.                                         wait()
  6559.                                 end
  6560.                                 self:SwitchToController(touchModule)
  6561.                         end
  6562.                 elseif computerInputTypeToModuleMap[lastInputType] ~= nil then
  6563.                         local computerModule = self:SelectComputerMovementModule()
  6564.                         if computerModule then
  6565.                                 self:SwitchToController(computerModule)
  6566.                         end
  6567.                 end
  6568.         end
  6569.        
  6570.         -- Called when any relevant values of GameSettings or LocalPlayer change, forcing re-evalulation of
  6571.         -- current control scheme
  6572.         function ControlModule:OnComputerMovementModeChange()
  6573.                 local controlModule, success =  self:SelectComputerMovementModule()
  6574.                 if success then
  6575.                         self:SwitchToController(controlModule)
  6576.                 end
  6577.         end
  6578.        
  6579.         function ControlModule:OnTouchMovementModeChange()
  6580.                 local touchModule, success = self:SelectTouchModule()
  6581.                 if success then
  6582.                         while not self.touchControlFrame do
  6583.                                 wait()
  6584.                         end
  6585.                         self:SwitchToController(touchModule)
  6586.                 end
  6587.         end
  6588.        
  6589.         function ControlModule:CreateTouchGuiContainer()
  6590.                 if self.touchGui then self.touchGui:Destroy() end
  6591.        
  6592.                 -- Container for all touch device guis
  6593.                 self.touchGui = Instance.new("ScreenGui")
  6594.                 self.touchGui.Name = "TouchGui"
  6595.                 self.touchGui.ResetOnSpawn = false
  6596.                 self.touchGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
  6597.                 self.touchGui.Enabled = self.humanoid ~= nil
  6598.        
  6599.                 self.touchControlFrame = Instance.new("Frame")
  6600.                 self.touchControlFrame.Name = "TouchControlFrame"
  6601.                 self.touchControlFrame.Size = UDim2.new(1, 0, 1, 0)
  6602.                 self.touchControlFrame.BackgroundTransparency = 1
  6603.                 self.touchControlFrame.Parent = self.touchGui
  6604.        
  6605.                 self.touchGui.Parent = self.playerGui
  6606.         end
  6607.        
  6608.         function ControlModule:GetClickToMoveController()
  6609.                 if not self.controllers[ClickToMove] then
  6610.                         self.controllers[ClickToMove] = ClickToMove.new(CONTROL_ACTION_PRIORITY)
  6611.                 end
  6612.                 return self.controllers[ClickToMove]
  6613.         end
  6614.        
  6615.         function ControlModule:IsJumping()
  6616.                 if self.activeController then
  6617.                         return self.activeController:GetIsJumping() or (self.touchJumpController and self.touchJumpController:GetIsJumping())
  6618.                 end
  6619.                 return false
  6620.         end
  6621.        
  6622.         return ControlModule.new()
  6623. end
  6624.  
  6625. function _PlayerModule()
  6626.         local PlayerModule = {}
  6627.         PlayerModule.__index = PlayerModule
  6628.         function PlayerModule.new()
  6629.                 local self = setmetatable({},PlayerModule)
  6630.                 self.cameras = _CameraModule()
  6631.                 self.controls = _ControlModule()
  6632.                 return self
  6633.         end
  6634.         function PlayerModule:GetCameras()
  6635.                 return self.cameras
  6636.         end
  6637.         function PlayerModule:GetControls()
  6638.                 return self.controls
  6639.         end
  6640.         function PlayerModule:GetClickToMoveController()
  6641.                 return self.controls:GetClickToMoveController()
  6642.         end
  6643.         return PlayerModule.new()
  6644. end
  6645.  
  6646. function _sounds()
  6647.        
  6648.         local SetState = Instance.new("BindableEvent",script)
  6649.        
  6650.         local Players = game:GetService("Players")
  6651.         local RunService = game:GetService("RunService")
  6652.        
  6653.         local SOUND_DATA = {
  6654.                 Climbing = {
  6655.                         SoundId = "rbxasset://sounds/action_footsteps_plastic.mp3",
  6656.                         Looped = true,
  6657.                 },
  6658.                 Died = {
  6659.                         SoundId = "rbxasset://sounds/uuhhh.mp3",
  6660.                 },
  6661.                 FreeFalling = {
  6662.                         SoundId = "rbxasset://sounds/action_falling.mp3",
  6663.                         Looped = true,
  6664.                 },
  6665.                 GettingUp = {
  6666.                         SoundId = "rbxasset://sounds/action_get_up.mp3",
  6667.                 },
  6668.                 Jumping = {
  6669.                         SoundId = "rbxasset://sounds/action_jump.mp3",
  6670.                 },
  6671.                 Landing = {
  6672.                         SoundId = "rbxasset://sounds/action_jump_land.mp3",
  6673.                 },
  6674.                 Running = {
  6675.                         SoundId = "rbxasset://sounds/action_footsteps_plastic.mp3",
  6676.                         Looped = true,
  6677.                         Pitch = 1.85,
  6678.                 },
  6679.                 Splash = {
  6680.                         SoundId = "rbxasset://sounds/impact_water.mp3",
  6681.                 },
  6682.                 Swimming = {
  6683.                         SoundId = "rbxasset://sounds/action_swim.mp3",
  6684.                         Looped = true,
  6685.                         Pitch = 1.6,
  6686.                 },
  6687.         }
  6688.        
  6689.          -- wait for the first of the passed signals to fire
  6690.         local function waitForFirst(...)
  6691.                 local shunt = Instance.new("BindableEvent")
  6692.                 local slots = {...}
  6693.        
  6694.                 local function fire(...)
  6695.                         for i = 1, #slots do
  6696.                                 slots[i]:Disconnect()
  6697.                         end
  6698.        
  6699.                         return shunt:Fire(...)
  6700.                 end
  6701.        
  6702.                 for i = 1, #slots do
  6703.                         slots[i] = slots[i]:Connect(fire)
  6704.                 end
  6705.        
  6706.                 return shunt.Event:Wait()
  6707.         end
  6708.        
  6709.         -- map a value from one range to another
  6710.         local function map(x, inMin, inMax, outMin, outMax)
  6711.                 return (x - inMin)*(outMax - outMin)/(inMax - inMin) + outMin
  6712.         end
  6713.        
  6714.         local function playSound(sound)
  6715.                 sound.TimePosition = 0
  6716.                 sound.Playing = true
  6717.         end
  6718.        
  6719.         local function stopSound(sound)
  6720.                 sound.Playing = false
  6721.                 sound.TimePosition = 0
  6722.         end
  6723.        
  6724.         local function shallowCopy(t)
  6725.                 local out = {}
  6726.                 for k, v in pairs(t) do
  6727.                         out[k] = v
  6728.                 end
  6729.                 return out
  6730.         end
  6731.        
  6732.         local function initializeSoundSystem(player, humanoid, rootPart)
  6733.                 local sounds = {}
  6734.        
  6735.                 -- initialize sounds
  6736.                 for name, props in pairs(SOUND_DATA) do
  6737.                         local sound = Instance.new("Sound")
  6738.                         sound.Name = name
  6739.        
  6740.                         -- set default values
  6741.                         sound.Archivable = false
  6742.                         sound.EmitterSize = 5
  6743.                         sound.MaxDistance = 150
  6744.                         sound.Volume = 0.65
  6745.        
  6746.                         for propName, propValue in pairs(props) do
  6747.                                 sound[propName] = propValue
  6748.                         end
  6749.        
  6750.                         sound.Parent = rootPart
  6751.                         sounds[name] = sound
  6752.                 end
  6753.        
  6754.                 local playingLoopedSounds = {}
  6755.        
  6756.                 local function stopPlayingLoopedSounds(except)
  6757.                         for sound in pairs(shallowCopy(playingLoopedSounds)) do
  6758.                                 if sound ~= except then
  6759.                                         sound.Playing = false
  6760.                                         playingLoopedSounds[sound] = nil
  6761.                                 end
  6762.                         end
  6763.                 end
  6764.        
  6765.                 -- state transition callbacks
  6766.                 local stateTransitions = {
  6767.                         [Enum.HumanoidStateType.FallingDown] = function()
  6768.                                 stopPlayingLoopedSounds()
  6769.                         end,
  6770.        
  6771.                         [Enum.HumanoidStateType.GettingUp] = function()
  6772.                                 stopPlayingLoopedSounds()
  6773.                                 playSound(sounds.GettingUp)
  6774.                         end,
  6775.        
  6776.                         [Enum.HumanoidStateType.Jumping] = function()
  6777.                                 stopPlayingLoopedSounds()
  6778.                                 playSound(sounds.Jumping)
  6779.                         end,
  6780.        
  6781.                         [Enum.HumanoidStateType.Swimming] = function()
  6782.                                 local verticalSpeed = math.abs(rootPart.Velocity.Y)
  6783.                                 if verticalSpeed > 0.1 then
  6784.                                         sounds.Splash.Volume = math.clamp(map(verticalSpeed, 100, 350, 0.28, 1), 0, 1)
  6785.                                         playSound(sounds.Splash)
  6786.                                 end
  6787.                                 stopPlayingLoopedSounds(sounds.Swimming)
  6788.                                 sounds.Swimming.Playing = true
  6789.                                 playingLoopedSounds[sounds.Swimming] = true
  6790.                         end,
  6791.        
  6792.                         [Enum.HumanoidStateType.Freefall] = function()
  6793.                                 sounds.FreeFalling.Volume = 0
  6794.                                 stopPlayingLoopedSounds(sounds.FreeFalling)
  6795.                                 playingLoopedSounds[sounds.FreeFalling] = true
  6796.                         end,
  6797.        
  6798.                         [Enum.HumanoidStateType.Landed] = function()
  6799.                                 stopPlayingLoopedSounds()
  6800.                                 local verticalSpeed = math.abs(rootPart.Velocity.Y)
  6801.                                 if verticalSpeed > 75 then
  6802.                                         sounds.Landing.Volume = math.clamp(map(verticalSpeed, 50, 100, 0, 1), 0, 1)
  6803.                                         playSound(sounds.Landing)
  6804.                                 end
  6805.                         end,
  6806.        
  6807.                         [Enum.HumanoidStateType.Running] = function()
  6808.                                 stopPlayingLoopedSounds(sounds.Running)
  6809.                                 sounds.Running.Playing = true
  6810.                                 playingLoopedSounds[sounds.Running] = true
  6811.                         end,
  6812.        
  6813.                         [Enum.HumanoidStateType.Climbing] = function()
  6814.                                 local sound = sounds.Climbing
  6815.                                 if math.abs(rootPart.Velocity.Y) > 0.1 then
  6816.                                         sound.Playing = true
  6817.                                         stopPlayingLoopedSounds(sound)
  6818.                                 else
  6819.                                         stopPlayingLoopedSounds()
  6820.                                 end
  6821.                                 playingLoopedSounds[sound] = true
  6822.                         end,
  6823.        
  6824.                         [Enum.HumanoidStateType.Seated] = function()
  6825.                                 stopPlayingLoopedSounds()
  6826.                         end,
  6827.        
  6828.                         [Enum.HumanoidStateType.Dead] = function()
  6829.                                 stopPlayingLoopedSounds()
  6830.                                 playSound(sounds.Died)
  6831.                         end,
  6832.                 }
  6833.        
  6834.                 -- updaters for looped sounds
  6835.                 local loopedSoundUpdaters = {
  6836.                         [sounds.Climbing] = function(dt, sound, vel)
  6837.                                 sound.Playing = vel.Magnitude > 0.1
  6838.                         end,
  6839.        
  6840.                         [sounds.FreeFalling] = function(dt, sound, vel)
  6841.                                 if vel.Magnitude > 75 then
  6842.                                         sound.Volume = math.clamp(sound.Volume + 0.9*dt, 0, 1)
  6843.                                 else
  6844.                                         sound.Volume = 0
  6845.                                 end
  6846.                         end,
  6847.        
  6848.                         [sounds.Running] = function(dt, sound, vel)
  6849.                                 sound.Playing = vel.Magnitude > 0.5 and humanoid.MoveDirection.Magnitude > 0.5
  6850.                         end,
  6851.                 }
  6852.        
  6853.                 -- state substitutions to avoid duplicating entries in the state table
  6854.                 local stateRemap = {
  6855.                         [Enum.HumanoidStateType.RunningNoPhysics] = Enum.HumanoidStateType.Running,
  6856.                 }
  6857.        
  6858.                 local activeState = stateRemap[humanoid:GetState()] or humanoid:GetState()
  6859.                 local activeConnections = {}
  6860.        
  6861.                 local stateChangedConn = humanoid.StateChanged:Connect(function(_, state)
  6862.                         state = stateRemap[state] or state
  6863.        
  6864.                         if state ~= activeState then
  6865.                                 local transitionFunc = stateTransitions[state]
  6866.        
  6867.                                 if transitionFunc then
  6868.                                         transitionFunc()
  6869.                                 end
  6870.        
  6871.                                 activeState = state
  6872.                         end
  6873.                 end)
  6874.                
  6875.                 local customStateChangedConn = SetState.Event:Connect(function(state)
  6876.                         state = stateRemap[state] or state
  6877.        
  6878.                         if state ~= activeState then
  6879.                                 local transitionFunc = stateTransitions[state]
  6880.        
  6881.                                 if transitionFunc then
  6882.                                         transitionFunc()
  6883.                                 end
  6884.        
  6885.                                 activeState = state
  6886.                         end
  6887.                 end)
  6888.        
  6889.                 local steppedConn = RunService.Stepped:Connect(function(_, worldDt)
  6890.                         -- update looped sounds on stepped
  6891.                         for sound in pairs(playingLoopedSounds) do
  6892.                                 local updater = loopedSoundUpdaters[sound]
  6893.        
  6894.                                 if updater then
  6895.                                         updater(worldDt, sound, rootPart.Velocity)
  6896.                                 end
  6897.                         end
  6898.                 end)
  6899.        
  6900.                 local humanoidAncestryChangedConn
  6901.                 local rootPartAncestryChangedConn
  6902.                 local characterAddedConn
  6903.        
  6904.                 local function terminate()
  6905.                         stateChangedConn:Disconnect()
  6906.                         customStateChangedConn:Disconnect()
  6907.                         steppedConn:Disconnect()
  6908.                         humanoidAncestryChangedConn:Disconnect()
  6909.                         rootPartAncestryChangedConn:Disconnect()
  6910.                         characterAddedConn:Disconnect()
  6911.                 end
  6912.        
  6913.                 humanoidAncestryChangedConn = humanoid.AncestryChanged:Connect(function(_, parent)
  6914.                         if not parent then
  6915.                                 terminate()
  6916.                         end
  6917.                 end)
  6918.        
  6919.                 rootPartAncestryChangedConn = rootPart.AncestryChanged:Connect(function(_, parent)
  6920.                         if not parent then
  6921.                                 terminate()
  6922.                         end
  6923.                 end)
  6924.        
  6925.                 characterAddedConn = player.CharacterAdded:Connect(terminate)
  6926.         end
  6927.        
  6928.         local function playerAdded(player)
  6929.                 local function characterAdded(character)
  6930.                         -- Avoiding memory leaks in the face of Character/Humanoid/RootPart lifetime has a few complications:
  6931.                         -- * character deparenting is a Remove instead of a Destroy, so signals are not cleaned up automatically.
  6932.                         -- ** must use a waitForFirst on everything and listen for hierarchy changes.
  6933.                         -- * the character might not be in the dm by the time CharacterAdded fires
  6934.                         -- ** constantly check consistency with player.Character and abort if CharacterAdded is fired again
  6935.                         -- * Humanoid may not exist immediately, and by the time it's inserted the character might be deparented.
  6936.                         -- * RootPart probably won't exist immediately.
  6937.                         -- ** by the time RootPart is inserted and Humanoid.RootPart is set, the character or the humanoid might be deparented.
  6938.        
  6939.                         if not character.Parent then
  6940.                                 waitForFirst(character.AncestryChanged, player.CharacterAdded)
  6941.                         end
  6942.        
  6943.                         if player.Character ~= character or not character.Parent then
  6944.                                 return
  6945.                         end
  6946.        
  6947.                         local humanoid = character:FindFirstChildOfClass("Humanoid")
  6948.                         while character:IsDescendantOf(game) and not humanoid do
  6949.                                 waitForFirst(character.ChildAdded, character.AncestryChanged, player.CharacterAdded)
  6950.                                 humanoid = character:FindFirstChildOfClass("Humanoid")
  6951.                         end
  6952.        
  6953.                         if player.Character ~= character or not character:IsDescendantOf(game) then
  6954.                                 return
  6955.                         end
  6956.        
  6957.                         -- must rely on HumanoidRootPart naming because Humanoid.RootPart does not fire changed signals
  6958.                         local rootPart = character:FindFirstChild("HumanoidRootPart")
  6959.                         while character:IsDescendantOf(game) and not rootPart do
  6960.                                 waitForFirst(character.ChildAdded, character.AncestryChanged, humanoid.AncestryChanged, player.CharacterAdded)
  6961.                                 rootPart = character:FindFirstChild("HumanoidRootPart")
  6962.                         end
  6963.        
  6964.                         if rootPart and humanoid:IsDescendantOf(game) and character:IsDescendantOf(game) and player.Character == character then
  6965.                                 initializeSoundSystem(player, humanoid, rootPart)
  6966.                         end
  6967.                 end
  6968.        
  6969.                 if player.Character then
  6970.                         characterAdded(player.Character)
  6971.                 end
  6972.                 player.CharacterAdded:Connect(characterAdded)
  6973.         end
  6974.        
  6975.         Players.PlayerAdded:Connect(playerAdded)
  6976.         for _, player in ipairs(Players:GetPlayers()) do
  6977.                 playerAdded(player)
  6978.         end
  6979.         return SetState
  6980. end
  6981.  
  6982. function _StateTracker()
  6983.         local EPSILON = 0.1
  6984.        
  6985.         local SPEED = {
  6986.                 ["onRunning"] = true,
  6987.                 ["onClimbing"] = true
  6988.         }
  6989.        
  6990.         local INAIR = {
  6991.                 ["onFreeFall"] = true,
  6992.                 ["onJumping"] = true
  6993.         }
  6994.        
  6995.         local STATEMAP = {
  6996.                 ["onRunning"] = Enum.HumanoidStateType.Running,
  6997.                 ["onJumping"] = Enum.HumanoidStateType.Jumping,
  6998.                 ["onFreeFall"] = Enum.HumanoidStateType.Freefall
  6999.         }
  7000.        
  7001.         local StateTracker = {}
  7002.         StateTracker.__index = StateTracker
  7003.        
  7004.         function StateTracker.new(humanoid, soundState)
  7005.                 local self = setmetatable({}, StateTracker)
  7006.                
  7007.                 self.Humanoid = humanoid
  7008.                 self.HRP = humanoid.RootPart
  7009.                
  7010.                 self.Speed = 0
  7011.                 self.State = "onRunning"
  7012.                 self.Jumped = false
  7013.                 self.JumpTick = tick()
  7014.                
  7015.                 self.SoundState = soundState
  7016.                
  7017.                 self._ChangedEvent = Instance.new("BindableEvent")
  7018.                 self.Changed = self._ChangedEvent.Event
  7019.                
  7020.                 return self
  7021.         end
  7022.        
  7023.         function StateTracker:Destroy()
  7024.                 self._ChangedEvent:Destroy()
  7025.         end
  7026.        
  7027.         function StateTracker:RequestedJump()
  7028.                 self.Jumped = true
  7029.                 self.JumpTick = tick()
  7030.         end
  7031.        
  7032.         function StateTracker:OnStep(gravityUp, grounded, isMoving)
  7033.                 local cVelocity = self.HRP.Velocity
  7034.                 local gVelocity = cVelocity:Dot(gravityUp)
  7035.                
  7036.                 local oldState, oldSpeed = self.State, self.Speed
  7037.                
  7038.                 local newState
  7039.                 local newSpeed = cVelocity.Magnitude
  7040.        
  7041.                 if (not grounded) then
  7042.                         if (gVelocity > 0) then
  7043.                                 if (self.Jumped) then
  7044.                                         newState = "onJumping"
  7045.                                 else
  7046.                                         newState = "onFreeFall"
  7047.                                 end
  7048.                         else
  7049.                                 if (self.Jumped) then
  7050.                                         self.Jumped = false
  7051.                                 end
  7052.                                 newState = "onFreeFall"
  7053.                         end
  7054.                 else
  7055.                         if (self.Jumped and tick() - self.JumpTick > 0.1) then
  7056.                                 self.Jumped = false
  7057.                         end
  7058.                         newSpeed = (cVelocity - gVelocity*gravityUp).Magnitude
  7059.                         newState = "onRunning"
  7060.                 end
  7061.                
  7062.                 newSpeed = isMoving and newSpeed or 0
  7063.                
  7064.                 if (oldState ~= newState or (SPEED[newState] and math.abs(oldSpeed - newSpeed) > EPSILON)) then
  7065.                         self.State = newState
  7066.                         self.Speed = newSpeed
  7067.                         self.SoundState:Fire(STATEMAP[newState])
  7068.                         self._ChangedEvent:Fire(self.State, self.Speed)
  7069.                 end
  7070.         end
  7071.        
  7072.         return StateTracker
  7073. end
  7074. function _InitObjects()
  7075.         local model = workspace:FindFirstChild("objects") or game:GetObjects("rbxassetid://5045408489")[1]
  7076.         local SPHERE = model:WaitForChild("Sphere")
  7077.         local FLOOR = model:WaitForChild("Floor")
  7078.         local VFORCE = model:WaitForChild("VectorForce")
  7079.         local BGYRO = model:WaitForChild("BodyGyro")
  7080.         local function initObjects(self)
  7081.                 local hrp = self.HRP
  7082.                 local humanoid = self.Humanoid
  7083.                 local sphere = SPHERE:Clone()
  7084.                 sphere.Parent = self.Character
  7085.                 local floor = FLOOR:Clone()
  7086.                 floor.Parent = self.Character
  7087.                 local isR15 = (humanoid.RigType == Enum.HumanoidRigType.R15)
  7088.                 local height = isR15 and (humanoid.HipHeight + 0.05) or 2
  7089.                 local weld = Instance.new("Weld")
  7090.                 weld.C0 = CFrame.new(0, -height, 0.1)
  7091.                 weld.Part0 = hrp
  7092.                 weld.Part1 = sphere
  7093.                 weld.Parent = sphere
  7094.                 local weld2 = Instance.new("Weld")
  7095.                 weld2.C0 = CFrame.new(0, -(height + 1.5), 0)
  7096.                 weld2.Part0 = hrp
  7097.                 weld2.Part1 = floor
  7098.                 weld2.Parent = floor
  7099.                 local gyro = BGYRO:Clone()
  7100.                 gyro.CFrame = hrp.CFrame
  7101.                 gyro.Parent = hrp
  7102.                 local vForce = VFORCE:Clone()
  7103.                 vForce.Attachment0 = isR15 and hrp:WaitForChild("RootRigAttachment") or hrp:WaitForChild("RootAttachment")
  7104.                 vForce.Parent = hrp
  7105.                 return sphere, gyro, vForce, floor
  7106.         end
  7107.         return initObjects
  7108. end
  7109. local plr = game.Players.LocalPlayer
  7110. local ms = plr:GetMouse()
  7111. local char
  7112. plr.CharacterAdded:Connect(function(c)
  7113.         char = c
  7114. end)
  7115. function _R6()
  7116.         function r6()
  7117.         local Figure = char
  7118.         local Torso = Figure:WaitForChild("Torso")
  7119.         local RightShoulder = Torso:WaitForChild("Right Shoulder")
  7120.         local LeftShoulder = Torso:WaitForChild("Left Shoulder")
  7121.         local RightHip = Torso:WaitForChild("Right Hip")
  7122.         local LeftHip = Torso:WaitForChild("Left Hip")
  7123.         local Neck = Torso:WaitForChild("Neck")
  7124.         local Humanoid = Figure:WaitForChild("Humanoid")
  7125.         local pose = "Standing"
  7126.         local currentAnim = ""
  7127.         local currentAnimInstance = nil
  7128.         local currentAnimTrack = nil
  7129.         local currentAnimKeyframeHandler = nil
  7130.         local currentAnimSpeed = 1.0
  7131.         local animTable = {}
  7132.         local animNames = {
  7133.                 idle =  {      
  7134.                                         { id = "http://www.roblox.com/asset/?id=180435571", weight = 9 },
  7135.                                         { id = "http://www.roblox.com/asset/?id=180435792", weight = 1 }
  7136.                                 },
  7137.                 walk =  {      
  7138.                                         { id = "http://www.roblox.com/asset/?id=180426354", weight = 10 }
  7139.                                 },
  7140.                 run =   {
  7141.                                         { id = "run.xml", weight = 10 }
  7142.                                 },
  7143.                 jump =  {
  7144.                                         { id = "http://www.roblox.com/asset/?id=125750702", weight = 10 }
  7145.                                 },
  7146.                 fall =  {
  7147.                                         { id = "http://www.roblox.com/asset/?id=180436148", weight = 10 }
  7148.                                 },
  7149.                 climb = {
  7150.                                         { id = "http://www.roblox.com/asset/?id=180436334", weight = 10 }
  7151.                                 },
  7152.                 sit =   {
  7153.                                         { id = "http://www.roblox.com/asset/?id=178130996", weight = 10 }
  7154.                                 },     
  7155.                 toolnone = {
  7156.                                         { id = "http://www.roblox.com/asset/?id=182393478", weight = 10 }
  7157.                                 },
  7158.                 toolslash = {
  7159.                                         { id = "http://www.roblox.com/asset/?id=129967390", weight = 10 }
  7160.         --                              { id = "slash.xml", weight = 10 }
  7161.                                 },
  7162.                 toollunge = {
  7163.                                         { id = "http://www.roblox.com/asset/?id=129967478", weight = 10 }
  7164.                                 },
  7165.                 wave = {
  7166.                                         { id = "http://www.roblox.com/asset/?id=128777973", weight = 10 }
  7167.                                 },
  7168.                 point = {
  7169.                                         { id = "http://www.roblox.com/asset/?id=128853357", weight = 10 }
  7170.                                 },
  7171.                 dance1 = {
  7172.                                         { id = "http://www.roblox.com/asset/?id=182435998", weight = 10 },
  7173.                                         { id = "http://www.roblox.com/asset/?id=182491037", weight = 10 },
  7174.                                         { id = "http://www.roblox.com/asset/?id=182491065", weight = 10 }
  7175.                                 },
  7176.                 dance2 = {
  7177.                                         { id = "http://www.roblox.com/asset/?id=182436842", weight = 10 },
  7178.                                         { id = "http://www.roblox.com/asset/?id=182491248", weight = 10 },
  7179.                                         { id = "http://www.roblox.com/asset/?id=182491277", weight = 10 }
  7180.                                 },
  7181.                 dance3 = {
  7182.                                         { id = "http://www.roblox.com/asset/?id=182436935", weight = 10 },
  7183.                                         { id = "http://www.roblox.com/asset/?id=182491368", weight = 10 },
  7184.                                         { id = "http://www.roblox.com/asset/?id=182491423", weight = 10 }
  7185.                                 },
  7186.                 laugh = {
  7187.                                         { id = "http://www.roblox.com/asset/?id=129423131", weight = 10 }
  7188.                                 },
  7189.                 cheer = {
  7190.                                         { id = "http://www.roblox.com/asset/?id=129423030", weight = 10 }
  7191.                                 },
  7192.         }
  7193.         local dances = {"dance1", "dance2", "dance3"}
  7194.         -- Existance in this list signifies that it is an emote, the value indicates if it is a looping emote
  7195.         local emoteNames = { wave = false, point = false, dance1 = true, dance2 = true, dance3 = true, laugh = false, cheer = false}
  7196.         function configureAnimationSet(name, fileList)
  7197.                 if (animTable[name] ~= nil) then
  7198.                         for _, connection in pairs(animTable[name].connections) do
  7199.                                 connection:disconnect()
  7200.                         end
  7201.                 end
  7202.                 animTable[name] = {}
  7203.                 animTable[name].count = 0
  7204.                 animTable[name].totalWeight = 0
  7205.                 animTable[name].connections = {}
  7206.                 -- check for config values
  7207.                 local config = script:FindFirstChild(name)
  7208.                 if (config ~= nil) then
  7209.         --              print("Loading anims " .. name)
  7210.                         table.insert(animTable[name].connections, config.ChildAdded:connect(function(child) configureAnimationSet(name, fileList) end))
  7211.                         table.insert(animTable[name].connections, config.ChildRemoved:connect(function(child) configureAnimationSet(name, fileList) end))
  7212.                         local idx = 1
  7213.                         for _, childPart in pairs(config:GetChildren()) do
  7214.                                 if (childPart:IsA("Animation")) then
  7215.                                         table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end))
  7216.                                         animTable[name][idx] = {}
  7217.                                         animTable[name][idx].anim = childPart
  7218.                                         local weightObject = childPart:FindFirstChild("Weight")
  7219.                                         if (weightObject == nil) then
  7220.                                                 animTable[name][idx].weight = 1
  7221.                                         else
  7222.                                                 animTable[name][idx].weight = weightObject.Value
  7223.                                         end
  7224.                                         animTable[name].count = animTable[name].count + 1
  7225.                                         animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
  7226.                 --                      print(name .. " [" .. idx .. "] " .. animTable[name][idx].anim.AnimationId .. " (" .. animTable[name][idx].weight .. ")")
  7227.                                         idx = idx + 1
  7228.                                 end
  7229.                         end
  7230.                 end
  7231.                 -- fallback to defaults
  7232.                 if (animTable[name].count  animTable[animName][idx].weight) do
  7233.                         roll = roll - animTable[animName][idx].weight
  7234.                         idx = idx + 1
  7235.                 end
  7236.         --              print(animName .. " " .. idx .. " [" .. origRoll .. "]")
  7237.                 local anim = animTable[animName][idx].anim
  7238.        
  7239.                 -- switch animation            
  7240.                 if (anim ~= currentAnimInstance) then
  7241.                        
  7242.                         if (currentAnimTrack ~= nil) then
  7243.                                 currentAnimTrack:Stop(transitionTime)
  7244.                                 currentAnimTrack:Destroy()
  7245.                         end
  7246.        
  7247.                         currentAnimSpeed = 1.0
  7248.                
  7249.                         -- load it to the humanoid; get AnimationTrack
  7250.                         currentAnimTrack = humanoid:LoadAnimation(anim)
  7251.                         currentAnimTrack.Priority = Enum.AnimationPriority.Core
  7252.                          
  7253.                         -- play the animation
  7254.                         currentAnimTrack:Play(transitionTime)
  7255.                         currentAnim = animName
  7256.                         currentAnimInstance = anim
  7257.        
  7258.                         -- set up keyframe name triggers
  7259.                         if (currentAnimKeyframeHandler ~= nil) then
  7260.                                 currentAnimKeyframeHandler:disconnect()
  7261.                         end
  7262.                         currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)
  7263.                        
  7264.                 end
  7265.        
  7266.         end
  7267.        
  7268.         -------------------------------------------------------------------------------------------
  7269.         -------------------------------------------------------------------------------------------
  7270.        
  7271.         local toolAnimName = ""
  7272.         local toolAnimTrack = nil
  7273.         local toolAnimInstance = nil
  7274.         local currentToolAnimKeyframeHandler = nil
  7275.        
  7276.         function toolKeyFrameReachedFunc(frameName)
  7277.                 if (frameName == "End") then
  7278.         --              print("Keyframe : ".. frameName)       
  7279.                         playToolAnimation(toolAnimName, 0.0, Humanoid)
  7280.                 end
  7281.         end
  7282.        
  7283.        
  7284.         function playToolAnimation(animName, transitionTime, humanoid, priority)         
  7285.                        
  7286.                         local roll = math.random(1, animTable[animName].totalWeight)
  7287.                         local origRoll = roll
  7288.                         local idx = 1
  7289.                         while (roll > animTable[animName][idx].weight) do
  7290.                                 roll = roll - animTable[animName][idx].weight
  7291.                                 idx = idx + 1
  7292.                         end
  7293.         --              print(animName .. " * " .. idx .. " [" .. origRoll .. "]")
  7294.                         local anim = animTable[animName][idx].anim
  7295.        
  7296.                         if (toolAnimInstance ~= anim) then
  7297.                                
  7298.                                 if (toolAnimTrack ~= nil) then
  7299.                                         toolAnimTrack:Stop()
  7300.                                         toolAnimTrack:Destroy()
  7301.                                         transitionTime = 0
  7302.                                 end
  7303.                                                
  7304.                                 -- load it to the humanoid; get AnimationTrack
  7305.                                 toolAnimTrack = humanoid:LoadAnimation(anim)
  7306.                                 if priority then
  7307.                                         toolAnimTrack.Priority = priority
  7308.                                 end
  7309.                                  
  7310.                                 -- play the animation
  7311.                                 toolAnimTrack:Play(transitionTime)
  7312.                                 toolAnimName = animName
  7313.                                 toolAnimInstance = anim
  7314.        
  7315.                                 currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc)
  7316.                         end
  7317.         end
  7318.        
  7319.         function stopToolAnimations()
  7320.                 local oldAnim = toolAnimName
  7321.        
  7322.                 if (currentToolAnimKeyframeHandler ~= nil) then
  7323.                         currentToolAnimKeyframeHandler:disconnect()
  7324.                 end
  7325.        
  7326.                 toolAnimName = ""
  7327.                 toolAnimInstance = nil
  7328.                 if (toolAnimTrack ~= nil) then
  7329.                         toolAnimTrack:Stop()
  7330.                         toolAnimTrack:Destroy()
  7331.                         toolAnimTrack = nil
  7332.                 end
  7333.        
  7334.        
  7335.                 return oldAnim
  7336.         end
  7337.        
  7338.         -------------------------------------------------------------------------------------------
  7339.         -------------------------------------------------------------------------------------------
  7340.        
  7341.        
  7342.         function onRunning(speed)
  7343.                 if speed > 0.01 then
  7344.                         playAnimation("walk", 0.1, Humanoid)
  7345.                         if currentAnimInstance and currentAnimInstance.AnimationId == "http://www.roblox.com/asset/?id=180426354" then
  7346.                                 setAnimationSpeed(speed / 14.5)
  7347.                         end
  7348.                         pose = "Running"
  7349.                 else
  7350.                         if emoteNames[currentAnim] == nil then
  7351.                                 playAnimation("idle", 0.1, Humanoid)
  7352.                                 pose = "Standing"
  7353.                         end
  7354.                 end
  7355.         end
  7356.        
  7357.         function onDied()
  7358.                 pose = "Dead"
  7359.         end
  7360.        
  7361.         function onJumping()
  7362.                 playAnimation("jump", 0.1, Humanoid)
  7363.                 jumpAnimTime = jumpAnimDuration
  7364.                 pose = "Jumping"
  7365.         end
  7366.        
  7367.         function onClimbing(speed)
  7368.                 playAnimation("climb", 0.1, Humanoid)
  7369.                 setAnimationSpeed(speed / 12.0)
  7370.                 pose = "Climbing"
  7371.         end
  7372.        
  7373.         function onGettingUp()
  7374.                 pose = "GettingUp"
  7375.         end
  7376.        
  7377.         function onFreeFall()
  7378.                 if (jumpAnimTime  0 then
  7379.                         pose = "Running"
  7380.                 else
  7381.                         pose = "Standing"
  7382.                 end
  7383.         end
  7384.        
  7385.         function getTool()     
  7386.                 for _, kid in ipairs(Figure:GetChildren()) do
  7387.                         if kid.className == "Tool" then return kid end
  7388.                 end
  7389.                 return nil
  7390.         end
  7391.        
  7392.         function getToolAnim(tool)
  7393.                 for _, c in ipairs(tool:GetChildren()) do
  7394.                         if c.Name == "toolanim" and c.className == "StringValue" then
  7395.                                 return c
  7396.                         end
  7397.                 end
  7398.                 return nil
  7399.         end
  7400.        
  7401.         function animateTool()
  7402.                
  7403.                 if (toolAnim == "None") then
  7404.                         playToolAnimation("toolnone", toolTransitionTime, Humanoid, Enum.AnimationPriority.Idle)
  7405.                         return
  7406.                 end
  7407.        
  7408.                 if (toolAnim == "Slash") then
  7409.                         playToolAnimation("toolslash", 0, Humanoid, Enum.AnimationPriority.Action)
  7410.                         return
  7411.                 end
  7412.        
  7413.                 if (toolAnim == "Lunge") then
  7414.                         playToolAnimation("toollunge", 0, Humanoid, Enum.AnimationPriority.Action)
  7415.                         return
  7416.                 end
  7417.         end
  7418.        
  7419.         function moveSit()
  7420.                 RightShoulder.MaxVelocity = 0.15
  7421.                 LeftShoulder.MaxVelocity = 0.15
  7422.                 RightShoulder:SetDesiredAngle(3.14 /2)
  7423.                 LeftShoulder:SetDesiredAngle(-3.14 /2)
  7424.                 RightHip:SetDesiredAngle(3.14 /2)
  7425.                 LeftHip:SetDesiredAngle(-3.14 /2)
  7426.         end
  7427.        
  7428.         local lastTick = 0
  7429.        
  7430.         function move(time)
  7431.                 local amplitude = 1
  7432.                 local frequency = 1
  7433.                 local deltaTime = time - lastTick
  7434.                 lastTick = time
  7435.        
  7436.                 local climbFudge = 0
  7437.                 local setAngles = false
  7438.        
  7439.                 if (jumpAnimTime > 0) then
  7440.                         jumpAnimTime = jumpAnimTime - deltaTime
  7441.                 end
  7442.        
  7443.                 if (pose == "FreeFall" and jumpAnimTime  toolAnimTime then
  7444.                                 toolAnimTime = 0
  7445.                                 toolAnim = "None"
  7446.                         end
  7447.        
  7448.                         animateTool()          
  7449.                 else
  7450.                         stopToolAnimations()
  7451.                         toolAnim = "None"
  7452.                         toolAnimInstance = nil
  7453.                         toolAnimTime = 0
  7454.                 end
  7455.         end
  7456.        
  7457.        
  7458.         local events = {}
  7459.         local eventHum = Humanoid
  7460.        
  7461.         local function onUnhook()
  7462.                 for i = 1, #events do
  7463.                         events[i]:Disconnect()
  7464.                 end
  7465.                 events = {}
  7466.         end
  7467.        
  7468.         local function onHook()
  7469.                 onUnhook()
  7470.                
  7471.                 pose = eventHum.Sit and "Seated" or "Standing"
  7472.                
  7473.                 events = {
  7474.                         eventHum.Died:connect(onDied),
  7475.                         eventHum.Running:connect(onRunning),
  7476.                         eventHum.Jumping:connect(onJumping),
  7477.                         eventHum.Climbing:connect(onClimbing),
  7478.                         eventHum.GettingUp:connect(onGettingUp),
  7479.                         eventHum.FreeFalling:connect(onFreeFall),
  7480.                         eventHum.FallingDown:connect(onFallingDown),
  7481.                         eventHum.Seated:connect(onSeated),
  7482.                         eventHum.PlatformStanding:connect(onPlatformStanding),
  7483.                         eventHum.Swimming:connect(onSwimming)
  7484.                 }
  7485.         end
  7486.        
  7487.        
  7488.         onHook()
  7489.        
  7490.         -- setup emote chat hook
  7491.         game:GetService("Players").LocalPlayer.Chatted:connect(function(msg)
  7492.                 local emote = ""
  7493.                 if msg == "/e dance" then
  7494.                         emote = dances[math.random(1, #dances)]
  7495.                 elseif (string.sub(msg, 1, 3) == "/e ") then
  7496.                         emote = string.sub(msg, 4)
  7497.                 elseif (string.sub(msg, 1, 7) == "/emote ") then
  7498.                         emote = string.sub(msg, 8)
  7499.                 end
  7500.                
  7501.                 if (pose == "Standing" and emoteNames[emote] ~= nil) then
  7502.                         playAnimation(emote, 0.1, Humanoid)
  7503.                 end
  7504.        
  7505.         end)
  7506.        
  7507.        
  7508.         -- main program
  7509.        
  7510.         -- initialize to idle
  7511.         playAnimation("idle", 0.1, Humanoid)
  7512.         pose = "Standing"
  7513.        
  7514.         spawn(function()
  7515.                 while Figure.Parent ~= nil do
  7516.                         local _, time = wait(0.1)
  7517.                         move(time)
  7518.                 end
  7519.         end)
  7520.        
  7521.         return {
  7522.                 onRunning = onRunning,
  7523.                 onDied = onDied,
  7524.                 onJumping = onJumping,
  7525.                 onClimbing = onClimbing,
  7526.                 onGettingUp = onGettingUp,
  7527.                 onFreeFall = onFreeFall,
  7528.                 onFallingDown = onFallingDown,
  7529.                 onSeated = onSeated,
  7530.                 onPlatformStanding = onPlatformStanding,
  7531.                 onHook = onHook,
  7532.                 onUnhook = onUnhook
  7533.         }
  7534.        
  7535.         end
  7536.         return r6()
  7537. end
  7538.  
  7539. function _R15()
  7540.         local function r15()
  7541.                
  7542.         local Character = char
  7543.         local Humanoid = Character:WaitForChild("Humanoid")
  7544.         local pose = "Standing"
  7545.        
  7546.         local userNoUpdateOnLoopSuccess, userNoUpdateOnLoopValue = pcall(function() return UserSettings():IsUserFeatureEnabled("UserNoUpdateOnLoop") end)
  7547.         local userNoUpdateOnLoop = userNoUpdateOnLoopSuccess and userNoUpdateOnLoopValue
  7548.         local userAnimationSpeedDampeningSuccess, userAnimationSpeedDampeningValue = pcall(function() return UserSettings():IsUserFeatureEnabled("UserAnimationSpeedDampening") end)
  7549.         local userAnimationSpeedDampening = userAnimationSpeedDampeningSuccess and userAnimationSpeedDampeningValue
  7550.        
  7551.         local animateScriptEmoteHookFlagExists, animateScriptEmoteHookFlagEnabled = pcall(function()
  7552.                 return UserSettings():IsUserFeatureEnabled("UserAnimateScriptEmoteHook")
  7553.         end)
  7554.         local FFlagAnimateScriptEmoteHook = animateScriptEmoteHookFlagExists and animateScriptEmoteHookFlagEnabled
  7555.        
  7556.         local AnimationSpeedDampeningObject = script:FindFirstChild("ScaleDampeningPercent")
  7557.         local HumanoidHipHeight = 2
  7558.        
  7559.         local EMOTE_TRANSITION_TIME = 0.1
  7560.        
  7561.         local currentAnim = ""
  7562.         local currentAnimInstance = nil
  7563.         local currentAnimTrack = nil
  7564.         local currentAnimKeyframeHandler = nil
  7565.         local currentAnimSpeed = 1.0
  7566.        
  7567.         local runAnimTrack = nil
  7568.         local runAnimKeyframeHandler = nil
  7569.        
  7570.         local animTable = {}
  7571.         local animNames = {
  7572.                 idle =  {      
  7573.                                         { id = "http://www.roblox.com/asset/?id=507766666", weight = 1 },
  7574.                                         { id = "http://www.roblox.com/asset/?id=507766951", weight = 1 },
  7575.                                         { id = "http://www.roblox.com/asset/?id=507766388", weight = 9 }
  7576.                                 },
  7577.                 walk =  {      
  7578.                                         { id = "http://www.roblox.com/asset/?id=507777826", weight = 10 }
  7579.                                 },
  7580.                 run =   {
  7581.                                         { id = "http://www.roblox.com/asset/?id=507767714", weight = 10 }
  7582.                                 },
  7583.                 swim =  {
  7584.                                         { id = "http://www.roblox.com/asset/?id=507784897", weight = 10 }
  7585.                                 },
  7586.                 swimidle =      {
  7587.                                         { id = "http://www.roblox.com/asset/?id=507785072", weight = 10 }
  7588.                                 },
  7589.                 jump =  {
  7590.                                         { id = "http://www.roblox.com/asset/?id=507765000", weight = 10 }
  7591.                                 },
  7592.                 fall =  {
  7593.                                         { id = "http://www.roblox.com/asset/?id=507767968", weight = 10 }
  7594.                                 },
  7595.                 climb = {
  7596.                                         { id = "http://www.roblox.com/asset/?id=507765644", weight = 10 }
  7597.                                 },
  7598.                 sit =   {
  7599.                                         { id = "http://www.roblox.com/asset/?id=2506281703", weight = 10 }
  7600.                                 },     
  7601.                 toolnone = {
  7602.                                         { id = "http://www.roblox.com/asset/?id=507768375", weight = 10 }
  7603.                                 },
  7604.                 toolslash = {
  7605.                                         { id = "http://www.roblox.com/asset/?id=522635514", weight = 10 }
  7606.                                 },
  7607.                 toollunge = {
  7608.                                         { id = "http://www.roblox.com/asset/?id=522638767", weight = 10 }
  7609.                                 },
  7610.                 wave = {
  7611.                                         { id = "http://www.roblox.com/asset/?id=507770239", weight = 10 }
  7612.                                 },
  7613.                 point = {
  7614.                                         { id = "http://www.roblox.com/asset/?id=507770453", weight = 10 }
  7615.                                 },
  7616.                 dance = {
  7617.                                         { id = "http://www.roblox.com/asset/?id=507771019", weight = 10 },
  7618.                                         { id = "http://www.roblox.com/asset/?id=507771955", weight = 10 },
  7619.                                         { id = "http://www.roblox.com/asset/?id=507772104", weight = 10 }
  7620.                                 },
  7621.                 dance2 = {
  7622.                                         { id = "http://www.roblox.com/asset/?id=507776043", weight = 10 },
  7623.                                         { id = "http://www.roblox.com/asset/?id=507776720", weight = 10 },
  7624.                                         { id = "http://www.roblox.com/asset/?id=507776879", weight = 10 }
  7625.                                 },
  7626.                 dance3 = {
  7627.                                         { id = "http://www.roblox.com/asset/?id=507777268", weight = 10 },
  7628.                                         { id = "http://www.roblox.com/asset/?id=507777451", weight = 10 },
  7629.                                         { id = "http://www.roblox.com/asset/?id=507777623", weight = 10 }
  7630.                                 },
  7631.                 laugh = {
  7632.                                         { id = "http://www.roblox.com/asset/?id=507770818", weight = 10 }
  7633.                                 },
  7634.                 cheer = {
  7635.                                         { id = "http://www.roblox.com/asset/?id=507770677", weight = 10 }
  7636.                                 },
  7637.         }
  7638.        
  7639.         -- Existance in this list signifies that it is an emote, the value indicates if it is a looping emote
  7640.         local emoteNames = { wave = false, point = false, dance = true, dance2 = true, dance3 = true, laugh = false, cheer = false}
  7641.        
  7642.         local PreloadAnimsUserFlag = false
  7643.         local PreloadedAnims = {}
  7644.         local successPreloadAnim, msgPreloadAnim = pcall(function()
  7645.                 PreloadAnimsUserFlag = UserSettings():IsUserFeatureEnabled("UserPreloadAnimations")
  7646.         end)
  7647.         if not successPreloadAnim then
  7648.                 PreloadAnimsUserFlag = false
  7649.         end
  7650.        
  7651.         math.randomseed(tick())
  7652.        
  7653.         function findExistingAnimationInSet(set, anim)
  7654.                 if set == nil or anim == nil then
  7655.                         return 0
  7656.                 end
  7657.                
  7658.                 for idx = 1, set.count, 1 do
  7659.                         if set[idx].anim.AnimationId == anim.AnimationId then
  7660.                                 return idx
  7661.                         end
  7662.                 end
  7663.                
  7664.                 return 0
  7665.         end
  7666.        
  7667.         function configureAnimationSet(name, fileList)
  7668.                 if (animTable[name] ~= nil) then
  7669.                         for _, connection in pairs(animTable[name].connections) do
  7670.                                 connection:disconnect()
  7671.                         end
  7672.                 end
  7673.                 animTable[name] = {}
  7674.                 animTable[name].count = 0
  7675.                 animTable[name].totalWeight = 0
  7676.                 animTable[name].connections = {}
  7677.        
  7678.                 local allowCustomAnimations = true
  7679.        
  7680.                 local success, msg = pcall(function() allowCustomAnimations = game:GetService("StarterPlayer").AllowCustomAnimations end)
  7681.                 if not success then
  7682.                         allowCustomAnimations = true
  7683.                 end
  7684.        
  7685.                 -- check for config values
  7686.                 local config = script:FindFirstChild(name)
  7687.                 if (allowCustomAnimations and config ~= nil) then
  7688.                         table.insert(animTable[name].connections, config.ChildAdded:connect(function(child) configureAnimationSet(name, fileList) end))
  7689.                         table.insert(animTable[name].connections, config.ChildRemoved:connect(function(child) configureAnimationSet(name, fileList) end))
  7690.                        
  7691.                         local idx = 0
  7692.                         for _, childPart in pairs(config:GetChildren()) do
  7693.                                 if (childPart:IsA("Animation")) then
  7694.                                         local newWeight = 1
  7695.                                         local weightObject = childPart:FindFirstChild("Weight")
  7696.                                         if (weightObject ~= nil) then
  7697.                                                 newWeight = weightObject.Value
  7698.                                         end
  7699.                                         animTable[name].count = animTable[name].count + 1
  7700.                                         idx = animTable[name].count
  7701.                                         animTable[name][idx] = {}
  7702.                                         animTable[name][idx].anim = childPart
  7703.                                         animTable[name][idx].weight = newWeight
  7704.                                         animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
  7705.                                         table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end))
  7706.                                         table.insert(animTable[name].connections, childPart.ChildAdded:connect(function(property) configureAnimationSet(name, fileList) end))
  7707.                                         table.insert(animTable[name].connections, childPart.ChildRemoved:connect(function(property) configureAnimationSet(name, fileList) end))
  7708.                                 end
  7709.                         end
  7710.                 end
  7711.                
  7712.                 -- fallback to defaults
  7713.                 if (animTable[name].count  0.75 then
  7714.                         local scale = 16.0
  7715.                         playAnimation("walk", 0.2, Humanoid)
  7716.                         setAnimationSpeed(speed / scale)
  7717.                         pose = "Running"
  7718.                 else
  7719.                         if emoteNames[currentAnim] == nil and not currentlyPlayingEmote then
  7720.                                 playAnimation("idle", 0.2, Humanoid)
  7721.                                 pose = "Standing"
  7722.                         end
  7723.                 end
  7724.         end
  7725.        
  7726.         function onDied()
  7727.                 pose = "Dead"
  7728.         end
  7729.        
  7730.         function onJumping()
  7731.                 playAnimation("jump", 0.1, Humanoid)
  7732.                 jumpAnimTime = jumpAnimDuration
  7733.                 pose = "Jumping"
  7734.         end
  7735.        
  7736.         function onClimbing(speed)
  7737.                 local scale = 5.0
  7738.                 playAnimation("climb", 0.1, Humanoid)
  7739.                 setAnimationSpeed(speed / scale)
  7740.                 pose = "Climbing"
  7741.         end
  7742.        
  7743.         function onGettingUp()
  7744.                 pose = "GettingUp"
  7745.         end
  7746.        
  7747.         function onFreeFall()
  7748.                 if (jumpAnimTime  1.00 then
  7749.                         local scale = 10.0
  7750.                         playAnimation("swim", 0.4, Humanoid)
  7751.                         setAnimationSpeed(speed / scale)
  7752.                         pose = "Swimming"
  7753.                 else
  7754.                         playAnimation("swimidle", 0.4, Humanoid)
  7755.                         pose = "Standing"
  7756.                 end
  7757.         end
  7758.        
  7759.         function animateTool()
  7760.                 if (toolAnim == "None") then
  7761.                         playToolAnimation("toolnone", toolTransitionTime, Humanoid, Enum.AnimationPriority.Idle)
  7762.                         return
  7763.                 end
  7764.        
  7765.                 if (toolAnim == "Slash") then
  7766.                         playToolAnimation("toolslash", 0, Humanoid, Enum.AnimationPriority.Action)
  7767.                         return
  7768.                 end
  7769.        
  7770.                 if (toolAnim == "Lunge") then
  7771.                         playToolAnimation("toollunge", 0, Humanoid, Enum.AnimationPriority.Action)
  7772.                         return
  7773.                 end
  7774.         end
  7775.        
  7776.         function getToolAnim(tool)
  7777.                 for _, c in ipairs(tool:GetChildren()) do
  7778.                         if c.Name == "toolanim" and c.className == "StringValue" then
  7779.                                 return c
  7780.                         end
  7781.                 end
  7782.                 return nil
  7783.         end
  7784.        
  7785.         local lastTick = 0
  7786.        
  7787.         function stepAnimate(currentTime)
  7788.                 local amplitude = 1
  7789.                 local frequency = 1
  7790.                 local deltaTime = currentTime - lastTick
  7791.                 lastTick = currentTime
  7792.        
  7793.                 local climbFudge = 0
  7794.                 local setAngles = false
  7795.        
  7796.                 if (jumpAnimTime > 0) then
  7797.                         jumpAnimTime = jumpAnimTime - deltaTime
  7798.                 end
  7799.        
  7800.                 if (pose == "FreeFall" and jumpAnimTime  toolAnimTime then
  7801.                                 toolAnimTime = 0
  7802.                                 toolAnim = "None"
  7803.                         end
  7804.        
  7805.                         animateTool()          
  7806.                 else
  7807.                         stopToolAnimations()
  7808.                         toolAnim = "None"
  7809.                         toolAnimInstance = nil
  7810.                         toolAnimTime = 0
  7811.                 end
  7812.         end
  7813.        
  7814.         -- connect events
  7815.        
  7816.         local events = {}
  7817.         local eventHum = Humanoid
  7818.        
  7819.         local function onUnhook()
  7820.                 for i = 1, #events do
  7821.                         events[i]:Disconnect()
  7822.                 end
  7823.                 events = {}
  7824.         end
  7825.        
  7826.         local function onHook()
  7827.                 onUnhook()
  7828.                
  7829.                 pose = eventHum.Sit and "Seated" or "Standing"
  7830.                
  7831.                 events = {
  7832.                         eventHum.Died:connect(onDied),
  7833.                         eventHum.Running:connect(onRunning),
  7834.                         eventHum.Jumping:connect(onJumping),
  7835.                         eventHum.Climbing:connect(onClimbing),
  7836.                         eventHum.GettingUp:connect(onGettingUp),
  7837.                         eventHum.FreeFalling:connect(onFreeFall),
  7838.                         eventHum.FallingDown:connect(onFallingDown),
  7839.                         eventHum.Seated:connect(onSeated),
  7840.                         eventHum.PlatformStanding:connect(onPlatformStanding),
  7841.                         eventHum.Swimming:connect(onSwimming)
  7842.                 }
  7843.         end
  7844.        
  7845.        
  7846.         onHook()
  7847.        
  7848.         -- setup emote chat hook
  7849.         game:GetService("Players").LocalPlayer.Chatted:connect(function(msg)
  7850.                 local emote = ""
  7851.                 if (string.sub(msg, 1, 3) == "/e ") then
  7852.                         emote = string.sub(msg, 4)
  7853.                 elseif (string.sub(msg, 1, 7) == "/emote ") then
  7854.                         emote = string.sub(msg, 8)
  7855.                 end
  7856.                
  7857.                 if (pose == "Standing" and emoteNames[emote] ~= nil) then
  7858.                         playAnimation(emote, EMOTE_TRANSITION_TIME, Humanoid)
  7859.                 end
  7860.         end)
  7861.        
  7862.         --[[ emote bindable hook
  7863.         if FFlagAnimateScriptEmoteHook then
  7864.                 script:WaitForChild("PlayEmote").OnInvoke = function(emote)
  7865.                         -- Only play emotes when idling
  7866.                         if pose ~= "Standing" then
  7867.                                 return
  7868.                         end
  7869.                         if emoteNames[emote] ~= nil then
  7870.                                 -- Default emotes
  7871.                                 playAnimation(emote, EMOTE_TRANSITION_TIME, Humanoid)
  7872.                                 return true
  7873.                         elseif typeof(emote) == "Instance" and emote:IsA("Animation") then
  7874.                                 -- Non-default emotes
  7875.                                 playEmote(emote, EMOTE_TRANSITION_TIME, Humanoid)
  7876.                                 return true
  7877.                         end
  7878.                         -- Return false to indicate that the emote could not be played
  7879.                         return false
  7880.                 end
  7881.         end
  7882.         ]]
  7883.         -- initialize to idle
  7884.         playAnimation("idle", 0.1, Humanoid)
  7885.         pose = "Standing"
  7886.         -- loop to handle timed state transitions and tool animations
  7887.         spawn(function()
  7888.                 while Character.Parent ~= nil do
  7889.                         local _, currentGameTime = wait(0.1)
  7890.                         stepAnimate(currentGameTime)
  7891.                 end
  7892.         end)
  7893.         return {
  7894.                 onRunning = onRunning,
  7895.                 onDied = onDied,
  7896.                 onJumping = onJumping,
  7897.                 onClimbing = onClimbing,
  7898.                 onGettingUp = onGettingUp,
  7899.                 onFreeFall = onFreeFall,
  7900.                 onFallingDown = onFallingDown,
  7901.                 onSeated = onSeated,
  7902.                 onPlatformStanding = onPlatformStanding,
  7903.                 onHook = onHook,
  7904.                 onUnhook = onUnhook
  7905.         }
  7906.         end
  7907.         return r15()
  7908. end
  7909. while true do
  7910.         wait(.1)
  7911.         if plr.Character ~= nil then
  7912.                 char = plr.Character
  7913.                 break
  7914.         end
  7915. end
  7916. function _Controller()
  7917.         local humanoid = char:WaitForChild("Humanoid")
  7918.         local animFuncs = {}
  7919.         if (humanoid.RigType == Enum.HumanoidRigType.R6) then
  7920.                 animFuncs = _R6()
  7921.         else
  7922.                 animFuncs = _R15()
  7923.         end
  7924.         print("Animation succes")
  7925.         return animFuncs
  7926. end
  7927. function _AnimationHandler()
  7928. local AnimationHandler = {}
  7929. AnimationHandler.__index = AnimationHandler
  7930.  
  7931. function AnimationHandler.new(humanoid, animate)
  7932.         local self = setmetatable({}, AnimationHandler)
  7933.        
  7934.         self._AnimFuncs = _Controller()
  7935.         self.Humanoid = humanoid
  7936.        
  7937.         return self
  7938. end
  7939.  
  7940. function AnimationHandler:EnableDefault(bool)
  7941.         if (bool) then
  7942.                 self._AnimFuncs.onHook()
  7943.         else
  7944.                 self._AnimFuncs.onUnhook()
  7945.         end
  7946. end
  7947.  
  7948. function AnimationHandler:Run(name, ...)
  7949.         self._AnimFuncs[name](...)
  7950. end
  7951.  
  7952. return AnimationHandler
  7953. end
  7954.  
  7955. function _GravityController()
  7956.  
  7957. local ZERO = Vector3.new(0, 0, 0)
  7958. local UNIT_X = Vector3.new(1, 0, 0)
  7959. local UNIT_Y = Vector3.new(0, 1, 0)
  7960. local UNIT_Z = Vector3.new(0, 0, 1)
  7961. local VEC_XY = Vector3.new(1, 0, 1)
  7962.  
  7963. local IDENTITYCF = CFrame.new()
  7964.  
  7965. local JUMPMODIFIER = 1.2
  7966. local TRANSITION = 0.15
  7967. local WALKF = 200 / 3
  7968.  
  7969. local UIS = game:GetService("UserInputService")
  7970. local RUNSERVICE = game:GetService("RunService")
  7971.  
  7972. local InitObjects = _InitObjects()
  7973. local AnimationHandler = _AnimationHandler()
  7974. local StateTracker = _StateTracker()
  7975.  
  7976. -- Class
  7977.  
  7978. local GravityController = {}
  7979. GravityController.__index = GravityController
  7980.  
  7981. -- Private Functions
  7982.  
  7983. local function getRotationBetween(u, v, axis)
  7984.         local dot, uxv = u:Dot(v), u:Cross(v)
  7985.         if (dot < -0.99999) then return CFrame.fromAxisAngle(axis, math.pi) end
  7986.         return CFrame.new(0, 0, 0, uxv.x, uxv.y, uxv.z, 1 + dot)
  7987. end
  7988.  
  7989. local function lookAt(pos, forward, up)
  7990.         local r = forward:Cross(up)
  7991.         local u = r:Cross(forward)
  7992.         return CFrame.fromMatrix(pos, r.Unit, u.Unit)
  7993. end
  7994.  
  7995. local function getMass(array)
  7996.         local mass = 0
  7997.         for _, part in next, array do
  7998.                 if (part:IsA("BasePart")) then
  7999.                         mass = mass + part:GetMass()
  8000.                 end
  8001.         end
  8002.         return mass
  8003. end
  8004.  
  8005. -- Public Constructor
  8006. local ExecutedPlayerModule = _PlayerModule()
  8007. local ExecutedSounds = _sounds()
  8008. function GravityController.new(player)
  8009.         local self = setmetatable({}, GravityController)
  8010.  
  8011.         --[[ Camera
  8012.         local loaded = player.PlayerScripts:WaitForChild("PlayerScriptsLoader"):WaitForChild("Loaded")
  8013.         if (not loaded.Value) then
  8014.                 --loaded.Changed:Wait()
  8015.         end
  8016.         ]]
  8017.         local playerModule = ExecutedPlayerModule
  8018.         self.Controls = playerModule:GetControls()
  8019.         self.Camera = playerModule:GetCameras()
  8020.        
  8021.         -- Player and character
  8022.         self.Player = player
  8023.         self.Character = player.Character
  8024.         self.Humanoid = player.Character:WaitForChild("Humanoid")
  8025.         self.HRP = player.Character:WaitForChild("HumanoidRootPart")
  8026.        
  8027.         -- Animation
  8028.         self.AnimationHandler = AnimationHandler.new(self.Humanoid, self.Character:WaitForChild("Animate"))
  8029.         self.AnimationHandler:EnableDefault(false)
  8030.         local ssss = game:GetService("Players").LocalPlayer.PlayerScripts:FindFirstChild("SetState") or Instance.new("BindableEvent",game:GetService("Players").LocalPlayer.PlayerScripts)
  8031.         local soundState = ExecutedSounds
  8032.         ssss.Name = "SetState"
  8033.        
  8034.         self.StateTracker = StateTracker.new(self.Humanoid, soundState)
  8035.         self.StateTracker.Changed:Connect(function(name, speed)
  8036.                 self.AnimationHandler:Run(name, speed)
  8037.         end)
  8038.        
  8039.         -- Collider and forces
  8040.         local collider, gyro, vForce, floor = InitObjects(self)
  8041.        
  8042.         floor.Touched:Connect(function() end)
  8043.         collider.Touched:Connect(function() end)
  8044.        
  8045.         self.Collider = collider
  8046.         self.VForce = vForce
  8047.         self.Gyro = gyro
  8048.         self.Floor = floor
  8049.        
  8050.         -- Attachment to parts
  8051.         self.LastPart = workspace.Terrain
  8052.         self.LastPartCFrame = IDENTITYCF
  8053.        
  8054.         -- Gravity properties
  8055.         self.GravityUp = UNIT_Y
  8056.         self.Ignores = {self.Character}
  8057.        
  8058.         function self.Camera.GetUpVector(this, oldUpVector)
  8059.                 return self.GravityUp
  8060.         end
  8061.        
  8062.         -- Events etc
  8063.         self.Humanoid.PlatformStand = true
  8064.        
  8065.         self.CharacterMass = getMass(self.Character:GetDescendants())
  8066.         self.Character.AncestryChanged:Connect(function() self.CharacterMass = getMass(self.Character:GetDescendants()) end)
  8067.        
  8068.         self.JumpCon = RUNSERVICE.RenderStepped:Connect(function(dt)
  8069.                 if (self.Controls:IsJumping()) then
  8070.                         self:OnJumpRequest()
  8071.                 end
  8072.         end)
  8073.        
  8074.         self.DeathCon = self.Humanoid.Died:Connect(function() self:Destroy() end)
  8075.         self.SeatCon = self.Humanoid.Seated:Connect(function(active) if (active) then self:Destroy() end end)
  8076.         self.HeartCon = RUNSERVICE.Heartbeat:Connect(function(dt) self:OnHeartbeatStep(dt) end)
  8077.         RUNSERVICE:BindToRenderStep("GravityStep", Enum.RenderPriority.Input.Value + 1, function(dt) self:OnGravityStep(dt) end)
  8078.        
  8079.        
  8080.         return self
  8081. end
  8082.  
  8083. -- Public Methods
  8084.  
  8085. function GravityController:Destroy()
  8086.         self.JumpCon:Disconnect()
  8087.         self.DeathCon:Disconnect()
  8088.         self.SeatCon:Disconnect()
  8089.         self.HeartCon:Disconnect()
  8090.        
  8091.         RUNSERVICE:UnbindFromRenderStep("GravityStep")
  8092.        
  8093.         self.Collider:Destroy()
  8094.         self.VForce:Destroy()
  8095.         self.Gyro:Destroy()
  8096.         self.StateTracker:Destroy()
  8097.        
  8098.         self.Humanoid.PlatformStand = false
  8099.         self.AnimationHandler:EnableDefault(true)
  8100.        
  8101.         self.GravityUp = UNIT_Y
  8102. end
  8103.  
  8104. function GravityController:GetGravityUp(oldGravity)
  8105.         return oldGravity
  8106. end
  8107.  
  8108. function GravityController:IsGrounded(isJumpCheck)
  8109.         if (not isJumpCheck) then
  8110.                 local parts = self.Floor:GetTouchingParts()
  8111.                 for _, part in next, parts do
  8112.                         if (not part:IsDescendantOf(self.Character)) then
  8113.                                 return true
  8114.                         end
  8115.                 end
  8116.         else
  8117.                 if (self.StateTracker.Jumped) then
  8118.                         return false
  8119.                 end
  8120.        
  8121.                 -- 1. check we are touching something with the collider
  8122.                 local valid = {}
  8123.                 local parts = self.Collider:GetTouchingParts()
  8124.                 for _, part in next, parts do
  8125.                         if (not part:IsDescendantOf(self.Character)) then
  8126.                                 table.insert(valid, part)
  8127.                         end
  8128.                 end
  8129.                
  8130.                 if (#valid > 0) then
  8131.                         -- 2. do a decently long downwards raycast
  8132.                         local max = math.cos(self.Humanoid.MaxSlopeAngle)
  8133.                         local ray = Ray.new(self.Collider.Position, -10 * self.GravityUp)
  8134.                         local hit, pos, normal = workspace:FindPartOnRayWithWhitelist(ray, valid, true)
  8135.                        
  8136.                         -- 3. use slope to decide on jump
  8137.                         if (hit and max  0.5 and -math.sign(fDot)*camCF.UpVector or camCF.LookVector
  8138.        
  8139.         local left = cForward:Cross(-newGravity).Unit
  8140.         local forward = -left:Cross(newGravity).Unit
  8141.        
  8142.         local move = self:GetMoveVector()
  8143.         local worldMove = forward*move.z - left*move.x
  8144.         worldMove = worldMove:Dot(worldMove) > 1 and worldMove.Unit or worldMove
  8145.        
  8146.         local isInputMoving = worldMove:Dot(worldMove) > 0
  8147.        
  8148.         -- get the desired character cframe
  8149.         local hrpCFLook = self.HRP.CFrame.LookVector
  8150.         local charF = hrpCFLook:Dot(forward)*forward + hrpCFLook:Dot(left)*left
  8151.         local charR = charF:Cross(newGravity).Unit
  8152.         local newCharCF = CFrame.fromMatrix(ZERO, charR, newGravity, -charF)
  8153.        
  8154.         local newCharRotation = IDENTITYCF
  8155.         if (isInputMoving) then
  8156.                 newCharRotation = IDENTITYCF:Lerp(getRotationBetween(charF, worldMove, newGravity), 0.7)       
  8157.         end
  8158.        
  8159.         -- calculate forces
  8160.         local g = workspace.Gravity
  8161.         local gForce = g * self.CharacterMass * (UNIT_Y - newGravity)
  8162.        
  8163.         local cVelocity = self.HRP.Velocity
  8164.         local tVelocity = self.Humanoid.WalkSpeed * worldMove
  8165.         local gVelocity = cVelocity:Dot(newGravity)*newGravity
  8166.         local hVelocity = cVelocity - gVelocity
  8167.        
  8168.         if (hVelocity:Dot(hVelocity) < 1) then
  8169.                 hVelocity = ZERO
  8170.         end
  8171.        
  8172.         local dVelocity = tVelocity - hVelocity
  8173.         local walkForceM = math.min(10000, WALKF * self.CharacterMass * dVelocity.Magnitude / (dt*60))
  8174.         local walkForce = walkForceM > 0 and dVelocity.Unit*walkForceM or ZERO
  8175.        
  8176.         -- mouse lock
  8177.         local charRotation = newCharRotation * newCharCF
  8178.        
  8179.         if (self.Camera:IsCamRelative()) then
  8180.                 local lv = workspace.CurrentCamera.CFrame.LookVector
  8181.                 local hlv = lv - charRotation.UpVector:Dot(lv)*charRotation.UpVector
  8182.                 charRotation = lookAt(ZERO, hlv, charRotation.UpVector)
  8183.         end
  8184.        
  8185.         -- get state
  8186.         self.StateTracker:OnStep(self.GravityUp, self:IsGrounded(), isInputMoving)
  8187.  
  8188.         -- update values
  8189.         self.VForce.Force = walkForce + gForce
  8190.         self.Gyro.CFrame = charRotation
  8191. end
  8192. return GravityController
  8193. end
  8194. function _Draw3D()
  8195.         local module = {}
  8196.        
  8197.         -- Style Guide
  8198.        
  8199.         module.StyleGuide = {
  8200.                 Point = {
  8201.                         Thickness = 0.5;
  8202.                         Color = Color3.new(0, 1, 0);
  8203.                 },
  8204.                
  8205.                 Line = {
  8206.                         Thickness = 0.1;
  8207.                         Color = Color3.new(1, 1, 0);
  8208.                 },
  8209.                
  8210.                 Ray = {
  8211.                         Thickness = 0.1;
  8212.                         Color = Color3.new(1, 0, 1);
  8213.                 },
  8214.                
  8215.                 Triangle = {
  8216.                         Thickness = 0.05;
  8217.                 };
  8218.                
  8219.                 CFrame = {
  8220.                         Thickness = 0.1;
  8221.                         RightColor3 = Color3.new(1, 0, 0);
  8222.                         UpColor3 = Color3.new(0, 1, 0);
  8223.                         BackColor3 = Color3.new(0, 0, 1);
  8224.                         PartProperties = {
  8225.                                 Material = Enum.Material.SmoothPlastic;
  8226.                         };
  8227.                 }
  8228.         }
  8229.        
  8230.         -- CONSTANTS
  8231.        
  8232.         local WEDGE = Instance.new("WedgePart")
  8233.         WEDGE.Material = Enum.Material.SmoothPlastic
  8234.         WEDGE.Anchored = true
  8235.         WEDGE.CanCollide = false
  8236.        
  8237.         local PART = Instance.new("Part")
  8238.         PART.Size = Vector3.new(0.1, 0.1, 0.1)
  8239.         PART.Anchored = true
  8240.         PART.CanCollide = false
  8241.         PART.TopSurface = Enum.SurfaceType.Smooth
  8242.         PART.BottomSurface = Enum.SurfaceType.Smooth
  8243.         PART.Material = Enum.Material.SmoothPlastic
  8244.        
  8245.         -- Functions
  8246.        
  8247.         local function draw(properties, style)
  8248.                 local part = PART:Clone()
  8249.                 for k, v in next, properties do
  8250.                         part[k] = v
  8251.                 end
  8252.                 if (style) then
  8253.                         for k, v in next, style do
  8254.                                 if (k ~= "Thickness") then
  8255.                                         part[k] = v
  8256.                                 end
  8257.                         end
  8258.                 end
  8259.                 return part
  8260.         end
  8261.        
  8262.         function module.Draw(parent, properties)
  8263.                 properties.Parent = parent
  8264.                 return draw(properties, nil)
  8265.         end
  8266.        
  8267.         function module.Point(parent, cf_v3)
  8268.                 local thickness = module.StyleGuide.Point.Thickness
  8269.                 return draw({
  8270.                         Size = Vector3.new(thickness, thickness, thickness);
  8271.                         CFrame = (typeof(cf_v3) == "CFrame" and cf_v3 or CFrame.new(cf_v3));
  8272.                         Parent = parent;
  8273.                 }, module.StyleGuide.Point)
  8274.         end
  8275.        
  8276.         function module.Line(parent, a, b)
  8277.                 local thickness = module.StyleGuide.Line.Thickness
  8278.                 return draw({
  8279.                         CFrame = CFrame.new((a + b)/2, b);
  8280.                         Size = Vector3.new(thickness, thickness, (b - a).Magnitude);
  8281.                         Parent = parent;
  8282.                 }, module.StyleGuide.Line)
  8283.         end
  8284.        
  8285.         function module.Ray(parent, origin, direction)
  8286.                 local thickness = module.StyleGuide.Ray.Thickness
  8287.                 return draw({
  8288.                         CFrame = CFrame.new(origin + direction/2, origin + direction);
  8289.                         Size = Vector3.new(thickness, thickness, direction.Magnitude);
  8290.                         Parent = parent;
  8291.                 }, module.StyleGuide.Ray)
  8292.         end
  8293.        
  8294.         function module.Triangle(parent, a, b, c)
  8295.                 local ab, ac, bc = b - a, c - a, c - b
  8296.                 local abd, acd, bcd = ab:Dot(ab), ac:Dot(ac), bc:Dot(bc)
  8297.                
  8298.                 if (abd > acd and abd > bcd) then
  8299.                         c, a = a, c
  8300.                 elseif (acd > bcd and acd > abd) then
  8301.                         a, b = b, a
  8302.                 end
  8303.                
  8304.                 ab, ac, bc = b - a, c - a, c - b
  8305.                
  8306.                 local right = ac:Cross(ab).Unit
  8307.                 local up = bc:Cross(right).Unit
  8308.                 local back = bc.Unit
  8309.                
  8310.                 local height = math.abs(ab:Dot(up))
  8311.                 local width1 = math.abs(ab:Dot(back))
  8312.                 local width2 = math.abs(ac:Dot(back))
  8313.                
  8314.                 local thickness = module.StyleGuide.Triangle.Thickness
  8315.                
  8316.                 local w1 = WEDGE:Clone()
  8317.                 w1.Size = Vector3.new(thickness, height, width1)
  8318.                 w1.CFrame = CFrame.fromMatrix((a + b)/2, right, up, back)
  8319.                 w1.Parent = parent
  8320.                
  8321.                 local w2 = WEDGE:Clone()
  8322.                 w2.Size = Vector3.new(thickness, height, width2)
  8323.                 w2.CFrame = CFrame.fromMatrix((a + c)/2, -right, up, -back)
  8324.                 w2.Parent = parent
  8325.                
  8326.                 for k, v in next, module.StyleGuide.Triangle do
  8327.                         if (k ~= "Thickness") then
  8328.                                 w1[k] = v
  8329.                                 w2[k] = v
  8330.                         end
  8331.                 end
  8332.                
  8333.                 return w1, w2
  8334.         end
  8335.        
  8336.         function module.CFrame(parent, cf)
  8337.                 local origin = cf.Position
  8338.                 local r = cf.RightVector
  8339.                 local u = cf.UpVector
  8340.                 local b = -cf.LookVector
  8341.                
  8342.                 local thickness = module.StyleGuide.CFrame.Thickness
  8343.                
  8344.                 local right = draw({
  8345.                         CFrame = CFrame.new(origin + r/2, origin + r);
  8346.                         Size = Vector3.new(thickness, thickness, r.Magnitude);
  8347.                         Color = module.StyleGuide.CFrame.RightColor3;
  8348.                         Parent = parent;
  8349.                 }, module.StyleGuide.CFrame.PartProperties)
  8350.                
  8351.                 local up = draw({
  8352.                         CFrame = CFrame.new(origin + u/2, origin + u);
  8353.                         Size = Vector3.new(thickness, thickness, r.Magnitude);
  8354.                         Color = module.StyleGuide.CFrame.UpColor3;
  8355.                         Parent = parent;
  8356.                 }, module.StyleGuide.CFrame.PartProperties)
  8357.                
  8358.                 local back = draw({
  8359.                         CFrame = CFrame.new(origin + b/2, origin + b);
  8360.                         Size = Vector3.new(thickness, thickness, u.Magnitude);
  8361.                         Color = module.StyleGuide.CFrame.BackColor3;
  8362.                         Parent = parent;
  8363.                 }, module.StyleGuide.CFrame.PartProperties)
  8364.                
  8365.                 return right, up, back
  8366.         end
  8367.        
  8368.         -- Return
  8369.        
  8370.         return module
  8371. end
  8372. function _Draw2D()
  8373.         local module = {}
  8374.        
  8375.         -- Style Guide
  8376.        
  8377.         module.StyleGuide = {
  8378.                 Point = {
  8379.                         BorderSizePixel = 0;
  8380.                         Size = UDim2.new(0, 4, 0, 4);
  8381.                         BorderColor3 = Color3.new(0, 0, 0);
  8382.                         BackgroundColor3 = Color3.new(0, 1, 0);
  8383.                 },
  8384.                
  8385.                 Line = {
  8386.                         Thickness = 1;
  8387.                         BorderSizePixel = 0;
  8388.                         BorderColor3 = Color3.new(0, 0, 0);
  8389.                         BackgroundColor3 = Color3.new(0, 1, 0);
  8390.                 },
  8391.                
  8392.                 Ray = {
  8393.                         Thickness = 1;
  8394.                         BorderSizePixel = 0;
  8395.                         BorderColor3 = Color3.new(0, 0, 0);
  8396.                         BackgroundColor3 = Color3.new(0, 1, 0);
  8397.                 },
  8398.                
  8399.                 Triangle = {
  8400.                         ImageTransparency = 0;
  8401.                         ImageColor3 = Color3.new(0, 1, 0);
  8402.                 }
  8403.         }
  8404.        
  8405.         -- CONSTANTS
  8406.        
  8407.         local HALF = Vector2.new(0.5, 0.5)
  8408.        
  8409.         local RIGHT = "rbxassetid://2798177521"
  8410.         local LEFT = "rbxassetid://2798177955"
  8411.        
  8412.         local IMG = Instance.new("ImageLabel")
  8413.         IMG.BackgroundTransparency = 1
  8414.         IMG.AnchorPoint = HALF
  8415.         IMG.BorderSizePixel = 0
  8416.        
  8417.         local FRAME = Instance.new("Frame")
  8418.         FRAME.BorderSizePixel = 0
  8419.         FRAME.Size = UDim2.new(0, 0, 0, 0)
  8420.         FRAME.BackgroundColor3 = Color3.new(1, 1, 1)
  8421.        
  8422.         -- Functions
  8423.        
  8424.         function draw(properties, style)
  8425.                 local frame = FRAME:Clone()
  8426.                 for k, v in next, properties do
  8427.                         frame[k] = v
  8428.                 end
  8429.                 if (style) then
  8430.                         for k, v in next, style do
  8431.                                 if (k ~= "Thickness") then
  8432.                                         frame[k] = v
  8433.                                 end
  8434.                         end
  8435.                 end
  8436.                 return frame
  8437.         end
  8438.        
  8439.         function module.Draw(parent, properties)
  8440.                 properties.Parent = parent
  8441.                 return draw(properties, nil)
  8442.         end
  8443.        
  8444.         function module.Point(parent, v2)
  8445.                 return draw({
  8446.                         AnchorPoint = HALF;
  8447.                         Position = UDim2.new(0, v2.x, 0, v2.y);
  8448.                         Parent = parent;
  8449.                 }, module.StyleGuide.Point)
  8450.         end
  8451.        
  8452.         function module.Line(parent, a, b)
  8453.                 local v = (b - a)
  8454.                 local m = (a + b)/2
  8455.                
  8456.                 return draw({
  8457.                         AnchorPoint = HALF;
  8458.                         Position = UDim2.new(0, m.x, 0, m.y);
  8459.                         Size = UDim2.new(0, module.StyleGuide.Line.Thickness, 0, v.magnitude);
  8460.                         Rotation = math.deg(math.atan2(v.y, v.x)) - 90;
  8461.                         BackgroundColor3 = Color3.new(1, 1, 0);
  8462.                         Parent = parent;
  8463.                 }, module.StyleGuide.Line)
  8464.         end
  8465.        
  8466.         function module.Ray(parent, origin, direction)
  8467.                 local a, b = origin, origin + direction
  8468.                 local v = (b - a)
  8469.                 local m = (a + b)/2
  8470.                
  8471.                 return draw({
  8472.                         AnchorPoint = HALF;
  8473.                         Position = UDim2.new(0, m.x, 0, m.y);
  8474.                         Size = UDim2.new(0, module.StyleGuide.Ray.Thickness, 0, v.magnitude);
  8475.                         Rotation = math.deg(math.atan2(v.y, v.x)) - 90;
  8476.                         Parent = parent;
  8477.                 }, module.StyleGuide.Ray)
  8478.         end
  8479.        
  8480.         function module.Triangle(parent, a, b, c)
  8481.                 local ab, ac, bc = b - a, c - a, c - b
  8482.                 local abd, acd, bcd = ab:Dot(ab), ac:Dot(ac), bc:Dot(bc)
  8483.                
  8484.                 if (abd > acd and abd > bcd) then
  8485.                         c, a = a, c
  8486.                 elseif (acd > bcd and acd > abd) then
  8487.                         a, b = b, a
  8488.                 end
  8489.                
  8490.                 ab, ac, bc = b - a, c - a, c - b
  8491.                
  8492.                 local unit = bc.unit
  8493.                 local height = unit:Cross(ab)
  8494.                 local flip = (height >= 0)
  8495.                 local theta = math.deg(math.atan2(unit.y, unit.x)) + (flip and 0 or 180)
  8496.                
  8497.                 local m1 = (a + b)/2
  8498.                 local m2 = (a + c)/2
  8499.                
  8500.                 local w1 = IMG:Clone()
  8501.                 w1.Image = flip and RIGHT or LEFT
  8502.                 w1.AnchorPoint = HALF
  8503.                 w1.Size = UDim2.new(0, math.abs(unit:Dot(ab)), 0, height)
  8504.                 w1.Position = UDim2.new(0, m1.x, 0, m1.y)
  8505.                 w1.Rotation = theta
  8506.                 w1.Parent = parent
  8507.                
  8508.                 local w2 = IMG:Clone()
  8509.                 w2.Image = flip and LEFT or RIGHT
  8510.                 w2.AnchorPoint = HALF
  8511.                 w2.Size = UDim2.new(0, math.abs(unit:Dot(ac)), 0, height)
  8512.                 w2.Position = UDim2.new(0, m2.x, 0, m2.y)
  8513.                 w2.Rotation = theta
  8514.                 w2.Parent = parent
  8515.                
  8516.                 for k, v in next, module.StyleGuide.Triangle do
  8517.                         w1[k] = v
  8518.                         w2[k] = v
  8519.                 end
  8520.                
  8521.                 return w1, w2
  8522.         end
  8523.        
  8524.         -- Return
  8525.        
  8526.         return module
  8527. end
  8528. function _DrawClass()
  8529.         local Draw2DModule = _Draw2D()
  8530.         local Draw3DModule = _Draw3D()
  8531.        
  8532.         --
  8533.        
  8534.         local DrawClass = {}
  8535.         local DrawClassStorage = setmetatable({}, {__mode = "k"})
  8536.         DrawClass.__index = DrawClass
  8537.        
  8538.         function DrawClass.new(parent)
  8539.                 local self = setmetatable({}, DrawClass)
  8540.                
  8541.                 self.Parent = parent
  8542.                 DrawClassStorage[self] = {}
  8543.                
  8544.                 self.Draw3D = {}
  8545.                 for key, func in next, Draw3DModule do
  8546.                         self.Draw3D[key] = function(...)
  8547.                                 local returns = {func(self.Parent, ...)}
  8548.                                 for i = 1, #returns do
  8549.                                         table.insert(DrawClassStorage[self], returns[i])
  8550.                                 end
  8551.                                 return unpack(returns)
  8552.                         end
  8553.                 end
  8554.                
  8555.                 self.Draw2D = {}
  8556.                 for key, func in next, Draw2DModule do
  8557.                         self.Draw2D[key] = function(...)
  8558.                                 local returns = {func(self.Parent, ...)}
  8559.                                 for i = 1, #returns do
  8560.                                         table.insert(DrawClassStorage[self], returns[i])
  8561.                                 end
  8562.                                 return unpack(returns)
  8563.                         end
  8564.                 end
  8565.                
  8566.                 return self
  8567.         end
  8568.        
  8569.         --
  8570.        
  8571.         function DrawClass:Clear()
  8572.                 local t = DrawClassStorage[self]
  8573.                 while (#t > 0) do
  8574.                         local part = table.remove(t)
  8575.                         if (part) then
  8576.                                 part:Destroy()
  8577.                         end
  8578.                 end
  8579.                 DrawClassStorage[self] = {}
  8580.         end
  8581.        
  8582.         --
  8583.        
  8584.         return DrawClass
  8585. end
  8586.  
  8587.  
  8588. --END TEST
  8589.  
  8590. local PLAYERS = game:GetService("Players")
  8591.  
  8592. local GravityController = _GravityController()
  8593. local Controller = GravityController.new(PLAYERS.LocalPlayer)
  8594.  
  8595. local DrawClass = _DrawClass()
  8596.  
  8597. local PI2 = math.pi*2
  8598. local ZERO = Vector3.new(0, 0, 0)
  8599.  
  8600. local LOWER_RADIUS_OFFSET = 3
  8601. local NUM_DOWN_RAYS = 24
  8602. local ODD_DOWN_RAY_START_RADIUS = 3    
  8603. local EVEN_DOWN_RAY_START_RADIUS = 2
  8604. local ODD_DOWN_RAY_END_RADIUS = 1.66666
  8605. local EVEN_DOWN_RAY_END_RADIUS = 1
  8606.  
  8607. local NUM_FEELER_RAYS = 9
  8608. local FEELER_LENGTH = 2
  8609. local FEELER_START_OFFSET = 2
  8610. local FEELER_RADIUS = 3.5
  8611. local FEELER_APEX_OFFSET = 1
  8612. local FEELER_WEIGHTING = 8
  8613.  
  8614. function GetGravityUp(self, oldGravityUp)
  8615.         local ignoreList = {}
  8616.         for i, player in next, PLAYERS:GetPlayers() do
  8617.                 ignoreList[i] = player.Character
  8618.         end
  8619.        
  8620.         -- get the normal
  8621.        
  8622.         local hrpCF = self.HRP.CFrame
  8623.         local isR15 = (self.Humanoid.RigType == Enum.HumanoidRigType.R15)
  8624.        
  8625.         local origin = isR15 and hrpCF.p or hrpCF.p + 0.35*oldGravityUp
  8626.         local radialVector = math.abs(hrpCF.LookVector:Dot(oldGravityUp)) < 0.999 and hrpCF.LookVector:Cross(oldGravityUp) or hrpCF.RightVector:Cross(oldGravityUp)
  8627.        
  8628.         local centerRayLength = 25
  8629.         local centerRay = Ray.new(origin, -centerRayLength * oldGravityUp)
  8630.         local centerHit, centerHitPoint, centerHitNormal = workspace:FindPartOnRayWithIgnoreList(centerRay, ignoreList)
  8631.        
  8632.         --[[disable
  8633.         DrawClass:Clear()
  8634.         DrawClass.Draw3D.Ray(centerRay.Origin, centerRay.Direction)
  8635.         ]]
  8636.         local downHitCount = 0
  8637.         local totalHitCount = 0
  8638.         local centerRayHitCount = 0
  8639.         local evenRayHitCount = 0
  8640.         local oddRayHitCount = 0
  8641.        
  8642.         local mainDownNormal = ZERO
  8643.         if (centerHit) then
  8644.                 mainDownNormal = centerHitNormal
  8645.                 centerRayHitCount = 0
  8646.         end
  8647.        
  8648.         local downRaySum = ZERO
  8649.         for i = 1, NUM_DOWN_RAYS do
  8650.                 local dtheta = PI2 * ((i-1)/NUM_DOWN_RAYS)
  8651.                
  8652.                 local angleWeight = 0.25 + 0.75 * math.abs(math.cos(dtheta))
  8653.                 local isEvenRay = (i%2 == 0)
  8654.                 local startRadius = isEvenRay and EVEN_DOWN_RAY_START_RADIUS or ODD_DOWN_RAY_START_RADIUS      
  8655.                 local endRadius = isEvenRay and EVEN_DOWN_RAY_END_RADIUS or ODD_DOWN_RAY_END_RADIUS
  8656.                 local downRayLength = centerRayLength
  8657.                
  8658.                 local offset = CFrame.fromAxisAngle(oldGravityUp, dtheta) * radialVector
  8659.                 local dir = (LOWER_RADIUS_OFFSET * -oldGravityUp + (endRadius - startRadius) * offset)
  8660.                 local ray = Ray.new(origin + startRadius * offset, downRayLength * dir.unit)
  8661.                 local hit, hitPoint, hitNormal = workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)
  8662.                 --[[disable
  8663.                 DrawClass.Draw3D.Ray(ray.Origin, ray.Direction)
  8664.                 ]]
  8665.                 if (hit) then
  8666.                         downRaySum = downRaySum + angleWeight * hitNormal
  8667.                         downHitCount = downHitCount + 1
  8668.                         if isEvenRay then
  8669.                                 evenRayHitCount = evenRayHitCount + 1                                  
  8670.                         else
  8671.                                 oddRayHitCount = oddRayHitCount + 1
  8672.                         end
  8673.                 end
  8674.         end
  8675.        
  8676.         local feelerHitCount = 0       
  8677.         local feelerNormalSum = ZERO
  8678.        
  8679.         for i = 1, NUM_FEELER_RAYS do
  8680.                 local dtheta = 2 * math.pi * ((i-1)/NUM_FEELER_RAYS)
  8681.                 local angleWeight =  0.25 + 0.75 * math.abs(math.cos(dtheta))  
  8682.                 local offset = CFrame.fromAxisAngle(oldGravityUp, dtheta) * radialVector
  8683.                 local dir = (FEELER_RADIUS * offset + LOWER_RADIUS_OFFSET * -oldGravityUp).unit
  8684.                 local feelerOrigin = origin - FEELER_APEX_OFFSET * -oldGravityUp + FEELER_START_OFFSET * dir
  8685.                 local ray = Ray.new(feelerOrigin, FEELER_LENGTH * dir)
  8686.                 local hit, hitPoint, hitNormal = workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)
  8687.                 --[[disable
  8688.                 DrawClass.Draw3D.Ray(ray.Origin, ray.Direction)
  8689.                 ]]
  8690.                 if (hit) then
  8691.                         feelerNormalSum = feelerNormalSum + FEELER_WEIGHTING * angleWeight * hitNormal --* hitDistSqInv
  8692.                         feelerHitCount = feelerHitCount + 1
  8693.                 end
  8694.         end
  8695.        
  8696.         if (centerRayHitCount + downHitCount + feelerHitCount > 0) then
  8697.                 local normalSum = mainDownNormal + downRaySum + feelerNormalSum
  8698.                 if (normalSum ~= ZERO) then
  8699.                         return normalSum.unit
  8700.                 end
  8701.         end
  8702.        
  8703.         return oldGravityUp
  8704. end
  8705.  
  8706. Controller.GetGravityUp = GetGravityUp
  8707.  
  8708. -- E is toggle
  8709. game:GetService("ContextActionService"):BindAction("Toggle", function(action, state, input)
  8710.         if not (state == Enum.UserInputState.Begin) then
  8711.                 return
  8712.         end
  8713.        
  8714.         if (Controller) then
  8715.                 Controller:Destroy()
  8716.                 Controller = nil
  8717.         else
  8718.                 Controller = GravityController.new(PLAYERS.LocalPlayer)
  8719.                 Controller.GetGravityUp = GetGravityUp
  8720.         end
  8721. end, false, Enum.KeyCode.Z)
  8722. print("end")



  • Recent Roblox Scripts