Clients/Client2018/content/scripts/PlayerScripts/StarterPlayerScripts/ControlScript.lua

488 lines
17 KiB
Lua

--[[
// FileName: ControlScript.lua
// Version 1.1
// Written by: jmargh and jeditkacheff
// Description: Manages in game controls for both touch and keyboard/mouse devices.
// This script will be inserted into PlayerScripts under each player by default. If you want to
// create your own custom controls or modify these controls, you must place a script with this
// name, ControlScript, under StarterPlayer -> PlayerScripts.
// Required Modules:
ClickToMove
DPad
KeyboardMovement
Thumbpad
Thumbstick
TouchJump
MasterControl
VehicleController
--]]
--[[ Services ]]--
local ContextActionService = game:GetService('ContextActionService')
local Players = game:GetService('Players')
local UserInputService = game:GetService('UserInputService')
local VRService = game:GetService('VRService')
-- Settings and GameSettings are read only
local Settings = UserSettings()
local GameSettings = Settings.GameSettings
-- Issue with play solo? (F6)
while not UserInputService.KeyboardEnabled and not UserInputService.TouchEnabled and not UserInputService.GamepadEnabled do
wait()
end
--[[ Script Variables ]]--
while not Players.LocalPlayer do
wait()
end
local lastInputType = nil
local LocalPlayer = Players.LocalPlayer
local PlayerGui = LocalPlayer:WaitForChild('PlayerGui')
local IsTouchDevice = UserInputService.TouchEnabled
local UserMovementMode = IsTouchDevice and GameSettings.TouchMovementMode or GameSettings.ComputerMovementMode
local DevMovementMode = IsTouchDevice and LocalPlayer.DevTouchMovementMode or LocalPlayer.DevComputerMovementMode
local IsUserChoice = (IsTouchDevice and DevMovementMode == Enum.DevTouchMovementMode.UserChoice) or (DevMovementMode == Enum.DevComputerMovementMode.UserChoice)
local TouchGui = nil
local TouchControlFrame = nil
local IsModalEnabled = UserInputService.ModalEnabled
local BindableEvent_OnFailStateChanged = nil
local isJumpEnabled = false
-- register what control scripts we are using
do
local PlayerScripts = LocalPlayer:WaitForChild("PlayerScripts")
local canRegisterControls = pcall(function() PlayerScripts:RegisterTouchMovementMode(Enum.TouchMovementMode.Default) end)
if canRegisterControls then
PlayerScripts:RegisterTouchMovementMode(Enum.TouchMovementMode.Thumbstick)
PlayerScripts:RegisterTouchMovementMode(Enum.TouchMovementMode.DPad)
PlayerScripts:RegisterTouchMovementMode(Enum.TouchMovementMode.Thumbpad)
PlayerScripts:RegisterTouchMovementMode(Enum.TouchMovementMode.ClickToMove)
PlayerScripts:RegisterTouchMovementMode(Enum.TouchMovementMode.DynamicThumbstick)
PlayerScripts:RegisterComputerMovementMode(Enum.ComputerMovementMode.Default)
PlayerScripts:RegisterComputerMovementMode(Enum.ComputerMovementMode.KeyboardMouse)
PlayerScripts:RegisterComputerMovementMode(Enum.ComputerMovementMode.ClickToMove)
end
end
local DynamicThumbstickAvailable = pcall(function()
return Enum.DevTouchMovementMode.DynamicThumbstick and Enum.TouchMovementMode.DynamicThumbstick
end)
local FFlagUserNoCameraClickToMoveSuccess, FFlagUserNoCameraClickToMoveResult = pcall(function() return UserSettings():IsUserFeatureEnabled("UserNoCameraClickToMove") end)
local FFlagUserNoCameraClickToMove = FFlagUserNoCameraClickToMoveSuccess and FFlagUserNoCameraClickToMoveResult
--[[ Modules ]]--
local ClickToMoveTouchControls = nil
local ControlModules = {}
local ControlState = {}
ControlState.Current = nil
function ControlState:SwitchTo(newControl)
if ControlState.Current == newControl then return end
if ControlState.Current then
ControlState.Current:Disable()
end
ControlState.Current = newControl
if ControlState.Current then
ControlState.Current:Enable()
end
end
function ControlState:IsTouchJumpModuleUsed()
return isJumpEnabled
end
local MasterControl = require(script:WaitForChild('MasterControl'))
--MasterControl needs access to ControlState in order to be able to fully enable and disable control
MasterControl.ControlState = ControlState
local DynamicThumbstickModule = require(script.MasterControl:WaitForChild('DynamicThumbstick'))
local ThumbstickModule = require(script.MasterControl:WaitForChild('Thumbstick'))
local ThumbpadModule = require(script.MasterControl:WaitForChild('Thumbpad'))
local DPadModule = require(script.MasterControl:WaitForChild('DPad'))
local DefaultModule = ControlModules.Thumbstick
local TouchJumpModule = require(script.MasterControl:WaitForChild('TouchJump'))
local ClickToMoveModule = FFlagUserNoCameraClickToMove and require(script.MasterControl:WaitForChild('ClickToMoveController')) or nil
MasterControl.TouchJumpModule = TouchJumpModule
local VRNavigationModule = require(script.MasterControl:WaitForChild('VRNavigation'))
local keyboardModule = require(script.MasterControl:WaitForChild('KeyboardMovement'))
ControlModules.Gamepad = require(script.MasterControl:WaitForChild('Gamepad'))
function getTouchModule()
local module = nil
if not IsUserChoice then
if DynamicThumbstickAvailable and DevMovementMode == Enum.DevTouchMovementMode.DynamicThumbstick then
module = DynamicThumbstickModule
isJumpEnabled = true
elseif DevMovementMode == Enum.DevTouchMovementMode.Thumbstick then
module = ThumbstickModule
isJumpEnabled = true
elseif DevMovementMode == Enum.DevTouchMovementMode.Thumbpad then
module = ThumbpadModule
isJumpEnabled = true
elseif DevMovementMode == Enum.DevTouchMovementMode.DPad then
module = DPadModule
isJumpEnabled = false
elseif DevMovementMode == Enum.DevTouchMovementMode.ClickToMove then
if FFlagUserNoCameraClickToMove then
module = ClickToMoveModule
isJumpEnabled = false -- TODO: What should this be, true or false?
else
module = nil
end
elseif DevMovementMode == Enum.DevTouchMovementMode.Scriptable then
module = nil
end
else
if DynamicThumbstickAvailable and UserMovementMode == Enum.TouchMovementMode.DynamicThumbstick then
module = DynamicThumbstickModule
isJumpEnabled = true
elseif UserMovementMode == Enum.TouchMovementMode.Default or UserMovementMode == Enum.TouchMovementMode.Thumbstick then
module = ThumbstickModule
isJumpEnabled = true
elseif UserMovementMode == Enum.TouchMovementMode.Thumbpad then
module = ThumbpadModule
isJumpEnabled = true
elseif UserMovementMode == Enum.TouchMovementMode.DPad then
module = DPadModule
isJumpEnabled = false
elseif UserMovementMode == Enum.TouchMovementMode.ClickToMove then
if FFlagUserNoCameraClickToMove then
module = ClickToMoveModule
isJumpEnabled = false -- TODO: What should this be, true or false?
else
module = nil
end
end
end
return module
end
function setJumpModule(isEnabled)
if not isEnabled then
TouchJumpModule:Disable()
elseif ControlState.Current == ControlModules.Touch then
TouchJumpModule:Enable()
end
end
function setClickToMove()
if DevMovementMode == Enum.DevTouchMovementMode.ClickToMove or DevMovementMode == Enum.DevComputerMovementMode.ClickToMove or
UserMovementMode == Enum.ComputerMovementMode.ClickToMove or UserMovementMode == Enum.TouchMovementMode.ClickToMove then
if lastInputType == Enum.UserInputType.Touch then
ClickToMoveTouchControls = ControlState.Current
end
elseif ClickToMoveTouchControls then
ClickToMoveTouchControls:Disable()
ClickToMoveTouchControls = nil
end
end
ControlModules.Touch = {}
ControlModules.Touch.Current = nil
ControlModules.Touch.LocalPlayerChangedCon = nil
ControlModules.Touch.GameSettingsChangedCon = nil
function ControlModules.Touch:RefreshControlStyle()
if ControlModules.Touch.Current then
ControlModules.Touch.Current:Disable()
end
setJumpModule(false)
TouchJumpModule:Disable()
ControlModules.Touch:Enable()
end
function ControlModules.Touch:DisconnectEvents()
if ControlModules.Touch.LocalPlayerChangedCon then
ControlModules.Touch.LocalPlayerChangedCon:disconnect()
ControlModules.Touch.LocalPlayerChangedCon = nil
end
if ControlModules.Touch.GameSettingsChangedCon then
ControlModules.Touch.GameSettingsChangedCon:disconnect()
ControlModules.Touch.GameSettingsChangedCon = nil
end
end
function ControlModules.Touch:Enable()
DevMovementMode = LocalPlayer.DevTouchMovementMode
IsUserChoice = DevMovementMode == Enum.DevTouchMovementMode.UserChoice
if IsUserChoice then
UserMovementMode = GameSettings.TouchMovementMode
end
local newModuleToEnable = getTouchModule()
if newModuleToEnable then
setClickToMove()
setJumpModule(isJumpEnabled)
newModuleToEnable:Enable()
ControlModules.Touch.Current = newModuleToEnable
if isJumpEnabled then TouchJumpModule:Enable() end
end
-- This being within the above if statement was causing issues with ClickToMove, which isn't a module within this script.
ControlModules.Touch:DisconnectEvents()
ControlModules.Touch.LocalPlayerChangedCon = LocalPlayer:GetPropertyChangedSignal("DevTouchMovementMode"):connect(function()
ControlModules.Touch:RefreshControlStyle()
end)
ControlModules.Touch.GameSettingsChangedCon = GameSettings:GetPropertyChangedSignal("TouchMovementMode"):connect(function()
ControlModules.Touch:RefreshControlStyle()
end)
end
function ControlModules.Touch:Disable()
ControlModules.Touch:DisconnectEvents()
local newModuleToDisable = getTouchModule()
if newModuleToDisable == ThumbstickModule or
newModuleToDisable == DPadModule or
newModuleToDisable == ThumbpadModule or
newModuleToDisable == DynamicThumbstickModule then
newModuleToDisable:Disable()
setJumpModule(false)
TouchJumpModule:Disable()
end
-- UserMovementMode will still have the previous value at this point
if FFlagUserNoCameraClickToMove and UserMovementMode == Enum.ComputerMovementMode.ClickToMove then
ClickToMoveModule:Disable()
end
end
local function getKeyboardModule()
-- NOTE: Click to move still uses keyboard. Leaving cases in case this ever changes.
local whichModule = nil
if not IsUserChoice then
if DevMovementMode == Enum.DevComputerMovementMode.KeyboardMouse then
whichModule = keyboardModule
elseif DevMovementMode == Enum.DevComputerMovementMode.ClickToMove then
whichModule = keyboardModule
end
else
if UserMovementMode == Enum.ComputerMovementMode.KeyboardMouse or UserMovementMode == Enum.ComputerMovementMode.Default then
whichModule = keyboardModule
elseif UserMovementMode == Enum.ComputerMovementMode.ClickToMove then
whichModule = keyboardModule
end
end
return whichModule
end
ControlModules.Keyboard = {}
function ControlModules.Keyboard:RefreshControlStyle()
ControlModules.Keyboard:Disable()
ControlModules.Keyboard:Enable()
end
function ControlModules.Keyboard:Enable()
DevMovementMode = LocalPlayer.DevComputerMovementMode
IsUserChoice = DevMovementMode == Enum.DevComputerMovementMode.UserChoice
if IsUserChoice then
UserMovementMode = GameSettings.ComputerMovementMode
end
local newModuleToEnable = getKeyboardModule()
if newModuleToEnable then
newModuleToEnable:Enable()
end
if FFlagUserNoCameraClickToMove and UserMovementMode == Enum.ComputerMovementMode.ClickToMove then
ClickToMoveModule:Enable()
end
ControlModules.Keyboard:DisconnectEvents()
ControlModules.Keyboard.LocalPlayerChangedCon = LocalPlayer.Changed:connect(function(property)
if property == 'DevComputerMovementMode' then
ControlModules.Keyboard:RefreshControlStyle()
end
end)
ControlModules.Keyboard.GameSettingsChangedCon = GameSettings.Changed:connect(function(property)
if property == 'ComputerMovementMode' then
ControlModules.Keyboard:RefreshControlStyle()
end
end)
end
function ControlModules.Keyboard:DisconnectEvents()
if ControlModules.Keyboard.LocalPlayerChangedCon then
ControlModules.Keyboard.LocalPlayerChangedCon:disconnect()
ControlModules.Keyboard.LocalPlayerChangedCon = nil
end
if ControlModules.Keyboard.GameSettingsChangedCon then
ControlModules.Keyboard.GameSettingsChangedCon:disconnect()
ControlModules.Keyboard.GameSettingsChangedCon = nil
end
end
function ControlModules.Keyboard:Disable()
ControlModules.Keyboard:DisconnectEvents()
local newModuleToDisable = getKeyboardModule()
if newModuleToDisable then
newModuleToDisable:Disable()
end
-- UserMovementMode will still be set to previous movement type
if FFlagUserNoCameraClickToMove and UserMovementMode == Enum.ComputerMovementMode.ClickToMove then
ClickToMoveModule:Disable()
end
end
ControlModules.VRNavigation = {}
function ControlModules.VRNavigation:Enable()
VRNavigationModule:Enable()
end
function ControlModules.VRNavigation:Disable()
VRNavigationModule:Disable()
end
if not FFlagUserNoCameraClickToMove and IsTouchDevice then
BindableEvent_OnFailStateChanged = script.Parent:WaitForChild("OnClickToMoveFailStateChange")
end
-- not used, but needs to be required
local VehicleController = require(script.MasterControl:WaitForChild('VehicleController'))
--[[ Initialization/Setup ]]--
local function createTouchGuiContainer()
if TouchGui then TouchGui:Destroy() end
-- Container for all touch device guis
TouchGui = Instance.new('ScreenGui')
TouchGui.Name = "TouchGui"
TouchGui.ResetOnSpawn = false
TouchGui.Parent = PlayerGui
TouchControlFrame = Instance.new('Frame')
TouchControlFrame.Name = "TouchControlFrame"
TouchControlFrame.Size = UDim2.new(1, 0, 1, 0)
TouchControlFrame.BackgroundTransparency = 1
TouchControlFrame.Parent = TouchGui
ThumbstickModule:Create(TouchControlFrame)
DPadModule:Create(TouchControlFrame)
ThumbpadModule:Create(TouchControlFrame)
TouchJumpModule:Create(TouchControlFrame)
DynamicThumbstickModule:Create(TouchControlFrame)
end
--[[ Settings Changed Connections ]]--
LocalPlayer.Changed:connect(function(property)
if lastInputType == Enum.UserInputType.Touch and property == 'DevTouchMovementMode' then
ControlState:SwitchTo(ControlModules.Touch)
elseif UserInputService.KeyboardEnabled and property == 'DevComputerMovementMode' then
ControlState:SwitchTo(ControlModules.Keyboard)
end
end)
GameSettings.Changed:connect(function(property)
if not IsUserChoice then return end
if property == 'TouchMovementMode' or property == 'ComputerMovementMode' then
UserMovementMode = GameSettings[property]
if property == 'TouchMovementMode' then
ControlState:SwitchTo(ControlModules.Touch)
elseif property == 'ComputerMovementMode' then
ControlState:SwitchTo(ControlModules.Keyboard)
end
end
end)
--[[ Touch Events ]]--
UserInputService.Changed:connect(function(property)
if property == 'ModalEnabled' then
IsModalEnabled = UserInputService.ModalEnabled
if lastInputType == Enum.UserInputType.Touch then
if ControlState.Current == ControlModules.Touch and IsModalEnabled then
ControlState:SwitchTo(nil)
elseif ControlState.Current == nil and not IsModalEnabled then
ControlState:SwitchTo(ControlModules.Touch)
end
end
end
end)
if FFlagUserNoCameraClickToMove then
BindableEvent_OnFailStateChanged = MasterControl:GetClickToMoveFailStateChanged()
end
if BindableEvent_OnFailStateChanged then
BindableEvent_OnFailStateChanged.Event:connect(function(isOn)
if lastInputType == Enum.UserInputType.Touch and ClickToMoveTouchControls then
if isOn then
ControlState:SwitchTo(ClickToMoveTouchControls)
else
ControlState:SwitchTo(nil)
end
end
end)
end
local switchToInputType = function(newLastInputType)
lastInputType = newLastInputType
if VRService.VREnabled then
ControlState:SwitchTo(ControlModules.VRNavigation)
return
end
if lastInputType == Enum.UserInputType.Touch then
ControlState:SwitchTo(ControlModules.Touch)
elseif lastInputType == Enum.UserInputType.Keyboard or
lastInputType == Enum.UserInputType.MouseButton1 or
lastInputType == Enum.UserInputType.MouseButton2 or
lastInputType == Enum.UserInputType.MouseButton3 or
lastInputType == Enum.UserInputType.MouseWheel or
lastInputType == Enum.UserInputType.MouseMovement then
ControlState:SwitchTo(ControlModules.Keyboard)
elseif lastInputType == Enum.UserInputType.Gamepad1 or
lastInputType == Enum.UserInputType.Gamepad2 or
lastInputType == Enum.UserInputType.Gamepad3 or
lastInputType == Enum.UserInputType.Gamepad4 then
ControlState:SwitchTo(ControlModules.Gamepad)
end
end
if IsTouchDevice then
createTouchGuiContainer()
end
MasterControl:Init()
UserInputService.GamepadDisconnected:connect(function(gamepadEnum)
local connectedGamepads = UserInputService:GetConnectedGamepads()
if #connectedGamepads > 0 then return end
if not VRService.VREnabled then
if UserInputService.KeyboardEnabled then
ControlState:SwitchTo(ControlModules.Keyboard)
elseif IsTouchDevice then
ControlState:SwitchTo(ControlModules.Touch)
end
end
end)
UserInputService.GamepadConnected:connect(function(gamepadEnum)
if not VRService.VREnabled then
ControlState:SwitchTo(ControlModules.Gamepad)
end
end)
switchToInputType(UserInputService:GetLastInputType())
UserInputService.LastInputTypeChanged:connect(switchToInputType)
VRService:GetPropertyChangedSignal("VREnabled"):Connect(function()
if VRService.VREnabled then
ControlState:SwitchTo(ControlModules.VRNavigation)
end
end)