How would i properly replicate climbing to the Server

I’m working on a simple climbing system for a game I’m making. It uses a Weld instance (built into the StarterCharacter) to force the player onto a climbing grip when they touch it. The problem is, when I change the Weld’s Part1 on the client it’s not replicating to the server.

Here is a video of the client and server pov when testing:

One solution I tried was using a RemoteEvent that the client would fire to set the Weld’s Part1 on the server, and it worked pretty well until i tested it with Incoming Replication Lag set to 1. With this solution, the player’s character would jump back and forth to different climbing grips because of the lag.
(unfortunately i didnt record this solution and im too lazy to bring it back)

Bump
I’d appreciate if someone could help

The issue you’re facing with Weld.Part1 not replicating from the client to the server, especially when combined with network lag, is a common problem in Roblox game development. This happens because Roblox’s physics simulation is primarily server-authoritative. Changes to physics-related properties (like Weld.Part1, CFrame, Velocity) made on the client generally won’t replicate to the server automatically. Your previous RemoteEvent solution caused “jumping back and forth” because the client’s immediate visual update got out of sync with the server’s delayed authoritative update.

To fix this, you need to make the server the authority for setting the Weld.Part1, while still providing immediate visual feedback on the client to ensure a smooth player experience.

Here’s a refined approach:

1. Client-Side Input and Immediate Visual Feedback

When the player character touches a climbing grip:

  • Immediately perform a local visual update on the client. This means setting the Weld.Part1 on the client’s side locally. This gives the player instant responsiveness, making the climbing feel smooth.
  • Fire a RemoteEvent to the server, informing it which climbing grip the player intends to attach to. Pass the BasePart object of the climbing grip as an argument.

2. Server-Side Validation and Weld Update

When the server receives the RemoteEvent:

  • Validate the request. This is crucial for security and consistency. Check if the requested climbing grip is actually reachable by the player and if the player is in a valid state to climb.
  • If validation passes, the server sets the Weld.Part1 of the player’s Weld instance to the requested climbing grip. Since the server is making this change, it will automatically replicate to all other clients, ensuring everyone sees the player correctly attached.
  • You may also need to adjust the character’s CFrame or other properties on the server to align them perfectly with the grip.

Why this approach works better with lag:

The “jumping back and forth” is mitigated because the client’s local change is only for temporary visual feedback and is not expected to replicate. The server’s update is the authoritative one that will replicate to all clients. While there might be a brief, minor visual correction when the server’s update propagates, it will be much smoother than constant snapping due to delayed server-side Part1 assignments.


Implementation Example (Roblox Luau)

Here’s how you can implement this in your Roblox game:

1. Create a RemoteEvent

In ReplicatedStorage, create a new RemoteEvent and name it ClimbRemoteEvent.

2. Server Script (e.g., in ServerScriptService)

This script will handle the RemoteEvent fired by the client and update the Weld on the server.

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ClimbRemoteEvent = ReplicatedStorage:WaitForChild("ClimbRemoteEvent")

ClimbRemoteEvent.OnServerEvent:Connect(function(player, climbingGripPart)
    local character = player.Character
    if not character then return end

    local humanoid = character:FindFirstChildOfClass("Humanoid")
    local rootPart = character:FindFirstChild("HumanoidRootPart")
    -- Assuming your Weld is named "BodyWeld" and is a child of the character.
    -- Adjust if your Weld is located elsewhere or named differently.
    local characterWeld = character:FindFirstChild("BodyWeld") 

    -- Basic validation checks
    if not humanoid or not rootPart or not characterWeld or not climbingGripPart or not climbingGripPart:IsA("BasePart") then
        warn(player.Name .. " sent an invalid climb request.")
        return
    end

    -- Further server-side validation (add more as needed)
    -- Example: Check if the climbingGripPart is actually a valid grip in your game
    -- and if the player is close enough to it.
    local distance = (rootPart.Position - climbingGripPart.Position).Magnitude
    if distance > 10 then -- Example: max distance of 10 studs to prevent exploits
        warn(player.Name .. " tried to climb a grip too far away.")
        return
    end

    -- Ensure the character is not already welded to something else or in an invalid state
    if characterWeld.Part1 == climbingGripPart then
        return -- Already welded to this part
    end

    -- Set the Weld.Part0 and Weld.Part1 on the server
    -- Part0 should be the part of the character you want to weld (e.g., HumanoidRootPart or UpperTorso)
    characterWeld.Part0 = rootPart 
    characterWeld.Part1 = climbingGripPart

    -- Adjust C0/C1 to correctly position the character relative to the grip
    -- This will depend on how your climbing grips are oriented and where you want the character to be.
    -- A common setup is to align the rootPart's CFrame with the grip's CFrame, then offset.
    characterWeld.C0 = rootPart.CFrame:Inverse() * climbingGripPart.CFrame * CFrame.new(0, -rootPart.Size.Y/2, 0) -- Example offset
    characterWeld.C1 = CFrame.new()

    -- Optional: Disable character movement/physics while climbing
    humanoid.Sit = true -- Makes the character sit, often used for welding
    humanoid.AutoRotate = false -- Prevents the character from rotating automatically

    print(player.Name .. " successfully welded to " .. climbingGripPart.Name)
end)`

#### 3. Local Script (e.g., in `StarterPlayerScripts` or `StarterCharacterScripts`)

This script will detect touches on the client and provide immediate feedback, then fire the `RemoteEvent`.

`Lua-- Local Script (e.g., in StarterPlayerScripts or StarterCharacterScripts)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ClimbRemoteEvent = ReplicatedStorage:WaitForChild("ClimbRemoteEvent")

