Killing the lights for certain players

Hi, I’m trying to make it so that when a button is pressed, the lights are killed (by a remote event) for only players who have the tag, Contestant. How do i do that?

1 Like

Client:

  1. Set up a remote event that the client is listening to
  2. Use CollectionService or iteratively find all the lights that you want to dim and keep a record of them (or create this table on the fly if the lights are dynamic) e.g.:
local Lights = { }
for i, v in next, game.Workspace.EnvObjects:GetDescendants() do
if v:IsA 'PointLight' then
Lights[#Lights + 1] = v
end
end
  1. When the remote event of (1) is fired, set a variable flag e.g. local LightsOff = false, to true
  2. When the remote above fires, loop through each light in workspace and set the ‘Enabled’ property to false if the remote event fired to turn off lights, or to true if the remote event asks you to turn them on
  3. Have a listener on the client that checks when the player dies/respawns, if LightsOff variable is true then repeat the above, if not then do the opposite (in case it’s reset on death)

Server:

  1. Loop through the players, and check to see they have a tag (not sure what you mean by tag, if it’s an object check if it’s there using the :FindFirstChild() method, or if it’s internal just check if it’s true/false/whatever value you intend to use
  2. If they do have the tag/it’s the value that defines whether the lights are on/off, then :FireClient() the remote event I mentioned above and tell it to set the flag to true/false

Would recommend you add in some kind of check to determine whether the client turns lights on/off again if this is an important part of the gameplay because this would be easily exploitable.

2 Likes

I’m receiving an error saying the argument is nil. here s my for loop:

for i, v in pairs(game.Players:GetPlayers()) do
if v:FindFirstChild("Contestant") then
game.ReplicatedStorage.PowerEvent:FireClient()
end
end

You’ve not given any argument to :FireClient(), you need to at least pass the Player e.g. in your example:

for i, v in pairs(game.Players:GetPlayers()) do
if v:FindFirstChild("Contestant") then
game.ReplicatedStorage.PowerEvent:FireClient(v)
end
end

However, don’t forget you need to pass whether they need to turn it on / off as well, so:


for i, v in pairs(game.Players:GetPlayers()) do
if v:FindFirstChild("Contestant") then
game.ReplicatedStorage.PowerEvent:FireClient(v, true)
end
end

(The latter comment is assuming that you aren’t using a secondary remote to turn the lights back on)

i’m trying to fire this from a local script, what’s the other function instead of :FireClient() ?

I’d just like to state a few things, which might be useful to know.

  1. ipairs are used for arrays, GetDescendants() returns an array.

  2. Assigning GetDescendants() to a local variable before looping through will speed it up the next time you call it, as locals run much faster when called the second time (and further on).

Im using the FireServer with those parameters but it has the same result

The iteration function ipairs uses the next function to iterate.

Similarly, I iterated through the results of the method :GetDescendants() in that example because I don’t know OP’s hierarchy. He may not have all of the lights within one folder and that’s why you can note me checking the class of the descendants to add them to a table for later use, and why I don’t put the results of the :GetDescendants() method into memory as it may have objects we don’t need.

To the second point, if this is a static workspace (and not dynamic as I did question in my original post), there’s no need to assign that table to memory alongside the ‘Lights’ table as you would only need to call and iterate through the results of this method once if OP follows the steps I noted above.

Hope that explains why the above is written as it is!

@WooleyWool, can you post your script? Hard to debug without knowing what you’ve done :slight_smile:

for i, v in pairs(game.Players:GetPlayers()) do
if v:FindFirstChild("Contestant") then
game.ReplicatedStorage.PowerEvent:FireServer(v, true)
end
end

Is that the entire script? You would need to fire the script you sent above every single time you need to change the lights for those users since I’m assuming this is a round based game?

Similarly, what does the local script look like?

You should use ipairs over pairs. GetDescendants returns an array, ipairs runs quicker and it’s idiomatic for contiguous arrays.
pairs is designed more for a dictionary where your keys aren’t known (noting that it returns next).

It’s easy to just pick pairs to iterate over any table but that often is a product of not understanding ipairs or what’s going on behind a for loop.

ipairs is designed to iterate over the array part of a table at an incremental level (index i+1 per iteration). ipairs will also guarantee ordered iteration and terminate at the first hole in an array. ipairs also makes it clear that what you’re iterating over is an array.

pairs, on the other hand, is designed to iterate over the hash part of a table. pairs is slightly slower because the keys aren’t known to the generator at the start, so it calls next to find which key-value pair should be iterated over next.

LuaU optimisations sped both generators up by a large amount, however ipairs saw the greater increase as noted by some benchmarks at RDC 2019 for the Lua As Fast As Possible presentation.

I appreciate that you think you’re helping but this is just derailing OP’s thread? I can see this is obviously something your passionate about and I’m really glad as in some instances it could be crucial, but I’m not here asking for help, the OP is, and he/she’s asking for help with something completely unrelated.

I am more than aware of the performance implications of pairs, next and ipairs as there are many of you that seem to be very passionate about this, but unless detrimental to functionality I prefer next for syntax aesthetics.

Instead of replying to me, I would suggest that you provide OP with their solution and/or correct his/her’s use of pairs in their code - you might note I didn’t actually use it myself. Thank you for your concern though, but I think OP would appreciate it far more :slight_smile:

That’s the local script but it does have the colorcorrection in lighting for night vision. The script that’s in the map has all of the lights values and goes off (with a value of 0 for the range) for 10 seconds then reverts to its original value

I’m providing you with the information as you were the one using next over ipairs.
You don’t have to use it, that’s fine, however it’s just a suggestion for the future.

It makes more sense to reply to you as you were the one providing an example, rather than me mentioning ipairs out of the blue.

You’re going to have to give me a little more detail, right now I’m just guessing as to what you’re trying to do - as far as I can tell from what you’ve said, you have n number of contestants and when some event occurs you need to turn the lights off for those contestants? Similarly, not really sure what you mean with the light values? To add to what I said above, you can’t fire remote events to clients from a client. I was suggesting something like this:

--[!] ServerScriptService (Server Script)

-- local
local function create(obj)
	obj = Instance.new(obj)
	return function (props)
		local parent = props.Parent
		props.Parent = nil
		for prop, val in next, props do
			obj[prop] = val
		end
		obj.Parent = parent
		return obj
	end
end

-- main
local remote = create 'RemoteEvent' {
	Name   = 'lightSwitchRemote';
	Parent = game:GetService 'ReplicatedStorage';
}

-- example usage:
  --> when calling 'toggleLightsForContestants()' you need to pass it a true/false value
  --> true will turn off lights, false will turn lights off
  
  -- e.g. when some game-related flag BoolValue is set to 'true'
local function toggleLightsForContestants(var)
	for i, v in next, game.Players:GetPlayers() do
		if v:FindFirstChild 'Contestant' then
			remote:FireClient(v, var or true)
		end
	end
end

local flag = game:GetService('ServerStorage').GameStates.FlagEnabled
flag:GetPropertyChangedSignal('Value'):Connect(function ()
	toggleLightsForContestants(flag.Value)
end)

-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------


--[!] PlayerScript (LocalScript)
local player 	= game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local remote    = game:GetService('ReplicatedStorage'):WaitForChild 'lightSwitchRemote'

local lightEnv = game.Workspace --> Can change this if you put all lights into a singular folder
local lights   = { }
local lightsOn = true

local function collectLights(reset) --> Can be used in future if you have dynamic instantiation of lights
	lights = reset and { } or lights
	for i, v in next, lightEnv:GetDescendants() do
		if v:IsA 'Light' then --> add whatever other checks you need to so that you can ensure it's the lights you want to toggle
			lights[#lights + 1] = v
		end
	end
end

remote.OnClientEvent:connect(function (var)
	if type(var) == 'boolean' then
		if lightsOn ~= var then
			lightsOn = var
			for i, v in next, lights do
				v.Enabled = lightsOn
			end
		end
	end
end)

player.CharacterAdded:connect(function ()
	if #lights > 0 and lights[1] then
		if lights[1].Enabled ~= lightsOn then
			for i, v in next, lights do
				v.Enabled = lightsOn
			end
		end
	end
end)

I have two scripts, a Local script and a normal script. The normal script waits for the event fire and once it’s fired, it’ll set the range for all of the lights to 0. The local script waits until the button is pressed to fire.

(I am a noob scripter but try this)

You would have to type this

function checkTags(player)  -- making a function this could be anything like local function or mouseClick function or anything else
if player:FindFirstChild("Contestant") then -- checking if the player has that tag
-- type the other scripts. Really sorry because I don't know that. As I said I am a noob scripter

end
1 Like