Roblox Universal Desync (using hooks)

Introduction

Hello so I will be showing how you will create a desync in Roblox that utilizies the hookmetamethod feature on most executors. This way is simple, but it works.

Defining Variables

Uh so we will be using localplayer and runservice so we will define those.

local runService = game:GetService("RunService")
local localPlayer = game:GetService("Players").LocalPlayer

Type.

Making our table for the desync

We want to know if its on or not so we will make an enabled one, we will also make something to store the location of the desync

local desyncT = {
   enabled = true,
   loc = CFrame.new()
}

runservice loop to update the desync position

runService.Heartbeat:Connect(function()
    if desyncT.enabled and localPlayer.Character then
    end
end)

we want to check if the desync is enabled or not, and if our localplayer character exists so yea. next we will be making the deeessssyyyynccc via the table.

runService.Heartbeat:Connect(function()
    if desyncT.enabled and localPlayer.Character then
        local character = localPlayer.Character
        local root = character:FindFirstChild("HumanoidRootPart")
        if root then
            desyncT.loc = root.CFrame -- setting the real cframe to where we are
            local newCframe = desyncT.loc -- storing the actual cframe
            newCframe = newCframe * CFrame.new(0, -5, 0) -- moving our player down 5 studs (via the desync)
            root.CFrame = newCframe -- setting our root cframe to the new cframe we made (no u will not be able to see this on ur client)
            runService.RenderStepped:Wait() -- waiitiititt
            root.CFrame = desyncT.loc -- reset our players cframe back to where we were beforehand
        end
    end
end)

ok now we make the hook….

local desynchook = nil
desynchook = hookmetamethod(game, "__index", newcclosure(function(self, key)
    if desyncT.enabled and not checkcaller() and key == "CFrame" and localPlayer.Character and self == localPlayer.Character.HumanoidRootPart then
        return desyncT.loc
    end
    return desynchook(self, key)
end))

incase u are wondering why we dont define the character or humanoidrootpart at top of code its because we die and it doesnt update unless we make another loop for that and theres just no need its such short code

combining it…

local runService = game:GetService("RunService")
local localPlayer = game:GetService("Players").LocalPlayer

local desyncT = {
   enabled = true,
   loc = CFrame.new()
}

runService.Heartbeat:Connect(function()
    if desyncT.enabled and localPlayer.Character then
        local character = localPlayer.Character
        local root = character:FindFirstChild("HumanoidRootPart")
        if root then
            desyncT.loc = root.CFrame -- setting the real cframe to where we are
            local newCframe = desyncT.loc -- storing the actual cframe
            newCframe = newCframe * CFrame.new(0, -5, 0) -- moving our player down 5 studs (via the desync)
            root.CFrame = newCframe -- setting our root cframe to the new cframe we made (no u will not be able to see this on ur client)
            runService.RenderStepped:Wait() -- waiitiititt
            root.CFrame = desyncT.loc -- reset our players cframe back to where we were beforehand
        end
    end
end)

local desynchook = nil
desynchook = hookmetamethod(game, "__index", newcclosure(function(self, key)
    if desyncT.enabled and not checkcaller() and key == "CFrame" and localPlayer.Character and self == localPlayer.Character.HumanoidRootPart then
        return desyncT.loc
    end
    return desynchook(self, key)
end))

— how much of this code is unnecessary? i do not know and dont wanna find out

11 Likes

Thank you shaqil o nil aka luv This Is Real Good Post Sir :smiley:

1 Like

Nice post, quick and easy hook on a getter never hurts haha.

1 Like

Why do you reset the root’s CFrame back to desyncT.loc after RenderStepped:Wait(), I’m inexperienced on this subject, isnt keeping it desynced for longer b8r?

1 Like

we use the wait so that we dont actually teleport to the position on the client, previously we set our root cframe to our desync position which if we didnt have that renderstep wait to teleport back, it would make us really teleport there

thanks shaq nice quick & easy post

