Bridging the client server boundary without a remote event?


I saw this paragraph on the wiki

While part properties do not technically replicate, there are a few exceptions. If the part is created by a client and that client simulates physics (the part falls, hits other objects, moves by constraints, etc.), the resulting changes will get copied to the server.

I am wondering if it is possible to somehow leverage this to cross the client server boundary without a remote event? Such as moving a part by constraints on a character locally and have it replicate to the server?

If I’m not mistaken, :SetNetworkOwner(Player) simulates all physics-based objects locally and are replicated to the server.

1 Like

Using a part to transfer info would be interesting to try. You could make a pretty simple 3 bit / part model.

The model has a base position. then use the delta of each axis as a bit. (+x,-y,-z) → (1,0,0)
(could use origin values as nils, giving you 3^3 instead of 2^3)

The issues become:
How much data do you need to share?
How inefficient would it become?

But piggybacking on physics would let you do P2P with the server as a default replicator. Hmm… if you have a part wiggle represent an event fire, other clients could listen for it.


So, did a thing.
Made a simple proof of concept. Things to note are:

  1. You have to use physics constraints, I used BodyPosition and BodyGyro. Direct CFrame and Position manipulation wasn’t replicated.
  2. Network Ownership requires parts be unanchored. If a part is anchored, there is no physics on the object ergo no ownership applicable.

This repro has 9, size(1,1,1) parts used as markers, 8 are bits and the 9th is reserved for signaling that the other client can read the new byte. Info compression and optimization can be added too as mentioned earlier. Since body movers are being used, not sure how much error will be in your positions so the reading process might need to be similar to electrical signals (define a threshold value that defines the 0,1 regions). I suspect depending on size of parts and positions, rounding errors will prevent absolute checks(==).

Server Script
local Players = game:GetService("Players")
local needsowner = true
local bits = workspace.Bits:GetChildren()
	if needsowner then
		for _, part in pairs(bits) do
			if part:IsA("Part") then
		needsowner = false
Local Script
local bits = workspace.Bits:GetChildren()
local defaultY = workspace.Bits.DefaultY.Value
local startVec =,defaultY,0)

local cf ="BodyGyro")
cf.CFrame =,0,0)
cf.MaxTorque =,math.huge,math.huge)

local pos ="BodyPosition")
pos.MaxForce =,math.huge,math.huge)

local prevVec = startVec
for _, part in pairs(bits) do
	if part:IsA("Part") then
		local temp = pos:Clone()
		temp.Position = prevVec +,0,0)
		prevVec = temp.Position
		temp.Parent = part
		local temp2 = cf:Clone()
		temp2.Parent = part

function programBit(bit, on)
	if on==1 then
		bit.BodyPosition.Position =,defaultY+1,bit.Position.Z)	
		bit.BodyPosition.Position =,defaultY,bit.Position.Z)	

sampleByte = {0,0,0,1,0,1,1,1}
local function programByte(byte)
	for _, bit in pairs(bits) do
		local num = tonumber(bit.Name)
		if num then 
			programBit(bit,sampleByte[8-num]) -- because least significant bit is highest array index

local button = workspace.SpawnLocation.SurfaceGui.TextButton

I’ve done something like this in the past. It’s a pretty naive approach, but it’s a bit more complete than what Pharyx has done. (Rather than a bit per part, it’s a byte per part.) An interesting thought experiment for sure, but certainly not a practical one. Link to my implementation:


Thank you all, but i guess I’ll just have to stick with remote events after all

1 Like