An alternative to RenderStepped for lerping w/ CFrames to all clients?

What I am trying to achieve through scripting is a part smoothly transitioning from somewhere behind the character to a few studs ahead of them, and then staying there for a few seconds.

However, I have failed to find a way to do so without RenderStepped serving as a wait() for a loop of lerping the part’s cframe.
An example of why Heartbeat or Stepped is not an option here:
https://gyazo.com/2657102bc8d693d668d3ab116f2de249

As shown in the gyazo above, if the character moves around, the part will lag behind its destination, and in general it looks pretty choppy. But with RenderStepped, you don’t have that issue.
https://gyazo.com/d6b3a935bc592b083b68f9e6571fd1a0

However, because RenderStepped can only be used in a local script, it can only be shown to a client. And so for me to let every client in the server know that this part is a few studs ahead of this character, I would have to use FireAllClients(), right? Well, I did this, but then realized that when a new player would join, this previous calling of FireAllClients() would not affect them, and so they would not see the floating brick that everyone else does. Can anyone help me figure out an alternative to RenderStepped to achieve my goal, or a way to use it so that I don’t have to worry about this issue with new players joining?

1 Like

Each client should move the bricks for himself.

Player joins
Loops thru players and checks whether theres that part, if there is, add him to table
New part created, add to table
While loop, go through every item in table and position it

1 Like

FireAllClients() or you can do FireClient(player), it depends on what you want. If you want all players to have that then FireAllClients(). For one player or if you want to one player at a time then FireClient(player)

If you want it to look like how it looks in the second gif, then I would just have the server weld the part to the Character. Another option is to set the network owner of the part to the player it needs to stay infront of which will allow the client to freely control & replicate the part’s movement, but that may still cause it to be choppy for other players if that player lags.

You could have a remotefunction that a new player may call when they join to receive the information given by FireAllClients() from the server. However, I recommend trying out the two options noted above instead.

If you are firing an event to the server only once, and firing to clients only once after that, then the behaviour you are describing is natural. Players who join after the server fires will not receive the information. I believe you need to add a second case scenario for when a player joins, via PlayerAdded event, to update them with this information.

This is my very first post, so I you find this helpful.

2 Likes

You can use either Welds (possibly weldconstraints) or BodyMovers. A BodyGyro with a BodyPosition may do the trick for what you’re trying to pull off. Using BodyMovers with a mix of SetNetworkOwner may succeed with what you’re doing.

If you didn’t understand Legoracer’s reply, this is essentially the framework you’re after.

function movePlayerPart( part )
    -- do your stuff
end

function handleCharacter( character )
    local part = character:FindFirstChild( 'YourPart' )
    if part then
        movePlayerPart( part )
    end
    
    character.ChildAdded:Connect( function ( part )
        if part.Name == 'YourPart' then
            movePlayerPart( part )
        end
    end )
end

function handlePlayer( player )
    if player.Character then
        handleCharacter( player.Character )
    end
    
    player.CharacterAdded:Connect( handleCharacter )
end

for _, player in pairs( game.Players:GetPlayers() ) do
    handlePlayer( player )
end
game.Players.PlayerAdded:Connect( handlePlayer )

The handle functions are to prevent the repetition of code. It’s a good habit to not repeat the same code anywhere as if you need to make changes to what we do with a character, you only need to edit the one function.

Hope that helps!

1 Like

Thanks to those who have responded to my post!
I initially did not want to use welds because I wanted a smooth transition from one point near the character to the front of them, but I ended up working a way out to get this smooth transition without using RenderStepped, because I really don’t want to mess with client-sided stuff, as I need to have things like damage, indicators, and more present in the code, and handling this all on each client would be pretty buggy.

What I am instead doing now is welding the part initially behind the character, then play an animation that moves the block forward, this both fixing the client problem and the smooth transition problem. I felt it was needed for me to explain that I had found a solution. If anyone has any other ideas on the topic of client-related problems like this one, please feel free to share!

Result: https://gyazo.com/9c1961fc4fb0abb0467bf0846a7dc1cf

2 Likes

lol you want every player firing FireAllClients at 60hz?

1 Like

You should use Heartbeat for part movement (which importantly works server sided). For smooth movement from server to client you can set the part’s Velocity to the difference between its current position and its last position times 1/delta and keep it unanchored. This should trigger clients to interpolate the part to the target location in one physics step meaning they will see smooth movement even if the server is lagging.

The reason you should use Heartbeat is because this is run immediately after physics calculations are done and before rendering parts on the client. Velocity is also updated immediately before Heartbeat.

If you do not want to use welds and the movement is handled client sided you should have the client mimick the server loop. That will mean that all clients will see the movement consistently since physics information will only be sent after server Heartbeat (which means it will appear in the right place related to your character for other clients) and your own client will also be updating the location for itself. If you want the server to control the offset locations of a part you should sync the target client’s offsets
with a remote only when they’re updated on the server, not per frame.

2 Likes

No need to do anything from above. You just set network ownership of the part to target player and move it with renderstepped from the client. It will replicate while looking smooth on the client.
Source: Network Ownership | Documentation - Roblox Creator Hub

1 Like

Network ownership only makes a specified entity authoritative of replicating physics. It doesn’t give complete replication authority over a part, plus you still need a way to move the part at all. If it’s physically involved, network ownership is a plus. Do not use RenderStepped though.

Unlike Heartbeat, RenderStepped is ran before frames are rendered. This means that frames can be blocked from rendering simply because you have connections taking time to complete under RenderStepped. Realistically you have few use cases for RenderStepped, which include updating the camera or running something in tandem with it (use BindToRenderStep instead).

Then use body force. Should look even smoother.

1 Like

Provided you render the item on the client-side, then. Body movers are not a catch-all solution. You will still require a client in some form or another to get the “smooth movement” as desired. That means either passing network ownership to a client (and thus trusting them with holding authority over the part’s physics), or making each client render its own copy of the part.

The heartbeat + velocity solution seems like the best way to go about it, but unfortunately I am not yet experienced enough to implement it. For example, I don’t know how one would go about retrieving a previous position nor am I really sure what delta is. Do you know of any resources I can look at to get at least some understanding of these two things?

Delta just means difference. The frame delta is the difference (in seconds) between the first and previous frame. 1/delta will be an estimate for FPS. It’s the first argument passed to the Heartbeat event. To connect to the Heartbeat event you can do this:

local RunService = game:Get service("RunService")
RunService.Heartbeat:Connect(function(delta)
	-- Stuff
end)

I was also mistaken with having parts be unanchored since it appears that clients will run their own physics and it gets too complicated to fix that issue. So you’ll basically just want to anchor the part and anything connected to it can be welded.

Where I put “-- Stuff” you can mimic the behaviour of welds by multiplying the part’s CFrame by what would be C0 and then multiply again by what would be C1:Inverse()

(By the way, C0 can just be the character’s CFrame and C1 can be the parts’s CFrame)