Player is in table, but table.Find() returns nil

` I am trying to program a function which detects if a player is in a region3. If the player is in the region3, it fires one event, but if the player is not in the region3, it fires a different event. This works by making a table of all of the players inside of the region and finding out which players aren’t on the list. By far it has worked consistently for one player, but once multiple players are involved it starts saying that the player is both inside of the table and not inside of it?

` This is a strange bug. I’ve even tried making my own iteration function and it still will not work properly.

Untitled
In the screenshot it shows that Player1 and Player2 are clearly both in the list, but right below it says that Player 2 is not in the region. Here is the code I wrote:

local PlayEvent = game.ReplicatedStorage:FindFirstChild('MusicEvent') --Defining events
local StopEvent = game.ReplicatedStorage:FindFirstChild('StopEvent')

-- The values for the region3
local Zone = game.Workspace.MusicZones.Zone1
local min = Vector3.new(Zone.Position.X-Zone.Size.X/2, Zone.Position.Y-Zone.Size.Y/2, Zone.Position.Z-Zone.Size.Z/2)
local max= Vector3.new(Zone.Position.X+Zone.Size.X/2, Zone.Position.Y+Zone.Size.Y/2, Zone.Position.Z+Zone.Size.Z/2)
local region = Region3.new(min,max)

-- This was the iteration function I used before. I'm not currently using it but it's here for reference
local function Contains(Table, Value)
	for i, v in pairs(Table) do
		if v.Name == Value.Name then
			return true
		end
	end
end

-- Main loop 
while wait(0.5) do
	local min = Zone.Position - Zone.Size*.5 -- Getting the size of the zone
	local max = Zone.Position + Zone.Size*.5 -- Getting the size of the zone
	local partInRegion = workspace:FindPartsInRegion3(region, nil, math.huge) --Find the parts
	local playersInRegion3 = {}
	for _, part in pairs(partInRegion) do
		if part.Parent:FindFirstChild("Humanoid") ~= nil then
			local plr = game.Players:FindFirstChild(part.Parent.Name)
			if not table.find(playersInRegion3,plr) then
				PlayEvent:FireClient(plr,Zone.Music)
			end
			table.insert(playersInRegion3,plr)--putting the player in the table
		end
	end
	for _, Player in pairs(game.Players:GetChildren()) do
		if table.find(playersInRegion3, Player) == nil then --checking if player is not in the table
			print(Player.Name.." is not in region3")
			StopEvent:FireClient(Player)
		end
		print(playersInRegion3)
		playersInRegion3 = {} --resetting the table after every loop
	end
end

1 Like

Isn’t this what GetPlayerFromCharacter is for? It might fix your issue.

That adds to the code readability (Idk why I didn’t think of using it at the time lol) but it ultimately does the same thing as my original buggy code.

You can try playersInRegion3[plr] = true, playersInRegion3[plr] = nil, and playersInRegion3[plr] = false instead of table.find/insert.

So from what I see, you seem to be inserting the player for each part in the region, which is all the parts in the player. Why don’t you filter for HumanoidRootParts and also check if an instance of the same player is in the table? Like:

if part.Name == "HumanoidRootPart" and part.Parent:FindFirstChild("Humanoid") then 
  --Do stuff
end

Aka only doing one insert, because there’s only one HumanoidRootPart.

local PlayEvent = game.ReplicatedStorage:FindFirstChild('MusicEvent') --Defining events
local StopEvent = game.ReplicatedStorage:FindFirstChild('StopEvent')

-- The values for the region3
local Zone = game.Workspace.MusicZones.Zone1
local min = Vector3.new(Zone.Position.X-Zone.Size.X/2, Zone.Position.Y-Zone.Size.Y/2, Zone.Position.Z-Zone.Size.Z/2)
local max= Vector3.new(Zone.Position.X+Zone.Size.X/2, Zone.Position.Y+Zone.Size.Y/2, Zone.Position.Z+Zone.Size.Z/2)
local region = Region3.new(min,max)

-- This was the iteration function I used before. I'm not currently using it but it's here for reference
local function Contains(Table, Value)
	for i, v in pairs(Table) do
		if v.Name == Value.Name then
			return true
		end
	end
end

