Replicating a custom physics simulated anchored character?

I have an Anchored character (to avoid Roblox’s physics) that runs custom physics client-sided. How can I force Roblox to replicate this part to server?

Well, unfortunately, that can only be accessed by CoreScripts, but there’s a few workarounds. For example, you can use a RemoteEvent to fire every split second (which doesn’t give horrible performance).

1 Like

does it need to be on the client? I imagine you can send the player inputs from the client to the server and do the simulation there

2 Likes

That’s true, but stuff like collision calculations is expensive server-side so for the smoothest physics I have to do it client-sided.

1 Like

well the only thing I can think of is unanchoring, then turning off gravity, and turning on no collide so the client’s changes will replicate

you’ll also probably need to reassign WASD and space

So I assume you already have a physics engine and your just trying to make all clients see the physics.

I think the best method for this is to make the client render physics for all players for a cleaner effect. The client should consistently receive data of player positions, velocity from all the other clients and render the physics based on that data they have received, while they send data of their own character to the other clients.
Rendering Self:

  • Render Physics of own character.
  • Send data of own character to all clients (velocity, position, rotation, rot velocity)

Rendering Other Players:

  • Receive data from other players to be rendered for smoother physics.
  • Render their physics from the data they received (velocity, position, rotation, rot velocity)

You can accomplish this by:
Local Script

local Remote = nil --Your RemoteEvent
local PlayerPhysics = { --Your Physics Data
	Position = Vector3.new(0, 0, 0),
	Rotation = Vector3.new(0, 0, 0),
	Velocity = Vector3.new(0, 0, 0),
	RotVelocity = Vector3.new(0, 0, 0),
}

local function RenderPhysics(Character, PlrPhysics) --Your Physics Engine
	local Physics = {}
	Physics.Position = PlrPhysics.Position
	Physics.Rotation = PlrPhysics.Rotation
	Physics.Velocity = PlrPhysics.Velocity
	Physics.RotVelocity = PlrPhysics.RotVelocity
	return Physics
end

Remote.OnClientEvent:Connect(function(Player, Physics) --Receive data from other players to be rendered for smoother physics.
	if Player ~= game.Players.LocalPlayer then --Make sure it dosent re-render itself, it dosent need to.
		RenderPhysics(Player.Character, Physics) --Render their physics from the data they received (velocity, position, rotation, rot velocity)
	end
end)

game:GetService("RunService").RenderStepped:Connect(function()
	PlayerPhysics = RenderPhysics(game.Players.LocalPlayer.Character, PlayerPhysics) --Render Physics of own character.
	Remote:FireServer(PlayerPhysics) --Send data of own character to all clients (velocity, position, rotation, rot velocity)
end)

Server Script

local Remote = nil --Your RemoteEvent

Remote.OnServerEvent:Connect(function(Player, PlayerPhysics) -- Recieved Physics data from a client.
	Remote:FireAllClients(Player, PlayerPhysics) -- Tell all clients to render this player's physics.
end)

This is a solution that I have already considered, but decided against due to remote throttling. Roblox built-in replication for the player and server is much smoother and isn’t throttled, though if all else fails I’ll use this instead.

Thank you for contributing ^^

1 Like

This is only a problem because we are spamming the remote with physics every frame. Like Roblox, we only need to send it every few seconds and we can rely on the other clients to fill in between the seconds.

This is why Roblox players are still smooth, because the client renders in between the seconds.
I set the delay to 1 second, but you can change that to go faster or slower if you want.
Local Script

local Remote = nil --Your RemoteEvent
local PlayerPhysics = { --Your Physics Data
	Position = Vector3.new(0, 0, 0),
	Rotation = Vector3.new(0, 0, 0),
	Velocity = Vector3.new(0, 0, 0),
	RotVelocity = Vector3.new(0, 0, 0),
}

local function RenderPhysics(Character, PlrPhysics) --Your Physics Engine
	local Physics = {}
	Physics.Position = PlrPhysics.Position
	Physics.Rotation = PlrPhysics.Rotation
	Physics.Velocity = PlrPhysics.Velocity
	Physics.RotVelocity = PlrPhysics.RotVelocity
	return Physics
end

Remote.OnClientEvent:Connect(function(Player, Physics) --Receive data from other players to be rendered for smoother physics.
	if Player ~= game.Players.LocalPlayer then --Make sure it dosent re-render itself, it dosent need to.
		RenderPhysics(Player.Character, Physics) --Render their physics from the data they received (velocity, position, rotation, rot velocity)
	end
end)

local RemoteDelay = 1 -- Only send data every second to stop sending too much information to other clients.
local StartTime = tick()

game:GetService("RunService").RenderStepped:Connect(function()
	if StartTime - tick() > RemoteDelay then
		PlayerPhysics = RenderPhysics(game.Players.LocalPlayer.Character, PlayerPhysics) --Render Physics of own character.
		Remote:FireServer(PlayerPhysics) --Send data of own character to all clients (velocity, position, rotation, rot velocity)
		StartTime = tick() -- Resets the clock
	end
end)

1 Like

Like this

BasePart.RootPart.Anchored = false
BasePart.RootPart:SetNetworkOwner(Player)

This will set any assemblies physics calculation to the control of whom ever is passed through the players argument.

I recommend holding off on Velocity and RotVelocity, as those are deprecated. Instead, use BasePart:GetVelocityAtPosition(BasePart.Position) and BasePart:GetAngularVelocityAtPosition(BasePart.Position). I’m not too sure about the 2nd one.

I’m not talking about the base part property “Velocity” and “RotVelocity”, because as they said they have their own custom physics engine.

Here is where they render their own physics using their custom physics engine, Roblox does not render this.

1 Like