How can I sync the physics of client generated debris

I’m making a destruction system where the server creates the holes and the client generate the debris. And that all works fine, however, when trying to get the debris to end up in about the same location doesn’t always work and it’s a bit frustrating. I’m really trying to avoid server physics calculations but I don’t know how I can get the clients to agree on an end position. I have the workspace physics set to fixed to make the roblox physics engine as deterministic as possible but it seems that the desync will spiral out of control if debris hits other misaligned debris.

example of what I’m talking about:

1 Like

Have you considered using the Network Ownership API? Unless I misread your post, this should be what you need.

the debris is client sided so the Network Ownership API wouldn’t exactly be applicable here. What i’m asking here is how can I make either the physics be deterministic or if I can somehow have a way for the debris to interpolate to some final position.

The debris in your game is handled on the client-side, which can cause it to move differently for each player. This happens because client-side physics can be unpredictable, especially when debris collides.

-- Set the physics settings in Workspaceto fixed so that calculations are the same for all clients.
-- Use tweening to smoothly move the debris to its final position instead of relying on physics. This way, all players will see the debris land in the same spot.

I do not know the final position of the debris though?

Oh-
Well, I created a script as an example so you can try to figure out where im coming from.

-- Variables
local debrisParent = game.Workspace
local debrisCount = 10
local debrisLifetime = 5  -- Lifetime of the debris in seconds

-- Function to create debris
local function createDebris(position, velocity)
    -- This creates a Part to represent the debris
    local debris = Instance.new("Part")
    debris.Size = Vector3.new(1, 1, 1)
    debris.Position = position
    debris.Anchored = false
    debris.CanCollide = true
    debris.Parent = debrisParent

    -- Apply an initial velocity
    local bodyVelocity = Instance.new("BodyVelocity")
    bodyVelocity.Velocity = velocity
    bodyVelocity.MaxForce = Vector3.new(1000, 1000, 1000)  -- Allow the part to move
    bodyVelocity.Parent = debris

    -- Calculate the predicted final position (for simplicity, we assume it stops after a certain time)
    local finalPosition = position + velocity * debrisLifetime

    -- Function to smoothly interpolate to the final position
    local function moveDebris()
        local startTime = tick()
        while tick() - startTime < debrisLifetime do
            -- Interpolate the position
            local alpha = (tick() - startTime) / debrisLifetime
            debris.Position = debris.Position:Lerp(finalPosition, alpha)
            wait(0.03)  -- Small wait to avoid freezing the game
        end
        -- Cleanup: Destroy debris after moving
        debris:Destroy()
    end

    -- Start moving the debris
    moveDebris()
end

-- Example of creating debris with random positions and velocities
for i = 1, debrisCount do
    local randomPosition = Vector3.new(math.random(-50, 50), 50, math.random(-50, 50))
    local randomVelocity = Vector3.new(math.random(-10, 10), -15, math.random(-10, 10))  -- Random downward velocity
    createDebris(randomPosition, randomVelocity)
end

-- The final position is calculated based on the initial velocity and how long the debris is allowed to move. SO, after the debris reaches its final position, it’s destroyed to free up resources.

Please bear with me; I’m still confused on this myself.

Oh, I’m sorry, I reread your message and didn’t see that you were avoiding physics calculations at first. However, I still think you should give that approach a try. While it does use some initial physics to create more natural-looking movement, the key part of the script is that it quickly switches to interpolation for smoother, more consistent debris positions across clients.

realistically the best you can do is tell every client that you wish to render this debris with the exact same info so that the client itself will render the debris, whether or not it’ll desync or not is not really in our control. if you truly want the exact same position you could make values on the server of positions and have the client render it, so the server doesn’t have to handle any load other than data distribution of data to clients.

but how exactly would I go about doing that? games like jjs and realm rampage seem to have it down. Like to me it’s one of two things, its either they’re somehow making the destruction physics work in a deterministic fashion where there is somehow no discrepancies or, two, they have some server side physics working to guide the client debris. But I’m like 99% sure that neither game actually instance the parts on the server and also does the physics on the server (cuz it would lag).

im not sure how they do the actual determination of the look of the debris, but the function goes something like this from how i’ve seen it work.

it creates a brick and gets a section of a destructible building, it figures out what section of it gets deformed parts around it and either tells the client, or the server itself deletes that section of the building.

once it determines what part of the building is destroyed, it tells every client nearby the building to spawn a bunch of parts at a set CFrame and parses a set velocity constructor through for each part so the wall will deform in a similar fashion on every client.

if my explanation is confusion, i can quickly whip up an rblx place of something similar to the tech they use in those games, but it’d be very watered down :sweat_smile:

If you could create that example I think that would help me understand what you’re talking about.

sorry for the wait, but i whipped up just a quick demo, i left comments explaining everything for those in the future who view the thread but, from my test it networks between clients pretty solidly, but as i said its never going to be 100% perfect.

destruction test.rbxl (49.4 KB)

1 Like

Yeah, this the same kind of approach I am running. So there must be some kind of correction going on in those other games. However, I just cant think of how they’re doing it. Thank you for your help in this!

edit: I would keep it like this, but people can then just stand on seemingly invisible debris to other clients, which i deem to be unacceptable

you’d be surprised at how much it happens, in games such as The Strongest Battleground the client renders most of, if not all of the effects. players who just join may see others floating as another player used a move that spawned big chunks of parts and you’ll notice they’ll be sitting on top of other parts that only their client perceives.

it does suck because even in games like Jujutsu Shenanigans, if multiple collisions happen at once and say it involves a player going through a wall, its almost impossible to stop desyncs. in the end its just something you’ll have to deal with because most of this is an approximation between clients.

2 Likes

for tsb it probably doesn’t need to be accurate at all considering that the moving debris is uncollidable i think. but in jjs I really never have experienced any desynchronization at all so I feel that there is something else going on behind the scenes. In another game that has destruction, realm rampage, I noticed that debris pieces would sometime interpolate to a different position. I’m not sure how exactly it’s determined but it is interesting.

it could be serversided or they have some sort of client syncro system once the parts settle, its speculation on my end at this point though.

as for tsb, you can use a Serious Punch and see what i mean, it randomizes the rotation of some of the parts on the client and you’ll see players flying on your screen temporarily

i think it has to be some kind of client syncronization system because in jjs’s case it literally shows partcache log messages in the client devconsole. But i just don’t get how that would work because in order to simulate the physics on the server you would have to instance the parts on the server, and those would immediately be sent to the client anyways, defeating the purpose of actually creating client sided debris.

i was testing jjs’es destruction system and i think it is server sided.

i had a partner join me and share their pov and did a few tests, and what i found is that objects will anchor themselves after like 1 second or so. when i killed my friend with a chair, the chair frame landed on her back and when she respawned, the part was anchored in midair. but low and behold, there was no desync. which leads me to believe that JJS doesn’t actually have a client sided destruction system, rather its server sided but to save on physics rendering, it anchors parts after a few seconds.

i don’t have the time to check rn, but if you REALLY want to check if its client sided, you could destroy the center of the map w/ gojos external blue + red and see if a client joining the game sees the same destruction, if not its client sided, if so its server sided.

That last part stated isn’t necessarily true, the server can store points of destruction and then tell the client joining to destroy those areas before they fully load in

you’re not wrong, but it seems like an unnecessary amount of data to store depending on how the destruction system is done, especially when it gets repaired in 1 minute