-- Main loop 
while wait(0.5) do
	local min = Zone.Position - Zone.Size*.5 -- Getting the size of the zone
	local max = Zone.Position + Zone.Size*.5 -- Getting the size of the zone
	local partInRegion = workspace:FindPartsInRegion3(region, nil, math.huge) --Find the parts
	local playersInRegion3 = {}
	for _, part in pairs(partInRegion) do
		if part.Name == "HumanoidRootPart" and part.Parent:FindFirstChild("Humanoid")  then
			local plr = game.Players:FindFirstChild(part.Parent.Name)
			if not table.find(playersInRegion3,plr.Name) then
				PlayEvent:FireClient(plr,Zone.Music)
			end
			table.insert(playersInRegion3,plr.Name)--putting the player in the table
		end
	end
	for _, Player in pairs(game.Players:GetChildren()) do
		if table.find(playersInRegion3, Player.Name) == nil then --checking if player is not in the table
			print(Player.Name.." is not in region3")
			StopEvent:FireClient(Player)
		end
		print(playersInRegion3)
		playersInRegion3 = {} --resetting the table after every loop
	end
end

Adding on. You seem to be inserting Instances into the table, which does work, but those instances might change some of the time which makes doing Player.Name a bit better. Try that.

I would do UserId instead of Name honestly, but still helpful for Ethaniel2004.

3 Likes
local PlayEvent = game.ReplicatedStorage:FindFirstChild('MusicEvent') --Defining events
local StopEvent = game.ReplicatedStorage:FindFirstChild('StopEvent')

-- The values for the region3
local Zone = game.Workspace.MusicZones.Zone1
local min = Vector3.new(Zone.Position.X-Zone.Size.X/2, Zone.Position.Y-Zone.Size.Y/2, Zone.Position.Z-Zone.Size.Z/2)
local max= Vector3.new(Zone.Position.X+Zone.Size.X/2, Zone.Position.Y+Zone.Size.Y/2, Zone.Position.Z+Zone.Size.Z/2)
local region = Region3.new(min,max)

-- This was the iteration function I used before. I'm not currently using it but it's here for reference
local function Contains(Table, Value)
	for i, v in pairs(Table) do
		if v.Name == Value.Name then
			return true
		end
	end
end

