Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

Script not working properly with FilteringEnabled?

Asked by 7 years ago

Alright so I have a feature that allows players to noclip in my game when they press V. I converted it to FilteringEnabled since it wasn't updating the position properly. Now it does update the position of the player properly but noclipping is very laggy and the screen seems like it's having a seizure. Here are the scripts that are involved in this. Any possible answers as to why this happens?

ServerScriptService:

local ev = game.ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("GoGhost")
ev.OnServerEvent:connect(function(plr,mode,opt)
    if mode == 0 then
        plr.Character.HumanoidRootPart.Anchored = true
        plr.Character.Humanoid.PlatformStand = true
    elseif mode == 1 then
        plr.Character.HumanoidRootPart.Anchored = false
        plr.Character.HumanoidRootPart.Velocity = Vector3.new()
        plr.Character.Humanoid.PlatformStand = false
    elseif mode == 2 then
        plr.Character.HumanoidRootPart.CFrame = opt
    end
end)

StarterGui:

local player = game.Players.LocalPlayer
local selected = false
local XboxPos = Vector3.new(0,0,0)
local c = workspace.CurrentCamera
local userInput = game:GetService("UserInputService")
local rs = game:GetService("RunService")
local starterPlayer = game:GetService("StarterPlayer")
local speed = 60
local lastUpdate = 0 
local ev = game.ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("GoGhost")

function getNextMovement(deltaTime)
    local nextMove = Vector3.new()
    -- Left/Right
        if userInput:IsKeyDown("A") or userInput:IsKeyDown("Left") then
            nextMove = Vector3.new(-1,0,0)
        elseif userInput:IsKeyDown("D") or userInput:IsKeyDown("Right") then
            nextMove = Vector3.new(1,0,0)
        end
    -- Forward/Back
        if userInput:IsKeyDown("W") or userInput:IsKeyDown("Up") then
            nextMove = nextMove + Vector3.new(0,0,-1)
        elseif userInput:IsKeyDown("S") or userInput:IsKeyDown("Down") then
            nextMove = nextMove + Vector3.new(0,0,1)
        end
    -- Up/Down
        if userInput:IsKeyDown("Space") then
            nextMove = nextMove + Vector3.new(0,1,0)
        elseif userInput:IsKeyDown("LeftControl") then
            nextMove = nextMove + Vector3.new(0,-1,0)
        end
        nextMove = nextMove + XboxPos
    return CFrame.new( nextMove * (speed * deltaTime) )
end

function onSelected()
local char = player.Character
    if char then
        local humanoid = char:WaitForChild("Humanoid")
        local root = char:WaitForChild("HumanoidRootPart")
        currentPos = root.Position
        selected = true
        ev:FireServer(0)
        lastUpdate = tick()
        while selected do
            wait()
            local delta = tick()-lastUpdate
            local look = (c.Focus.p-c.CoordinateFrame.p).unit
            local move = getNextMovement(delta)
            local pos = root.Position
            ev:FireServer(2,CFrame.new(pos,pos+look) * move)
            lastUpdate = tick()
        end
        ev:FireServer(1)
    end
end

game:GetService("UserInputService").InputBegan:connect(function(input,event)
    if event then return end
    if input.KeyCode == Enum.KeyCode.ButtonB or input.KeyCode == Enum.KeyCode.V then
        if (selected == false) then
            selected = true
            onSelected()
        elseif (selected == true) then
            selected = false
        end
    end
end)

2 answers

Log in to vote
0
Answered by 7 years ago
Edited 7 years ago

Ok, after a lot of playing around i've come up with a workable solution. It seems to be the case that CFraming your character locally and even moving it locally with a BodyPosition replicate to the server just fine even with filtering enabled on. This seems weird to me and an easy vector for exploit, but it does make creating the functionality you want fairly easy. It isn't exactly like the code you had posted, as you can't look up or down to move up/down - you have to use space/left ctrl, but adding that functionality introduced other problems so I thought it was better this way. The character is also playing the falling animation when no clip is active, but you can always add to the code below to play a custom animation if it is important to you.

