Physics replication affecting every client's locally scripted parts - trying to find workaround

Okay! For future readers - I’ve got a local script that puts it all together and is working. It tracks players, sets player parts to client-specific collision groups, and sets them again if those parts stream out and back in (which causes them to otherwise go back in the Default collision group) or whenever a player dies and gets a new character.

The prerequisite is that you create collision groups in studio first, called ClientCharacter and OtherCharacters, and set it so neither can collide with itself or the other.

The whole point of this is so each client can have its own client-only collision groups, for the local player and All Other Players, which can be used to prevent non-local players’ simulated physics affecting certain objects on the client. (e.g. client-generated primsatically constrained platforms, in my case.) by stopping other players colliding with them.

You also have to make sure ClientCharacter can collide with whatever the parts in question are in your game, and that OtherCharacters cannot.

Whew…

local Players = game:GetService("Players")
local Client = Players.LocalPlayer

local trackingConnections = {}

local function onInstanceRemoved(object)
	if trackingConnections[object] then
		trackingConnections[object]:Disconnect()
		trackingConnections[object] = nil
	end
end



-- Note player is only ever added once. Character will be replaced on player whenever player dies. 
local function HandleCharacter(Player, Character)
	print("HANDLING RUNNING FOR ",Player)
	local Group = if Player == Client then "ClientCharacter" else "OtherCharacters"
	for _, Object in Character:GetChildren() do
		if Object:IsA("BasePart") then
			Object.CollisionGroup = Group
			print(Object, "initially tagged as ",Group)
		end
	end
end


local function trackCharacterChildren(Player, Character)
	local Group = if Player == Client then "ClientCharacter" else "OtherCharacters"
	
	trackingConnections[Player] = Character.ChildAdded:Connect(function(Child)
		if Child:IsA("BasePart") then
			Child.CollisionGroup = Group
			print(Child, "added to ",Player," and tagged as ",Group)
		end
	end)
end


local function trackPlayer(Player, Character)
	HandleCharacter(Player, Character) -- tag its parts with appropriate Collision Group
	trackCharacterChildren(Player, Character) -- track future children
end

local function HandleJoined(Player)
	local Character = Player.Character or Player.CharacterAdded:Wait() -- wait to get character
	trackPlayer(Player, Character)
	
	Player.CharacterAdded:Connect(function(Character)
		trackPlayer(Player, Character)
	end)
	
end


local function onCharacterRemoving(character) -- Despawn fires when a player dies (at end of their death wait) AND
	--	if they leave the game. It doesn't fire if the player is streamed out for being out of range of local player.
	
	print(character.Name .. " is despawning")
	local characterNowGone = Players:GetPlayerFromCharacter(character)
	onInstanceRemoved(characterNowGone)
end



for _, Player in Players:GetChildren() do
	HandleJoined(Player)
end

-- This next event happens once when a player joins. it doesn't fire again if they respawn or stream out and in.
Players.PlayerAdded:Connect(HandleJoined)

Rinpix and IDoLua’s code and suggestions got me here.

If anyone can see easy improvements to be made to this code, feel free to chime in. On the plus side, it’s already working.

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