-- Main loop 
while wait(0.5) do
	local min = Zone.Position - Zone.Size*.5 -- Getting the size of the zone
	local max = Zone.Position + Zone.Size*.5 -- Getting the size of the zone
	local partInRegion = workspace:FindPartsInRegion3(region, nil, math.huge) --Find the parts
	local playersInRegion3 = {}
	for _, part in pairs(partInRegion) do
		if part.Name == "HumanoidRootPart" and part.Parent:FindFirstChild("Humanoid")  then
			local plr = game.Players:GetPlayerFromCharacter(part.Parent)
			if not playersInRegion3["ID"..plr.UserId] then
				PlayEvent:FireClient(plr,Zone.Music)
			end
			playersInRegion3[#playersInRegion3 + 1] = "ID"..plr.UserId --putting the player in the table
		end
	end
	for _, Player in pairs(game.Players:GetChildren()) do
		print(playersInRegion3["ID"..Player.UserId])
		if playersInRegion3["ID"..Player.UserId] == nil then --checking if player is not in the table
			print(Player.Name.." is not in region3")
			StopEvent:FireClient(Player)
		end
		print(playersInRegion3)
		playersInRegion3 = {} --resetting the table after every loop
	end
end

I tried doing this and playersInRegion3[“ID”…Player.UserId] returns as nil. For some reason this made both events fire. I appended the ID onto that because I believe if it was just the userId it would try to find the item at that index.

So I tested this, and this does not work, but table.Find does.
Here’s my testing code so you can replicate.

local Thing = {} Thing[#Thing+1] = "Hello" print(table.find(Thing,"Hello")) --This works
local Thing = {} Thing[#Thing+1] = "Hello" print(Thing("Hello")) --This does not

the first prints “1”, which is the position within the table.
The other prints nil.

Use table.Find:

if not table.Find(playersInRegion3["ID"..plr.UserId] then
  --Do stuff
end
local PlayEvent = game.ReplicatedStorage:FindFirstChild('MusicEvent') --Defining events
local StopEvent = game.ReplicatedStorage:FindFirstChild('StopEvent')

-- The values for the region3
local Zone = game.Workspace.MusicZones.Zone1
local min = Vector3.new(Zone.Position.X-Zone.Size.X/2, Zone.Position.Y-Zone.Size.Y/2, Zone.Position.Z-Zone.Size.Z/2)
local max= Vector3.new(Zone.Position.X+Zone.Size.X/2, Zone.Position.Y+Zone.Size.Y/2, Zone.Position.Z+Zone.Size.Z/2)
local region = Region3.new(min,max)

-- This was the iteration function I used before. I'm not currently using it but it's here for reference
local function Contains(Table, Value)
	for i, v in pairs(Table) do
		if v.Name == Value.Name then
			return true
		end
	end
end

-- Main loop 
while wait(0.5) do
	local min = Zone.Position - Zone.Size*.5 -- Getting the size of the zone
	local max = Zone.Position + Zone.Size*.5 -- Getting the size of the zone
	local partInRegion = workspace:FindPartsInRegion3(region, nil, math.huge) --Find the parts
	local playersInRegion3 = {}
	for _, part in pairs(partInRegion) do
		if part.Name == "HumanoidRootPart" and part.Parent:FindFirstChild("Humanoid")  then
			local plr = game.Players:GetPlayerFromCharacter(part.Parent)
			if not table.find(playersInRegion3,"ID"..plr.UserId) then
				PlayEvent:FireClient(plr,Zone.Music)
			end
			playersInRegion3[#playersInRegion3 + 1] = "ID"..plr.UserId --putting the player in the table
		end
	end
	for _, Player in pairs(game.Players:GetChildren()) do
		print(table.find(playersInRegion3,"ID"..Player.UserId))
		if table.find(playersInRegion3,"ID"..Player.UserId) == nil then --checking if player is not in the table
			print(Player.Name.." is not in region3")
			StopEvent:FireClient(Player)
		end
		print(playersInRegion3)
		playersInRegion3 = {} --resetting the table after every loop
	end
end

Revised the code. Once again this works, but only when one client is involved. Whenever I try it with multiple clients I get strange results where both players’ UserIds are on the table but only the first client functions correctly. The second client receives both events simultaneously which cancels out the effect.

I think. NOT SURE that you made a mistake resetting the table.
If you put:

		playersInRegion3 = {} --resetting the table after every loop

outside of the for loop. Does that work? And which event is firing?

Now that I look at that it’s completely unnecessary to have that in the code, the same thing is done right above it! I expected it to break the program but it works like a charm. Thanks for the help bro.

Here is the final code if anybody wanted to reference this. I’m using it to play/ stop ambient sound effects in the region3. All you need to get it to work is just hook up some local scripts to the events and it should work perfectly.

local PlayEvent = game.ReplicatedStorage:FindFirstChild('MusicEvent') --Defining events
local StopEvent = game.ReplicatedStorage:FindFirstChild('StopEvent')

-- The values for the region3
local Zone = game.Workspace.MusicZones.Zone1
local min = Vector3.new(Zone.Position.X-Zone.Size.X/2, Zone.Position.Y-Zone.Size.Y/2, Zone.Position.Z-Zone.Size.Z/2)
local max= Vector3.new(Zone.Position.X+Zone.Size.X/2, Zone.Position.Y+Zone.Size.Y/2, Zone.Position.Z+Zone.Size.Z/2)
local region = Region3.new(min,max)

-- This was the iteration function I used before. I'm not currently using it but it's here for reference
local function Contains(Table, Value)
	for i, v in pairs(Table) do
		if v.Name == Value.Name then
			return true
		end
	end
end

-- Main loop 
while wait(0.5) do
	local min = Zone.Position - Zone.Size*.5 -- Getting the size of the zone
	local max = Zone.Position + Zone.Size*.5 -- Getting the size of the zone
	local partInRegion = workspace:FindPartsInRegion3(region, nil, math.huge) --Find the parts
	local playersInRegion3 = {}
	for _, part in pairs(partInRegion) do
		if part.Name == "HumanoidRootPart" and part.Parent:FindFirstChild("Humanoid")  then
			local plr = game.Players:GetPlayerFromCharacter(part.Parent)
			if not table.find(playersInRegion3,"ID"..plr.UserId) then
				PlayEvent:FireClient(plr,Zone.Music)
			end
			playersInRegion3[#playersInRegion3 + 1] = "ID"..plr.UserId --putting the player in the table
		end
	end
	for _, Player in pairs(game.Players:GetChildren()) do
		print(table.find(playersInRegion3,"ID"..Player.UserId))
		if table.find(playersInRegion3,"ID"..Player.UserId) == nil then --checking if player is not in the table
			print(Player.Name.." is not in region3")
			StopEvent:FireClient(Player)
		end
		print(playersInRegion3)
		--playersInRegion3 = {} --resetting the table after every loop
	end
end

1 Like