This should be in a local script in StarterPlayerScripts. It handles input, messaging the server to turn on/off collision, the BodyPosition that controls hovering, and I also rotate the character in a renderstep that runs after camera update to get smooth rotations. I have commented the two variables you can change here to control noclip speed.

local UserInputService = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local MasterControl = require(player:WaitForChild("PlayerScripts"):WaitForChild("ControlScript"):WaitForChild("MasterControl"))
local noClipEvent = game.ReplicatedStorage:WaitForChild("NoClipEvent")
local isNoClipActive = false
local isSpaceHeld = false
local isCtrlHeld = false
local hoverHeight
local lastUpdate

local bodyPosition = Instance.new("BodyPosition")
bodyPosition.Name = "NoClipBodyPosition"
bodyPosition.MaxForce = Vector3.new(500000000, 500000000, 500000000)
bodyPosition.D = 400

-- These two variables will change the noclip horizontal and vertical speeds respectively
local noClipSpeed = 40
local hoverIncrementSpeed = 1

UserInputService.InputBegan:connect(function(input, event)
    if not event then
        if input.KeyCode == Enum.KeyCode.ButtonB or input.KeyCode == Enum.KeyCode.V then
            if player.Character and player.Character.Parent then
                lastUpdate = tick()
                isNoClipActive = not isNoClipActive
                noClipEvent:FireServer(isNoClipActive)
                MasterControl:SetNoClip(isNoClipActive, noClipSpeed)

                if isNoClipActive then
                    local root = player.Character:FindFirstChild("HumanoidRootPart")
                    if root then
                        bodyPosition.Parent = player.Character.HumanoidRootPart
                        bodyPosition.Position = root.Position
                        hoverHeight = root.Position.Y
                    end
                else
                    bodyPosition.Parent = nil
                end
            end
        end
        if input.KeyCode == Enum.KeyCode.Space then
            isSpaceHeld = true
        end
        if input.KeyCode == Enum.KeyCode.LeftControl then
            isCtrlHeld = true
        end
    end
end)

UserInputService.InputEnded:connect(function(input, event)
    if not event then
        if input.KeyCode == Enum.KeyCode.Space then
            isSpaceHeld = false
        end
        if input.KeyCode == Enum.KeyCode.LeftControl then
            isCtrlHeld = false
        end
    end
end)

game:GetService("RunService"):BindToRenderStep("updateLoop", Enum.RenderPriority.Camera.Value + 1, function()
    if isNoClipActive and player.Character and player.Character.Parent then
        local root = player.Character:FindFirstChild("HumanoidRootPart")
        if root then
            local cam = workspace.CurrentCamera
            local camForward = cam.CFrame.lookVector
            camForward = Vector3.new(camForward.X, 0, camForward.Z).Unit
            root.CFrame = CFrame.new(root.CFrame.p, root.CFrame.p + camForward)

            if isSpaceHeld then
                hoverHeight = hoverHeight + hoverIncrementSpeed
            end
            if isCtrlHeld then
                hoverHeight = hoverHeight - hoverIncrementSpeed
            end
            if bodyPosition.Parent then
                bodyPosition.Position = Vector3.new(root.CFrame.p.X, hoverHeight, root.CFrame.p.Z)
            end
        end
    end
end)

This is a server script that should be in ServerScriptService. It's job is to toggle player collision on/off when it receives a message from the local script.

local PhysicsService = game:GetService("PhysicsService")
local Players = game:GetService("Players")

local noClipEvent = Instance.new("RemoteEvent")
noClipEvent.Name = "NoClipEvent"
noClipEvent.Parent = game.ReplicatedStorage

local noClipPlayers = "Players"
PhysicsService:CreateCollisionGroup(noClipPlayers)
PhysicsService:CollisionGroupSetCollidable("Default", noClipPlayers, false)

local function setCollisionGroupRecursive(object, groupName)
    if object:IsA("BasePart") then
        PhysicsService:SetPartCollisionGroup(object, groupName)
    end
    for _, child in ipairs(object:GetChildren()) do
        setCollisionGroupRecursive(child, groupName)
    end
end

noClipEvent.OnServerEvent:connect(function(player, isNoClipActive)
    local character = player.Character
    if character then
        if isNoClipActive then
            setCollisionGroupRecursive(character, noClipPlayers)
        else
            setCollisionGroupRecursive(character, "Default")
        end
    end
end)