1 Like

this desync is nowhere near real and essentially useless. it only desynchronizes your client’s position from the server, but other players will still see you at your actual server position. so, there is little to no practical use for this. however, +rep for some explanation :sparkling_heart:

the purpose of a desync is to de-synchronize server and client position, where u can return one thing to the server whilst be somewhere else on the client - shown in this example.

i will make a better post sooner, wait. and this is not the purpose of a desync. the purpose of a desync is to de-synchronize server position from the position on others’ players screen

that is what this is doing, the other players will see the cframe value you set to return on the server whilst you are somewhere else

literally no. wait for my post

a lock position on toggle based one, i havent tested but im uploading for something else - so ill just post it with this

local runService = game:GetService("RunService")
local localPlayer = game:GetService("Players").LocalPlayer
local uis = game:GetService("UserInputService")

local desyncT = {
    enabled = true,
    loc = CFrame.new()
}

local lockedPos = localPlayer.Character.HumanoidRootPart.CFrame

runService.Heartbeat:Connect(function()
    if desyncT.enabled and localPlayer.Character then
        local character = localPlayer.Character
        local root = character:FindFirstChild("HumanoidRootPart")
        if root then
            desyncT.loc = root.CFrame
            root.CFrame = lockedPos
            runService.RenderStepped:Wait()
            root.CFrame = desyncT.loc
        end
    end
end)

uis.InputBegan:Connect(function(input)
    if input.KeyCode == Enum.KeyCode.Q then
        desyncT.enabled = not desyncT.enabled
    end
end)

local desynchook = nil
desynchook = hookmetamethod(game, "__index", newcclosure(function(self, key)
    if desyncT.enabled and not checkcaller() and key == "CFrame" and localPlayer.Character and self ==
        localPlayer.Character.HumanoidRootPart then
        return desyncT.loc
    end
    return desynchook(self, key)
end))

I think @shaq meant to show how to desync the client and server positions using hookmetamethod and RunService. While it’s true this only affects the client side position, the goal was to show how the client and server can be out of sync. Here’s shaq’s code with comments I added to explain how it works:

-- necessary services
local runService = game:GetService("RunService")
local localPlayer = game:GetService("Players").LocalPlayer
local uis = game:GetService("UserInputService")

-- Table to store desync settings
local desyncT = {
    enabled = true,
    loc = CFrame.new() -- Stores the player's real position
}

-- Lock the player's position to their current position
local lockedPos = localPlayer.Character.HumanoidRootPart.CFrame

-- Heartbeat loop to handle desync
runService.Heartbeat:Connect(function()
    if desyncT.enabled and localPlayer.Character then
        local character = localPlayer.Character
        local root = character:FindFirstChild("HumanoidRootPart")
        if root then
            -- Save the player's real position
            desyncT.loc = root.CFrame
            -- Move the player to the locked position (desync)
            root.CFrame = lockedPos
            -- Wait for the next frame
            runService.RenderStepped:Wait()
            -- Reset the player to their real position
            root.CFrame = desyncT.loc
        end
    end
end)

-- Toggle desync with the "Q" key
uis.InputBegan:Connect(function(input)
    if input.KeyCode == Enum.KeyCode.Q then
        desyncT.enabled = not desyncT.enabled
    end
end)

-- Hook to return the real position to the server
local desynchook = nil
desynchook = hookmetamethod(game, "__index", newcclosure(function(self, key)
    if desyncT.enabled and not checkcaller() and key == "CFrame" and localPlayer.Character and self ==
        localPlayer.Character.HumanoidRootPart then
        return desyncT.loc -- Return the real position to the server
    end
    return desynchook(self, key) -- Otherwise, return the original value
end))
1 Like

Why would you need this tho? /srs

1 Like

it makes a cleaner experience in some areas, like for a game like dahood you can use the desync and hit the player from entirely across the map (it would appear) tho your actual player would be near them, you wouldnt see this and it would look smooth. so enhancing user experience