Clients/Client2018/content/scripts/PlayerScripts/StarterPlayerScripts_NewStr.../RobloxPlayerScript/ControlScript.lua

329 lines
11 KiB
Lua

--[[
ControlScript - This module manages the selection of the current character control module
and calls update() on the active module on RenderStepped
2018 PlayerScripts Update - AllYourBlox
--]]
local ControlScript = {}
--[[ Roblox Services ]]--
local a = shared
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Settings = UserSettings()
local GameSettings = Settings.GameSettings
local activeControlModule = nil -- Used to prevent unnecessarily expensive checks on each input event
local activeController = nil
local touchJumpController = nil
local moveFunction = Players.LocalPlayer.Move
local humanoid = nil
local lastInputType = Enum.UserInputType.None
local cameraRelative = true
-- For Roblox VehicleController
local humanoidSeatedConn = nil
local vehicleController = nil
local touchControlFrame = nil
-- Modules - each returns a new() constructor function used to create controllers as needed
local Keyboard = require(script:WaitForChild("Keyboard"))
local Gamepad = require(script:WaitForChild("Gamepad"))
local TouchDPad = require(script:WaitForChild("TouchDPad"))
local DynamicThumbstick = require(script:WaitForChild("DynamicThumbstick"))
-- These controllers handle only walk/run movement, jumping is handled by the
-- TouchJump controller if any of these are active
local ClickToMove = require(script:WaitForChild("ClickToMoveController"))
local TouchThumbstick = require(script:WaitForChild("TouchThumbstick"))
local TouchThumbpad = require(script:WaitForChild("TouchThumbpad"))
local TouchJump = require(script:WaitForChild("TouchJump"))
-- Old control script notes that this must be required but is not used like a control module?
local VehicleController = require(script:WaitForChild("VehicleController"))
-- The Modules above are used to construct controller instances as-needed, and this
-- table is a map from Module to the instance created from it
local controllers = {}
-- Mapping from movement mode and lastInputType enum values to control modules to avoid huge if elseif switching
local movementEnumToModuleMap = {
[Enum.TouchMovementMode.DPad] = TouchDPad,
[Enum.DevTouchMovementMode.DPad] = TouchDPad,
[Enum.TouchMovementMode.Thumbpad] = TouchThumbpad,
[Enum.DevTouchMovementMode.Thumbpad] = TouchThumbpad,
[Enum.TouchMovementMode.Thumbstick] = TouchThumbstick,
[Enum.DevTouchMovementMode.Thumbstick] = TouchThumbstick,
[Enum.TouchMovementMode.DynamicThumbstick] = DynamicThumbstick,
[Enum.DevTouchMovementMode.DynamicThumbstick] = DynamicThumbstick,
[Enum.TouchMovementMode.ClickToMove] = ClickToMove,
[Enum.DevTouchMovementMode.ClickToMove] = ClickToMove,
-- Current default
[Enum.TouchMovementMode.Default] = TouchThumbstick,
[Enum.ComputerMovementMode.Default] = Keyboard,
[Enum.ComputerMovementMode.KeyboardMouse] = Keyboard,
[Enum.DevComputerMovementMode.KeyboardMouse] = Keyboard,
[Enum.DevComputerMovementMode.Scriptable] = nil,
[Enum.ComputerMovementMode.ClickToMove] = ClickToMove,
[Enum.DevComputerMovementMode.ClickToMove] = ClickToMove,
}
-- Keyboard controller is really keyboard and mouse controller
local computerInputTypeToModuleMap = {
[Enum.UserInputType.Keyboard] = Keyboard,
[Enum.UserInputType.MouseButton1] = Keyboard,
[Enum.UserInputType.MouseButton2] = Keyboard,
[Enum.UserInputType.MouseButton3] = Keyboard,
[Enum.UserInputType.MouseWheel] = Keyboard,
[Enum.UserInputType.MouseMovement] = Keyboard,
[Enum.UserInputType.Gamepad1] = Gamepad,
[Enum.UserInputType.Gamepad2] = Gamepad,
[Enum.UserInputType.Gamepad3] = Gamepad,
[Enum.UserInputType.Gamepad4] = Gamepad,
}
-- Returns module (possibly nil) and success code to differentiate returning nil due to error vs Scriptable
local function SelectComputerMovementModule()
if not (UserInputService.KeyboardEnabled or UserInputService.GamepadEnabled) then
return nil, false
end
local computerModule = nil
local DevMovementMode = Players.LocalPlayer.DevComputerMovementMode
if DevMovementMode == Enum.DevComputerMovementMode.UserChoice then
computerModule = computerInputTypeToModuleMap[lastInputType]
if not computerModule then
computerModule = movementEnumToModuleMap[GameSettings.ComputerMovementMode]
end
elseif DevMovementMode == Enum.DevComputerMovementMode.Scriptable then
return nil, true
elseif DevMovementMode == Enum.DevComputerMovementMode.ClickToMove then
computerModule = ClickToMove
else
computerModule = computerInputTypeToModuleMap[lastInputType]
if not computerModule then
computerModule = movementEnumToModuleMap[DevMovementMode]
end
end
return computerModule, true
end
-- Choose current Touch control module based on settings (user, dev)
-- Returns module (possibly nil) and success code to differentiate returning nil due to error vs Scriptable
local function SelectTouchModule()
if not UserInputService.TouchEnabled then
return nil, false
end
local touchModule = nil
local DevMovementMode = Players.LocalPlayer.DevTouchMovementMode
if DevMovementMode == Enum.DevTouchMovementMode.UserChoice then
touchModule = movementEnumToModuleMap[GameSettings.TouchMovementMode]
elseif DevMovementMode == Enum.DevTouchMovementMode.Scriptable then
return nil, true
else
touchModule = movementEnumToModuleMap[DevMovementMode]
end
return touchModule, true
end
local function OnRenderStepped()
if activeController and activeController.enabled and humanoid then
local moveVector = activeController:GetMoveVector()
local vehicleConsumedInput = false
if vehicleController then
moveVector, vehicleConsumedInput = vehicleController:Update(moveVector, activeControlModule==Gamepad)
end
-- User of vehicleConsumedInput is commented out to preserve legacy behavior, in case some game relies on Humanoid.MoveDirection still being set while in a VehicleSeat
--if not vehicleConsumedInput then
moveFunction(Players.LocalPlayer, moveVector, cameraRelative)
--end
humanoid.Jump = activeController:GetIsJumping() or (touchJumpController and touchJumpController:GetIsJumping())
end
end
local function OnHumanoidSeated(active, currentSeatPart)
if active then
if currentSeatPart and currentSeatPart:IsA("VehicleSeat") then
if not vehicleController then
vehicleController = VehicleController.new()
end
vehicleController:Enable(true, currentSeatPart)
end
else
if vehicleController then
vehicleController:Enable(false, currentSeatPart)
end
end
end
local function OnCharacterAdded(char)
humanoid = char:FindFirstChildOfClass("Humanoid")
while not humanoid do
char.ChildAdded:wait()
humanoid = char:FindFirstChildOfClass("Humanoid")
end
if humanoidSeatedConn then
humanoidSeatedConn:Disconnect()
humanoidSeatedConn = nil
end
humanoidSeatedConn = humanoid.Seated:connect(OnHumanoidSeated)
end
local function OnCharacterRemoving(char)
humanoid = nil
end
-- Helper function to lazily instantiate a controller if it does not yet exist,
-- disable the active controller if it is different from the on being switched to,
-- and then enable the requested controller. The argument to this function must be
-- a reference to one of the control modules, i.e. Keyboard, Gamepad, etc.
local function SwitchToController(controlModule)
if not controlModule then
if activeController then
activeController:Enable(false)
end
activeController = nil
activeControlModule = nil
else
if not controllers[controlModule] then
controllers[controlModule] = controlModule.new()
end
if activeController ~= controllers[controlModule] then
if activeController then
activeController:Enable(false)
end
activeController = controllers[controlModule]
activeControlModule = controlModule -- Only used to check if controller switch is necessary
if touchControlFrame then
activeController:Enable(true, touchControlFrame)
else
activeController:Enable(true)
end
if touchControlFrame and (activeControlModule == TouchThumbpad
or activeControlModule == TouchThumbstick
or activeControlModule == ClickToMove
or activeControlModule == DynamicThumbstick) then
touchJumpController = controllers[TouchJump]
if not touchJumpController then
touchJumpController = TouchJump.new()
end
touchJumpController:Enable(true, touchControlFrame)
else
if touchJumpController then
touchJumpController:Enable(false)
end
end
end
end
end
local function OnLastInputTypeChanged(newLastInputType)
if lastInputType == newLastInputType then
warn("LastInputType Change listener called with current type.")
end
lastInputType = newLastInputType
if lastInputType == Enum.UserInputType.Touch then
-- TODO: Check if touch module already active
local touchModule, success = SelectTouchModule()
if success then
while not touchControlFrame do
wait()
end
SwitchToController(touchModule)
end
else
local computerModule = computerInputTypeToModuleMap[lastInputType]
if computerModule then
SwitchToController(computerModule)
end
end
end
-- Called when any relevant values of GameSettings or LocalPlayer change, forcing re-evalulation of
-- current control scheme
local function OnComputerMovementModeChange()
local controlModule, success = SelectComputerMovementModule()
if success then
SwitchToController(controlModule)
end
end
local function OnTouchMovementModeChange()
local touchModule, success = SelectTouchModule()
if success then
while not touchControlFrame do
wait()
end
SwitchToController(touchModule)
end
end
Players.LocalPlayer.CharacterAdded:Connect(OnCharacterAdded)
Players.LocalPlayer.CharacterRemoving:Connect(OnCharacterRemoving)
if Players.LocalPlayer.Character then
OnCharacterAdded(Players.LocalPlayer.Character)
end
RunService:BindToRenderStep("ControlScriptRenderstep", Enum.RenderPriority.Input.Value, OnRenderStepped)
UserInputService.LastInputTypeChanged:Connect(OnLastInputTypeChanged)
local propertyChangeListeners = {
GameSettings:GetPropertyChangedSignal("TouchMovementMode"):Connect(OnTouchMovementModeChange),
Players.LocalPlayer:GetPropertyChangedSignal("DevTouchMovementMode"):Connect(OnTouchMovementModeChange),
GameSettings:GetPropertyChangedSignal("ComputerMovementMode"):Connect(OnComputerMovementModeChange),
Players.LocalPlayer:GetPropertyChangedSignal("DevComputerMovementMode"):Connect(OnComputerMovementModeChange),
}
--[[ Touch Device UI ]]--
local PlayerGui = nil
local touchGui = nil
local playerGuiAddedConn = nil
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
touchControlFrame = Instance.new("Frame")
touchControlFrame.Name = "TouchControlFrame"
touchControlFrame.Size = UDim2.new(1, 0, 1, 0)
touchControlFrame.BackgroundTransparency = 1
touchControlFrame.Parent = touchGui
touchGui.Parent = PlayerGui
end
if UserInputService.TouchEnabled then
PlayerGui = Players.LocalPlayer:FindFirstChildOfClass("PlayerGui")
if PlayerGui then
createTouchGuiContainer()
OnLastInputTypeChanged(UserInputService:GetLastInputType())
else
playerGuiAddedConn = Players.LocalPlayer.ChildAdded:Connect(function(child)
if child:IsA("PlayerGui") then
PlayerGui = child
createTouchGuiContainer()
playerGuiAddedConn:Disconnect()
playerGuiAddedConn = nil
OnLastInputTypeChanged(UserInputService:GetLastInputType())
end
end)
end
end
return ControlScript