Creating a "Traffic Light" for multiple scripts

I have 3 scripts that do 1 thing in common: they give tools to a player.
problem is, when you are the place owner, all those scripts activate at once.
this is what happens to me, and I feel like having a cluttered inventory with so many duplicates of the same gear over and over again is completly disorganized and messy. so I thought of creating a “Traffic Light” to control which script that is most important to be the only one that runs, but I dont know how to create something like this.

ServerScripts
  • OwnerOnlyGears
    • The Main Script. purpose is to give me every tool in ServerStorage
  • AssetGearGiver
    • purpose is to give the player a tool if they have a certain asset
  • GamePassGearGiver
    • purpose is to give the player a tool if they own a gamepass
Diagram

ive tried to create a thing that if one tool is already given to the player, that it wont give another duplicate of it Mostly because mostly all of them have the same tool inside of it, but it didnt work because they all detect at the same time and still give me duplicates.

2 Likes

From your post, I’m coming to the conclusion that you are dealing with a race condition. You have multiple scripts accessing let’s say “player” at once and checking if it has an item and adds it if it doesn’t at the same time. What I recommend is having a module script that keeps track of players. When one of these scripts tries to do something with the player, it should lock the player with a table value like locked = true. This allows you in the other scripts to check if the player is locked and go into a while loop until it is unlocked to continue. Since what I heard from this is that the scripts only run once, it shouldn’t be a big deal to performance.

Here is an example of a module script that would be shared between the scripts.

local players = {}

return players;

In the main scripts, you can use

local players = require(ModuleScriptLocation)
if players[playerID] == nil then
players[playerID] = {locked = false};
end

while players[PlayerID].locked do
wait(500)
end

if players[PlayerID].locked == false then
   players[PlayerID].locked = true;
   -- Check for duplicates / give items
   players[PlayerID].locked = false;
end

Consider the code I give as pseudo code since I didn’t test it and some syntax may not be 100% correct. I provided some code to get the idea of what I suggested. More about racing conditions can be found here: Race condition - Wikipedia

Another suggestion that may be simpler is combing the three scripts into one so they are forced to run in sequential order. My post may not be 100% correct so if anyone sees errors, please reply to this.

do i need this in only one script, since im assuming this is supposed to create PlayerID?

The reason I put that in all the scripts is because I don’t know which script runs first and so this allows it to be created in any of them. Though I’m thinking about maybe having one script that catches the player joined and then triggering the other three scripts in someway. There are many ways to handle this.

added it to every script, i find errors that say that the table index is nil.

As well, can you post your existing code. Tbh the one big script may be better for this purpose since it avoids the race condition.

ModuleLock(the ModuleScript)
local players = {}

return players

OwnerOnlyGears(Main Script)
local playersMod = require(script.Parent.Parent.ModuleLock)
local players = {"Drewel112233"}
local gears = game.ServerStorage:GetChildren()
local mps = game:GetService("MarketplaceService")
local scriptParent = script.Parent
local scriptChild = script
--[[local boolValue = scriptParent:FindFirstChild("ValueChange")

if scriptParent.ValueChose.Value == true then
	scriptChild.Disabled = false
else
	scriptChild.Disabled = true
end ]]--
if playersMod[playerID] == nil then
playersMod[playerID] = {locked = false}
end

while playersMod[playerID].locked do
	wait(500)
end

game.Players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:Connect(function(chr)
		for i = 1, #players do
			if players[i] == plr.Name then
				for i = 1, #gears do
					if gears[i]:IsA("Tool") then
						if playersMod[playerID].locked == false then
							playersMod[playerID].locked = true
							gears[i]:Clone().Parent = plr:WaitForChild("Backpack")
							playersMod[playerID].locked = false
					end
				end
			end
		end
		end
	end)
end)

AssetGears
local playersMod = require(script.Parent.Parent.ModuleLock)
local ASSET_ID = 4562719333
local ASSET_NAME = "Blue Letter D"
local scriptParent = script.Parent
local scriptChild = script
     
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
local PlayerOwnsAsset = MarketplaceService.PlayerOwnsAsset
local specialPlayers = {"Drewel12233"}
--[[local boolValue = scriptParent:FindFirstChild("ValueChange")

if scriptParent.ValueChose.Value == true then
	scriptChild.Disabled = false
else
	scriptChild.Disabled = true
end --]]
--[[if playersMod[playerID] == nil then
playersMod[playerID] = {locked = false}
end]]--

while playersMod[playerID].locked do
	wait(500)
end
     
Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(chr)
		--[[for i = 1, #specialPlayers do
			if specialPlayers[i] ~= player.Name then
				local backpack = player.Backpack
				local gear = backpack:FindFirstChild("OwnerStaff")]]--
    			local success, doesPlayerOwnAsset = pcall(PlayerOwnsAsset, MarketplaceService, player, ASSET_ID)
				
					if doesPlayerOwnAsset then
						if playersMod[playerID].locked == false then
							playersMod[playerID].locked = true
						game.ServerStorage.Ownerstaff:Clone().Parent = player.Backpack
						game.ServerStorage.Ownerstaff:Clone().Parent = player.StarterGear
						print("added staff")
						playersMod[playerID].locked = false
					end
    				else
    					print(player.Name .. " doesn't qualify")
    				end
	
	end)
end)


GamepassGears
local playersMod = require(script.Parent.Parent.ModuleLock)
local mps = game:GetService("MarketplaceService")
local gamepass_id = 7964223
local tshirt_id = 4562719333
local plrs = game:GetService("Players")
local specialPlayers = {"Drewel12233"}
local scriptParent = script.Parent
local scriptChild = script
--[[local boolValue = scriptParent:FindFirstChild("ValueChange")

if scriptParent.ValueChose.Value == true then
	scriptChild.Disabled = false
else
	scriptChild.Disabled = true
end --]]
--[[if playersMod[playerID] == nil then
playersMod[playerID] = {locked = false}
end]]--

while playersMod[playerID].locked do
	wait(500)
end

game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(chr)
					if mps:UserOwnsGamePassAsync(player.UserId , gamepass_id) then
						if playersMod[playerID].locked == false then
							playersMod[playerID].locked = true
							game.ServerStorage.Speed:Clone().Parent = player.Backpack
							game.ServerStorage.Speed:Clone().Parent = player.StarterGear
							print("added gear")
							playersMod[playerID].locked = false
						end
					else
						warn("couldnt confirm if true")
					end
		
	end)
end)

--game.ReplicatedStorage.Give.OnServerEvent:connect(function()
	--game.ServerStorage.Speed:Clone().Parent = player.Backpack
	--game.ServerStorage.Speed:Clone().Parent = player.StarterGear
--end)

Try adding waits on the scripts, like
On the asset gear script, add a wait(3) and the gamepass wait(2) and dont add a wait on the owner gear script. You would do something like this

If owner then
  if owner.Backpack:FindFirstChild("nameoftool") == nil then
    game.serverstorage.nameoftool:Clone().Parent = owner.backpack

im also getting errors saying attempt to index nil with 'locked', table index is nil, and attempt to index nil with nil(last one is from a script i put in the ModuleScript, wondering if that might do something)
and playersMod[playerID] is underlined blue in every script.

i also dont know how ModuleScripts work entirely, and i dont know how to do shared data reads between scripts using them.

i also tried adding

if players[playerID] == nil then
players[playerID] = {locked = false}
end

inside the ModuleScript and it didnt work.