Finally, we have the code that updates player movement, which I have put in a modified ControlScript. This same code can be run within the local script and still work, but having it in the control script speeds things up a lot. You will see i'm also rotating the character here before moving it. You can get away with only having the character rotation updated here, and not also in the local script, but as this is bound to the input render priority, only having it updated here gives you jittery rotations. To set this up, you will want to press play in studio, and in the explorer navigate to Players -> [your player name] -> PlayerScripts and copy the ControlScript you find in there (Ctrl+C). Then press stop to exit the game, and paste the ControlScript into StarterPlayer -> StarterPlayerScripts. Then expand the ControlScript in the explorer and you will find the MasterControl module. Open MasterControl up for editing.

On lines 82 to 99 is the code for the updateMovement function. You need to replace these 18 lines with the following

local getHumanoid = MasterControl.GetHumanoid
local moveFunc = LocalPlayer.Move
local shouldUpdate = false
local lastUpdate
local updateMovement = function()

    if not areControlsEnabled then return end

    local humanoid = getHumanoid()
    if not humanoid then return end

    if isJumpEnabled and isJumping and not humanoid.PlatformStand then
        local state = humanoid:GetState()
        if state ~= STATE_JUMPING and state ~= STATE_FREEFALL and state ~= STATE_LANDED then
            humanoid.Jump = isJumping
        end
    end

    if allowNoClip then
        if shouldUpdate then
            shouldUpdate = false
            moveFunc(LocalPlayer, Vector3.new(), true)
            lastUpdate = tick()
        end

        local root = LocalCharacter:FindFirstChild("HumanoidRootPart")
        if root then
            local cam = workspace.CurrentCamera
            local camForward = cam.CFrame.lookVector
            camForward = Vector3.new(camForward.X, 0, camForward.Z).Unit
            local currentTime = tick()
            local delta = currentTime - lastUpdate
            root.CFrame = CFrame.new(root.CFrame.p, root.CFrame.p + camForward) * CFrame.new(moveValue * delta * noClipSpeed)
            lastUpdate = currentTime
        end
    else
        moveFunc(LocalPlayer, moveValue, true)
        shouldUpdate = true
    end
end

Above what you just pasted, you want to insert this code

local allowNoClip = false
local noClipSpeed = 40
function MasterControl:SetNoClip(isNoClipActive, speed)
    allowNoClip = isNoClipActive
    noClipSpeed = speed
end

So the area you just modified should now look like this

if LocalCharacter then
    characterAdded(LocalCharacter)
end
LocalPlayer.CharacterAdded:connect(characterAdded)

-- The above was already there. Your code starts below
local allowNoClip = false
local noClipSpeed = 40
function MasterControl:SetNoClip(isNoClipActive, speed)
    allowNoClip = isNoClipActive
    noClipSpeed = speed
end

local getHumanoid = MasterControl.GetHumanoid
local moveFunc = LocalPlayer.Move
local shouldUpdate = false
local lastUpdate
local updateMovement = function()

    if not areControlsEnabled then return end

    local humanoid = getHumanoid()
    if not humanoid then return end

    if isJumpEnabled and isJumping and not humanoid.PlatformStand then
        local state = humanoid:GetState()
        if state ~= STATE_JUMPING and state ~= STATE_FREEFALL and state ~= STATE_LANDED then
            humanoid.Jump = isJumping
        end
    end

    if allowNoClip then
        if shouldUpdate then
            shouldUpdate = false
            moveFunc(LocalPlayer, Vector3.new(), true)
            lastUpdate = tick()
        end

        local root = LocalCharacter:FindFirstChild("HumanoidRootPart")
        if root then
            local cam = workspace.CurrentCamera
            local camForward = cam.CFrame.lookVector
            camForward = Vector3.new(camForward.X, 0, camForward.Z).Unit
            local currentTime = tick()
            local delta = currentTime - lastUpdate
            root.CFrame = CFrame.new(root.CFrame.p, root.CFrame.p + camForward) * CFrame.new(moveValue * delta * noClipSpeed)
            lastUpdate = currentTime
        end
    else
        moveFunc(LocalPlayer, moveValue, true)
        shouldUpdate = true
    end
