How to get client-client

I want to have a door open on all clients end when a single player is near said door. At first I thought Bindable’s then remembered they are only for your client. But I don’t want to use a remote event as that would then force me to do client-server-client which has delays and what not.

-- Client code
-- Check players and their distance to doors --
coroutine.wrap(function()
	while true do
		local Character = Player.Character
		if Character then				
			-- Check for closest interaction
			for _, door in pairs(CollectionService:GetTagged('Doors')) do
				if door.PrimaryPart and door then
					-- See if door is within range
					if Player:DistanceFromCharacter(door.PrimaryPart.Position) <= ReachDistance then
						-- Open door						
						OpenDoor:Fire(door)
					else
						-- Close door
						CloseDoor:Fire(door)
					end
				end
			end
		end
		
		wait()
	end
end)()

If you want it to open for all clients you need to use a remote event.

You can still use a remote as you can use the function :FireAllClients(params) which will affect all clients.

1 Like

Ye but the reason I don’t want to use that is because of delay. Firing from client-server then server-allclients will take a noticeable time to act

A potential solution could be checking on the server (Might not be a good idea) and update a value then on client when the value is updated, open or close the door accordingly.

nope, you’re forced to send any kind of information thru server

client-to-client behavior was exactly what non-filtering enabled was about, and this leads to a massive amount of exploits possible, and i don’t think there is a exception to that nowadays.

there might be ways to transfer the information faster than ever, but i do not know of it.
i will let the elite answer it further.

EDIT : It would be possible to do a local check on all players, so it bypass the server, “however”, the information about a character also comes by the server, so you might have to make a position prediction to open the door (if via magnitude/ray)

1 Like

You can either do what @tobias6262 said or maybe check magnitude from that door for each client but that would be a little heavier on the performance (you can have little delay like .1-.5between checks, and due to magnitude not being that exspensive it can be done)

Hey !

You could still loop throught all players instance by using
local Players = game:GetService("Players") Players:GetChildren()

And then, check the distance of each character, if the distance is <= ReachDistance then you open the door ( don’t forget the check if the door is already open too ^^ )
There still might have a little delay with the player position, but that would solve the way of non using a remote event.

I think you can do it by like this, client to server, server to all clients.
And why you aren’t using Remote Events?
Basiclly this;

FireServer()
FireAllClients()

You can not go client-to-client for security reason on Roblox.
Reasons are:
Preventing Exploits.
Filtering.
Etc.

I recommend you use a server script to transfer the data over to another script.

Problem I have with that is if 2 players are near the door, and 1 player walks away, the door closes and stays closed, even if the other player is still within range of the door

-- Check players and their distance to doors --
coroutine.wrap(function()
	while true do
		for _, player in pairs(Players:GetPlayers()) do
			local Character = player.Character
			if Character then				
				-- Check for closest interaction
				for _, door in pairs(CollectionService:GetTagged('Doors')) do
					if door.PrimaryPart and door then
						-- See if door is within range
						if player:DistanceFromCharacter(door.PrimaryPart.Position) <= ReachDistance then
							-- Open door						
							Open(door)
						else
							-- Close door
							Close(door)
						end
					end
				end
			end
		end
		
		wait()
	end
end)()

Since you are already polling through all the players, all you need to do is to remember how many characters are near that door, and only close them when the said number equals zero.

coroutine.wrap(function()
	local PreviousOpenDoors = {}
	while true do
		local CurrentCharNearDoors = {}
		for _, player in pairs(Players:GetPlayers()) do
			local Character = player.Character
			if Character then				
				-- Check for closest interaction
				for _, door in pairs(CollectionService:GetTagged('Doors')) do
					if door.PrimaryPart and door then
						if not CurrenCharNearDoors[door] then
							CurrenCharNearDoors[door] = 0
						end
						-- See if door is within range
						if player:DistanceFromCharacter(door.PrimaryPart.Position) <= ReachDistance then
							CurrentCharNearDoors[door] = CurrentCharNearDoors[door] + 1
						end
					end
				end
			end
		end
		for door, chars in pairs(CurrentCharNearDoors) do
			if not PreviousOpenDoors[door]  and chars > 0 then
				Open(door)
				PreviousOpenDoors[door] = true
			elseif PreviousOpenDoors[door] and chars == 0 then
				Close(door)
				PreviousOpenDoors[door] = nil
			end
		end

		wait()
	end
end)()

That being said this method is quite inefficient. You should avoid polling whenever you can. I would use Touched event on special invisible activation plate to open the doors. Once the door is opened, simple periodic magnitude check on all players is usually best method to close the doors.

1 Like

What do you mean by ‘polling’?

First of all sorry for late reply. Polling means synchronous sampling of certain values. In Roblox it is usually used to sample character position, as player movements cannot be easily predicted. For example I use it as anti-teleport exploit and anti speed hacks.

Polling however has a huge impact on performance, especially if you connect it to run service or use short intervals between polls (like wait() which is approx. 0.03 sec in perfect conditions). If that is your only polling script in the game, you may get away with it. But in larger games, with lots of players and doors you may start to notice lag. Introduce similar scripts for other parts of your world, and the whole thing will eventually break apart.

That is why I have suggested Touched event. If you have lots of doors and players, it will reduce significantly workload on the server. There are however issues with ToucheEnded event, that I will not indulge in right now. Long story short, I use hybrid system of polling and Touched events. In this system polling is only done after “doors” have opened, and for each door separately.

Here is an example script. You need to create invisible, anchored and non-collidable part that will cover the floor area where you want to have door opened triggered. It will work as a sensor. Once the door will open, a polling function will start detecting nearby players. If all players are away from doors, door will shut and reactivate the sensor. Notice that polling intervals do not need to be short, as players will not notice the delay in this case.

Parent this script and created sensor to a door.

local door = script.Parent
local sensor = door:FindFirstChild("Sensor")
local connection


local function OnTouch(hit)
	local root = hit.Parent:FindFirstChild("HumanoidRootPart")
	if not root then
		return --ignore all signals from non-humanoids
	end
	--next is optional - ignore NPC. Not needed if you do not have wandering NPCs in the game
	if not Players:GetPlayerFromCharcter(hit.Parent) then
		return
	end
	connection:Disconnect()
	Open(door)
	local foundSomeone = true
	while foundSomeone do
		wait(1) --1 second interval is usually good enough, but feel free to adjust
		foundSomeone = false
		for _, player in pairs(Player:GetPlayers()) do
			if player.Character then
				local thisRoot = player.Character:FindFirstChild("HumanoidRootPart")
				if thisRoot then
					if (thisRoot.Position - door.Position).Magnitude < ReachDistance then
						foundSomeone = true
					end
				end
			end
		end
	end
	Close(door)
	connection = sensor.Touched:Connect(OnTouch)
end
connection = sensor.Touched:Connect(OnTouch)

Parenting this script to the doors, could mean that you will need a BindableEvent to fire when opening/closing the doors. For example Open:Fire(door). Or use module script: local Open = require(game.ServerScriptService.Open).

1 Like