EzShiftlock - Quickly and easily toggle shift lock (even for mobile)

stop lol

Introduction

So again, I’ve needed this for one of my recent games but I also believe it’d be helpful to other people with similar goals. This module allows you to set whether or not a user’s shift lock is enabled, one of the main reasons I made this was so I could have a mobile shift lock option.

Before I go onto usage and other stuff, I’d like to credit people who contributed to it’s creation.

Usage

To use the system, all you need to do is insert the model and reparent the ‘PlayerScriptsLoader’ that comes with it to ‘StarterPlayerScripts’ and change the configurations to your likings.

In the main script there’s a configuration named ‘ShiftlockAttributeName’ and whatever you set it to is what will enable / disable shift lock for the client.

You can enable shift lock when installed and the ‘ShiftlockAttributeName’ is set to ‘Shiftlock’ with something like:

player:SetAttribute("Shiftlock",true)

It’s that easy!

Installation

  • You can get the model here.

If you’re too lazy to do all the installation steps you can run this code in the command bar to do that job for you.

-- Author: @Jumpathy
-- Usage: Installing EzShiftlock through the command bar

local start = tick()
local model = game:GetObjects("rbxassetid://8285701600")[1]
local init = model:WaitForChild("EzShiftlock")
local plugin = PluginManager():CreatePlugin()

init.Parent = game:GetService("ServerScriptService")
init:WaitForChild("PlayerScriptsLoader").Parent = game:GetService("StarterPlayer").StarterPlayerScripts

game:GetService("Selection"):Set({init})
plugin:OpenScript(init)

warn(("[Installed in %s]"):format(tick() - start))

Use-cases:

  • Mobile shift lock support
  • Extra shift lock keys
  • Needing to change shift lock in general
  • Some other weird reason

Polls

Would you use this?
  • Yes
  • No

0 voters

How helpful would this be to you if you did use it?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

0 voters

Notes

  • Best of all? You never need to fork the Camera module because I’m just that cool (jk thank you EgoMoose for fixing that Roblox update) but yea! You don’t need to change any code and you can just get started easily!
  • I’m aware this post is a bit vague, but there’s not a whole lot else than what’s outlined to it. I hope this can be helpful to the people who are needing something like this.
  • If you have any problems with the system or need help don’t hesitate to PM me or leave a reply!
28 Likes

Just wanted to say this looks amazing and I might use it in my upcoming game!
One question, does it for console players?

1 Like

Hey. It works perfectly except for mobile. On mobile it outputs [no mouse lock callback found].

3 Likes

That’s annoying, I can try doing debugs on it later but my phone won’t download Roblox.

1 Like

This is pretty cool. Is there a way to check if shiftlock is already on or off?

1 Like
player:GetAttribute("Shiftlock")
2 Likes

Please reply with your findings, thank you.

1 Like

EDIT: Fetch MouseLockController from the CameraModule at the top of the PlayerScriptsLoader script

local cameraModule = require(playerModule:WaitForChild("CameraModule"))

local MouseLockController = require(playerModule.CameraModule:WaitForChild("MouseLockController"))

Then tack this onto the end of the script, and it should work on mobile

---------------
-- Add in detection for TouchEnabled, as this is
-- how the CameraModule decides not to instantiate
-- a mouselockcontroller.
if (userInput.TouchEnabled) then
	cameraModule.activeMouseLockController = MouseLockController.new()
	local toggleEvent = cameraModule.activeMouseLockController:GetBindableToggleEvent()
	
	if toggleEvent then
		toggleEvent:Connect(function()
			cameraModule:OnMouseLockToggled()
		end)
	end
	
	userInput:GetPropertyChangedSignal("MouseBehavior"):Connect(function()
		-- in testing scenarios on studio, locking the mouse on mobile prevents user input.
		-- if this has any impact on functionality in your game, remove it
		userInput.MouseBehavior = Enum.MouseBehavior.Default
	end)
end
4 Likes

I don’t know if this is just a me problem but I made it in my game that pressing V enables third person and automatically sets the attribute to True, and when pressed again it sets the player to first person and disables the attribute. However, when another player does this and I try to enable third person, third person is enabled but shift lock is not (until I disable first person, and then reenable it again).

Code in LocalScript under StarterGui:

local uis = game:GetService("UserInputService")
local player = game:GetService("Players").LocalPlayer
local playergui = script.Parent.Parent
local mobilebutton = playergui:WaitForChild("MobileStuff"):WaitForChild("Frame").ToggleView

local human = player.Character:WaitForChild("Humanoid")
local teams = game:GetService("Teams")

local firstperson = true

function togglecamera()
	if player.CameraMode == Enum.CameraMode.LockFirstPerson then
		firstperson = false
		if player.Team == teams.Monsters then
			player.CameraMaxZoomDistance = 15
			player.CameraMinZoomDistance = 10
		elseif player.Team == teams.Players then
			player.CameraMaxZoomDistance = 5
			player.CameraMinZoomDistance = 5
		end
		player.CameraMode = Enum.CameraMode.Classic
		player:SetAttribute("Shiftlock",true)
	else
		firstperson = true
		player.CameraMinZoomDistance = .5
		player.CameraMaxZoomDistance = .5
		player.CameraMode = Enum.CameraMode.LockFirstPerson
		player:SetAttribute("Shiftlock",false)
	end
end

function resetcamera()
	if not firstperson then togglecamera() end
end

uis.InputBegan:Connect(function(input,gameProcessedEvent)
	if not gameProcessedEvent and human.Health > 0 and player.Team ~= teams.Idle and playergui:WaitForChild("A_Title").Enabled == false then
		if input.KeyCode == Enum.KeyCode.V then
			togglecamera()
		end
	end
end)

mobilebutton.MouseButton1Down:Connect(function()
	if human.Health > 0 then togglecamera() end
end)

player.CharacterAdded:Connect(function()
	resetcamera()
end)

human.Died:Connect(function()
	resetcamera()
end)

player.CharacterRemoving:Connect(function()
	resetcamera()
end)

TL;DR for me, another playing enabling Shiftlock via the attribute system makes it so the next player does not go into Shiftlock when it is supposed to. Any idea for why this might be?

2 Likes

Haven’t been able to replicate this in my testing, but the whole system is subject to randomly not working at moments from what I’ve experienced and I haven’t remedied that, either cuz I can’t narrow down the fail cases. Hopefully eventually roblox will just expose a better mouse lock control method in the PlayerModule, I don’t see why it’s not more accessible.
If this approach cannot do what you’re trying to do, there is a workaround, albeit hacky and maybe not the most stable. It works for now and never seems to fail.
Use UserInputService’s MouseBehavior property in conjunction with an update function and hook it to one of the events that runs after the core camera script updates (like RenderStepped), and offset by your desired CFrame from the Camera’s CFrame.
example:

local CameraDisplacement = Spring.new(Vector3.new(), 16, 1)
function toggleMouseLock(bool)
	if bool then
		CameraDisplacement.Target = Vector3.new(-5,0,0)
	else
		CameraDisplacement.Target = Vector3.new(0,0,0)
	end
end

function update()
	local displacementPos = CameraDisplacement.Position
	workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame
		*CFrame.new(displacementPos.X,displacementPos.Y,displacementPos.Z)
end

game:GetService("RunService").RenderStepped:Connect(update)

you’d probably want to expose this in a module

EDIT: note that this will not impact the core camera’s PopperCam detection, so your offset is capable of clipping into walls. Pretty sure you can fix this by requiring and calling PopperCam AGAIN in your update function, which I will choose not to do lol

2 Likes