end
-- Your edits end here

--[[ Public API ]]--

And that's it. I apologize for the long post, but I wanted to be as clear as possible with everything. If you have any questions feel free to ask.

0
I haven’t had time to test your script, but I’m not sure if it functions the same. I would want players to freely go through any object in the game and be able to fly around. Is that possible when using Collision Groups? Do you mind testing the script I posted to see how it works and tell me if it’s possible to make it less laggy? ericvesper123 65 — 7y
0
You are right, sorry. The script I posted only let's players go through objects. I didn't realize you wanted flight as well. I will have another look when I get some free time this afternoon vector3_zero 1056 — 7y
0
Looking at your scripts, you are calling the remote event 30 times a second when noclip is toggled on. That's bad for one client to be doing, but even worse if multiple clients are all doing it at once. Combined with that you will have the latency of handling movement on the server. There should be a way to modify the control script to make this workable, but i'll have to dig into it and see... vector3_zero 1056 — 7y
0
...what I can come up with. I will post here if I can find a workable solution vector3_zero 1056 — 7y
View all comments (2 more)
0
Ok, i've come up with a solution that I hope works for you. I have replaced my old answer above with the new code vector3_zero 1056 — 7y
0
That isn’t what I’m looking for though. I need the player to move when they look up/down while noclipping. What problems would it create if you did add it? I also tried to remove that falling animation but it’s just breaking the script. ericvesper123 65 — 7y
Ad
Log in to vote
0
Answered by 7 years ago

Never mind, I've found a solution!

In a LocalScript

repeat wait() until game.Players.LocalPlayer and game.Players.LocalPlayer.Character and game.Players.LocalPlayer.Character:findFirstChild("Torso") and game.Players.LocalPlayer.Character:findFirstChild("Humanoid") 
local mouse = game.Players.LocalPlayer:GetMouse() 
repeat wait() until mouse
local plr = game.Players.LocalPlayer 
local torso = plr.Character.Torso 
local flying = false
local deb = true 
local ctrl = {f = 0, b = 0, l = 0, r = 0} 
local lastctrl = {f = 0, b = 0, l = 0, r = 0} 
local maxspeed = 60 
local speed = 60 
function Fly()
    local char = plr.Character
    if char then
        local humanoid = char:WaitForChild("Humanoid")
        local root = char:WaitForChild("HumanoidRootPart")
        root.Anchored = true
        root.Anchored = false
        root.Velocity = Vector3.new()
        humanoid.PlatformStand = false
    end 