local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer
local Character = LocalPlayer.Character or LocalPlayer.CharacterAdded:Wait()
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
-- Assuming your Weld is named "BodyWeld" and is a child of the character.
local CharacterWeld = Character:WaitForChild("BodyWeld") 

-- You might want to use CollectionService to tag your climbing grips
-- For example, tag all climbable parts with "ClimbingGrip"
local CollectionService = game:GetService("CollectionService")

local function onTouched(otherPart)
    -- Check if the touched part is a climbing grip
    -- You can use CollectionService tags, or check by name/parent, etc.
    if CollectionService:HasTag(otherPart, "ClimbingGrip") then
        -- Ensure we have the necessary parts
        if CharacterWeld and HumanoidRootPart then
            -- Client-side visual update (temporary, will be overridden by server)
            -- This provides immediate feedback to the player.
            CharacterWeld.Part0 = HumanoidRootPart
            CharacterWeld.Part1 = otherPart
            CharacterWeld.C0 = HumanoidRootPart.CFrame:Inverse() * otherPart.CFrame * CFrame.new(0, -HumanoidRootPart.Size.Y/2, 0)
            CharacterWeld.C1 = CFrame.new()

            -- Fire the RemoteEvent to the server
            ClimbRemoteEvent:FireServer(otherPart)
        end
    end
end

-- Connect the Touched event of the HumanoidRootPart
HumanoidRootPart.Touched:Connect(onTouched)

-- You'll also need logic to un-weld the player (e.g., when they jump or press a key)
-- This un-welding logic should also be handled via a RemoteEvent to the server
-- so the server can set Weld.Part1 to nil and allow normal movement.`
---

By implementing this client-server communication pattern, you ensure that the server maintains authority over the Weld’s state, leading to a more stable and synchronized climbing system, even with network lag.

Why’d you have to send an AI response…??

It might work, tell me if it works or not, and I will try next time without AI

…This is basically the exact same solution as my attempt but with server validation and a bunch of comments

I would recommend approaching the movement of the player by altering their CFrame while keeping their HumanoidRootPart anchored. The CFrame of the player’s character will always replicate and stay where you want it.

The reason the server isn’t replicating the weld is because it technically doesn’t exist from the server’s perspective, so it’s most likely trying to run physics on the server which keeps it out of sync. But in general, it’s a good rule of thumb to not use constraints specifically on the client when you’re aiming for replication.

Alright so i came up with a solution which was to make the system server-authoritative

Basically what i did was make the client invoke a RemoteFunction to replicate the weld on the server. The client would then weld the player to the hold and ask the server to do the same. It then waits for a valid response before being able to do anything else (like jumping off)
If the server denies the request then the player will be forced off.
This might not be the smoothest solution for anyone with horrendous lag but i guess it works fine.

Update: I later realized that i could just “anchor” the rootpart (lock the player’s velocity with a BodyVelocity, not actually anchor since the player would then lose network ownership) and continuously move them to the hold on the client. That way it would replicate to the server and the lag wouldnt mess up the player.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.