local bg = Instance.new("BodyGyro", torso) 
bg.P = 9e4 
bg.maxTorque = Vector3.new(9e9, 9e9, 9e9) 
bg.cframe = torso.CFrame 
local bv = Instance.new("BodyVelocity", torso) 
bv.velocity = Vector3.new(0,0.1,0) 
bv.maxForce = Vector3.new(9e9, 9e9, 9e9) 
repeat wait() 
plr.Character.Humanoid.PlatformStand = true 
if ctrl.l + ctrl.r ~= 0 or ctrl.f + ctrl.b ~= 0 then 
speed = speed+.5+(speed/maxspeed) 
if speed > maxspeed then 
speed = maxspeed 
end 
elseif not (ctrl.l + ctrl.r ~= 0 or ctrl.f + ctrl.b ~= 0) and speed ~= 0 then 
speed = speed-1 
if speed < 0 then 
speed = 0 
end 
end 
if (ctrl.l + ctrl.r) ~= 0 or (ctrl.f + ctrl.b) ~= 0 then 
bv.velocity = ((game.Workspace.CurrentCamera.CoordinateFrame.lookVector * (ctrl.f+ctrl.b)) + ((game.Workspace.CurrentCamera.CoordinateFrame * CFrame.new(ctrl.l+ctrl.r,(ctrl.f+ctrl.b)*.2,0).p) - game.Workspace.CurrentCamera.CoordinateFrame.p))*60
lastctrl = {f = ctrl.f, b = ctrl.b, l = ctrl.l, r = ctrl.r} 
elseif (ctrl.l + ctrl.r) == 0 and (ctrl.f + ctrl.b) == 0 and speed ~= 0 then 
bv.velocity = ((game.Workspace.CurrentCamera.CoordinateFrame.lookVector * (lastctrl.f+lastctrl.b)) + ((game.Workspace.CurrentCamera.CoordinateFrame * CFrame.new(lastctrl.l+lastctrl.r,(lastctrl.f+lastctrl.b)*.2,0).p) - game.Workspace.CurrentCamera.CoordinateFrame.p))*0 
else 
bv.velocity = Vector3.new(0,0,0) 
end 
bg.cframe = game.Workspace.CurrentCamera.CoordinateFrame 
until not flying 
ctrl = {f = 0, b = 0, l = 0, r = 0} 
lastctrl = {f = 0, b = 0, l = 0, r = 0} 
speed = 0 
bg:Destroy() 
bv:Destroy() 
plr.Character.Humanoid.PlatformStand = false 
end 
mouse.KeyDown:connect(function(key) 
if key:lower() == "" then 
if flying then flying = false
else 
flying = true
Fly() 
end 
elseif key:lower() == "w" then 
ctrl.f = 1 
elseif key:lower() == "s" then 
ctrl.b = -1 
elseif key:lower() == "a" then 
ctrl.l = -1 
elseif key:lower() == "d" then 
ctrl.r = 1 
end 
end) 
mouse.KeyUp:connect(function(key) 
if key:lower() == "w" then 
ctrl.f = 0 
elseif key:lower() == "s" then 
ctrl.b = 0 
elseif key:lower() == "a" then 
ctrl.l = 0 
elseif key:lower() == "d" then 
ctrl.r = 0 
end 
end)
Fly()

game:GetService("UserInputService").InputBegan:connect(function(input,event)
    if event then return end
if input.KeyCode == Enum.KeyCode.ButtonB or input.KeyCode == Enum.KeyCode.V then
        if (flying == false) then
            flying = true
            Fly()
        elseif (flying == true) then
            flying = false
        end
    end
end)

local noClipEvent = game.ReplicatedStorage:WaitForChild("NoClipEvent")
local isNoClipActive = false
local hoverHeight
local lastUpdate

local bodyPosition = Instance.new("BodyPosition")

game:GetService("UserInputService").InputBegan:connect(function(input, event)
    if not event then
        if input.KeyCode == Enum.KeyCode.ButtonB or input.KeyCode == Enum.KeyCode.V then
            if plr.Character and plr.Character.Parent then
                lastUpdate = tick()
                isNoClipActive = not isNoClipActive
                noClipEvent:FireServer(isNoClipActive)

                if isNoClipActive then
                    local root = plr.Character:FindFirstChild("HumanoidRootPart")
                    if root then
                        bodyPosition.Parent = plr.Character.HumanoidRootPart
                        bodyPosition.Position = root.Position
                        hoverHeight = root.Position.Y
                    end
                else
                    bodyPosition.Parent = nil
                end
            end
        end
    end
end)

Then I used your server script which uses Collision Groups

local PhysicsService = game:GetService("PhysicsService")
local Players = game:GetService("Players")

local noClipEvent = Instance.new("RemoteEvent")
noClipEvent.Name = "NoClipEvent"
noClipEvent.Parent = game.ReplicatedStorage

local noClipPlayers = "Players"
PhysicsService:CreateCollisionGroup(noClipPlayers)
PhysicsService:CollisionGroupSetCollidable("Default", noClipPlayers, false)

local function setCollisionGroupRecursive(object, groupName)
    if object:IsA("BasePart") then
        PhysicsService:SetPartCollisionGroup(object, groupName)
    end
    for _, child in ipairs(object:GetChildren()) do
        setCollisionGroupRecursive(child, groupName)
    end
end

noClipEvent.OnServerEvent:connect(function(player, isNoClipActive)
    local character = player.Character
    if character then
        if isNoClipActive then
            setCollisionGroupRecursive(character, noClipPlayers)
        else
            setCollisionGroupRecursive(character, "Default")
        end
    end
end)

Anyways, thanks for your help. Your collision groups script was really helpful!

0
Glad you got it working :) vector3_zero 1056 — 7y

Answer this question