How can I know when a game starts instead of using 'waits'

Hello everyone, recently one of my script broke when I was testing in Roblox itself instead of Roblox studio. I don’t know if it’s because Roblox runs faster than Roblox studio or something. Basically, my game has a round generating system, and in the script I fire a remote event to the client to change some Ui’s, but in the first round for some weird reasons it doesn’t pick up the remote event, like it literally doesn’t fire it. :confused:

here is the script, how can I run it accordingly to the player when he joins, so it can run the remote event?

local level = game.ReplicatedStorage:WaitForChild("GeneratedLevels"):GetChildren()
local studs = 0
local endLevel = game.ReplicatedStorage.End

local ColorTable = {}

while true do
	wait()
	local ColorTable = {}
	local SizeTable = {}
	for count = 1, 6 do
		for i, placeHolder in pairs(game.Workspace.PlaceHolders:GetChildren()) do
			local chosenLevel = level[math.random(1, #level)]:Clone()
			print(chosenLevel.Name)
			table.insert(SizeTable, UDim2.new(chosenLevel.SizeInfo.Size.Value,chosenLevel.SizeInfo.Size2.Value,chosenLevel.SizeInfo.Size3.Value,chosenLevel.SizeInfo.Size4.Value))
			table.insert(ColorTable, Color3.new(chosenLevel.ColorBar.Value/250,chosenLevel.ColorBar2.Value/250,chosenLevel.ColorBar3.Value/250))
			chosenLevel.PrimaryPart = chosenLevel.Floor
			chosenLevel:SetPrimaryPartCFrame(CFrame.new(placeHolder.Position)+ Vector3.new(studs, 0, 0))
			studs = studs - chosenLevel.studs.Value

			chosenLevel.Parent = game.Workspace.currentLevels
		end
	end

	local endLevelClone = endLevel:Clone()
	endLevelClone.PrimaryPart = endLevelClone.Floor
	endLevelClone:SetPrimaryPartCFrame(CFrame.new(game.Workspace.PlaceHolders.Floor.Position)+ Vector3.new(studs, 0, 0))
	endLevelClone.Parent = game.Workspace.currentLevels	
	print("Be savage")
	game.ReplicatedStorage.SideBar.GiveColoursToClient:FireAllClients(ColorTable, SizeTable)


	local minutes = 6
	local seconds = 0

	local minutesVal = game.ReplicatedStorage:WaitForChild("TimerVal"):WaitForChild("minutesVal")
	minutesVal.Value = minutes

	local secondsVal = game.ReplicatedStorage:WaitForChild("TimerVal"):WaitForChild("secondsVal")
	secondsVal.Value = seconds

	local timer = game.ReplicatedStorage.Timer


	repeat
		if seconds <= 0 and secondsVal.Value <= 0 then
			minutes = minutes - 1
			seconds = 59

			minutesVal.Value = minutesVal.Value - 1
			secondsVal.Value = 59
		else
			seconds = seconds - 1
			secondsVal.Value = secondsVal.Value - 1
		end

		if seconds <= 9 then

			timer.Value = tostring(minutes)..":0"..tostring(seconds) else

			timer.Value = tostring(minutes)..":"..tostring(seconds)
		end

		wait(game.Workspace.Values.WaitSpeed.Value)

	until minutes <= 0 and seconds <= 0

	if minutes <= 0 and seconds <= 0 then		
		-- Claimed Value
		for _, player in ipairs(game:GetService("Players"):GetPlayers()) do
			if (player) then
				player.ClaimedFolder.Claimed.Value = false
			end
		end
		-- Rep Values for local Buttons
		game.ReplicatedStorage.ShopEvents.LocalButtons.invisibilityButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.BunnyHopButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.FogButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.HighSpeedButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.LowGravityButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.invincibilityButton.Value = false

		-- Bought Values
		script.Parent.ShopItems.BunnyHopFolder.bought.Value = false
		script.Parent.ShopItems.invisivilityFolder.bought.Value = false
		script.Parent.ShopItems.FogFolder.bought.Value = false
		script.Parent.ShopItems.LowGravityFolder.bought.Value = false
		script.Parent.ShopItems.HighSpeedFolder.bought.Value = false
		script.Parent.ShopItems.invincibilityFolder.bought.Value = false
		-- Enabled Value example(BunnyHopEnabled)
		script.Parent.ShopItems.BunnyHopFolder.BunnyHopEnabled.Value = false
		script.Parent.ShopItems.invisivilityFolder.InvisibilityEnabled.Value = false
		script.Parent.ShopItems.FogFolder.FogEnabled.Value = false
		script.Parent.ShopItems.LowGravityFolder.LowGravityEnabled.Value = false
		script.Parent.ShopItems.HighSpeedFolder.HighSpeedEnabled.Value = false
		script.Parent.ShopItems.invincibilityFolder.invincibilityEnabled.Value = false
		-- Fog Back to normal ;)
		game.Lighting.FogEnd = 100000
		game.Lighting.FogStart = 0
		game.Lighting.OutdoorAmbient = Color3.fromRGB(128, 128, 128)
		-- Gravity Back to normal ;)
		game.Workspace.Gravity = 196.2
	end

	for i, player in pairs(game.Players:GetChildren())do
		player:LoadCharacter()
		wait(.1)
		player:LoadCharacter()
	end

	game.Workspace.Values.WaitSpeed.Value = 1
	game.Workspace.Values.SpeedMultiplier.Value = 1	


	game.Workspace.currentLevels:ClearAllChildren()
	studs = 0 

end

Thank you, everyone, for helping me in advance :sweat_smile:

1 Like

I have tried ‘RunService.Heartbeat’ but for some reasons rept spaming remote events? :confused:

You could use game.Players.PlayerAdded to check when a player joins the game. Now, RunService.Heartbeat on the other hand, runs every single frame (every 1/30th or 1/60th of a second or so).

Something like this:

-- Services
local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player))
    -- Do whatever you want/need
end
1 Like

I tried it out recently, but each time a new player joins it fires the remote event so, it wont work sadly, but thx for trying :sweat_smile:

Well instead of using FireAllClients() you can use FireClient(player), firing to that single client that joined instead. Though, I think I misread your post - you mean when your own round starts that you made yourself to fire the event right?

Could you share where you fire and receive the event, and surrounding code? Thanks, it’s just kind of complicated to look through your whole script/localscript there.

1 Like

Basically what doesn’t work when using Players.PlayerAdded is the timer and the fire all clients to change a UI I want to change. The Main Problem is only in the first round because there is not enough wait time before the ‘while true do’ runs it doesn’t pick up the remote event/doesn’t fire it, to change the UI.

The game is a kind of “Tower Of Hell” kind or “Epic Minigames”

Then use something like wait() to just put a delay before it - would that work out? Like wait(5) or whatever to give everything time to load.

1 Like

You should try using os.time() + SecondUntilRoundEnd in this case and put a code in a local script that collect it’s data and compared it with the current os.time()

1 Like

Ight.

  1. Use
if (not game:IsLoaded()) then game.Loaded:Wait() end
  1. Use :WaitForChild() to make sure it works
  2. Never fire an event the SECOND the client joins, always wait 1 or 2 seconds
3 Likes

Here is an example of a timer that will always refresh without server having to fire remote to the client

-- Script in ServerScriptService
local TimeForEachRound = 180

function StartGame()
	local TimeRemaining = workspace.TimeRemaining -- Number value within workspace
	TimeRemaining.Value = os.time() + TimeForEachRound
    -- Loop, etc
end

StartGame()
-- Local script in gui
-- This script will display the time for players

local TextLabel = script.Parent.TextLabel -- TextLabel in the ScreenGui
game:GetService("RunService").Heartbeat:Connect(function()
   TextLabel.Text = game.Workspace.GameInfo.TimeRemaining.Value - os.time()
end)

with this every time a new player joins the game they’ll be able to see how much time is remaining without the remote firing problem.

sorry if my explanation is a bit weird

2 Likes

Still doesn’t quite work, I tried all of you guy’s methods but none of them seemed to work maybe I did them wrong?

I tried out @MJTFreeTime’s Method/idea still doesn’t fire the remote event.

I tried @OminousVibes0’s Methods/Steps still did not work :confused:

I also tried your methods but I got confused with os.time() and don’t get it :confused:

My Problem is only for the remote event that is not firing at round 1 but for all other rounds after round 1 it works fine.

Does it only fail to fire if it is the first player?

Or does every player experience this the first round. Even if they are not the first player to join?

1 Like

os.time() is the seconds that have passed since the Unix epoch (1 January 1970, 00:00:00)
(More info on that here)
which means you can use os.time() to determine the exact time that something will happen for example.

If I want something to happen within 10 seconds then I could either use

wait(10)
-- Something Happen

or use

local WaitTime = os.time() + 10
wait(WaitTime - os.time()) -- Also 10 seconds
-- Something Happen

now the thing that makes os.time() the best choice is that it always get updated every second continuously which means you don’t have to use the remote just to send the current remaining time to client.

2 Likes

I got to give it to you, nice explaination for os.time().

When I learned it, it was a lot more confusing on text.

2 Likes

Ok, so thx to your explanation I now know what is ‘os.time’ and how to use it. But for some weird reasons, it still doesn’t work, the remote event still doesn’t fire. The remote event only doesn’t get fired at round 1 after the first round it fires normally and seems to work fine. The remote event is used to change some UI in the client for all players.

Here is the script that I changed with everyone’s help:

local level = game.ReplicatedStorage:WaitForChild("GeneratedLevels"):GetChildren()
local studs = 0
local endLevel = game.ReplicatedStorage.End

-- Wait Time Variables
local WaitTime1 = os.time() + 2

local ColorTable = {}

wait(WaitTime1 - os.time())
while true do
	wait()
	local ColorTable = {}
	local SizeTable = {}
	for count = 1, 6 do
		for i, placeHolder in pairs(game.Workspace.PlaceHolders:GetChildren()) do
			local chosenLevel = level[math.random(1, #level)]:Clone()
			print(chosenLevel.Name)
			table.insert(SizeTable, UDim2.new(chosenLevel.SizeInfo.Size.Value,chosenLevel.SizeInfo.Size2.Value,chosenLevel.SizeInfo.Size3.Value,chosenLevel.SizeInfo.Size4.Value))
			table.insert(ColorTable, Color3.new(chosenLevel.ColorBar.Value/250,chosenLevel.ColorBar2.Value/250,chosenLevel.ColorBar3.Value/250))
			chosenLevel.PrimaryPart = chosenLevel.Floor
			chosenLevel:SetPrimaryPartCFrame(CFrame.new(placeHolder.Position)+ Vector3.new(studs, 0, 0))
			studs = studs - chosenLevel.studs.Value

			chosenLevel.Parent = game.Workspace.currentLevels
		end
	end

	local endLevelClone = endLevel:Clone()
	endLevelClone.PrimaryPart = endLevelClone.Floor
	endLevelClone:SetPrimaryPartCFrame(CFrame.new(game.Workspace.PlaceHolders.Floor.Position)+ Vector3.new(studs, 0, 0))
	endLevelClone.Parent = game.Workspace.currentLevels	
	print("Be savage")
	game.ReplicatedStorage:WaitForChild("SideBar"):WaitForChild("GiveColoursToClient"):FireAllClients(ColorTable, SizeTable)


	local minutes = 6
	local seconds = 0

	local minutesVal = game.ReplicatedStorage:WaitForChild("TimerVal"):WaitForChild("minutesVal")
	minutesVal.Value = minutes

	local secondsVal = game.ReplicatedStorage:WaitForChild("TimerVal"):WaitForChild("secondsVal")
	secondsVal.Value = seconds

	local timer = game.ReplicatedStorage.Timer


	repeat
		if seconds <= 0 and secondsVal.Value <= 0 then
			minutes = minutes - 1
			seconds = 59

			minutesVal.Value = minutesVal.Value - 1
			secondsVal.Value = 59
		else
			seconds = seconds - 1
			secondsVal.Value = secondsVal.Value - 1
		end

		if seconds <= 9 then

			timer.Value = tostring(minutes)..":0"..tostring(seconds) else

			timer.Value = tostring(minutes)..":"..tostring(seconds)
		end

		wait(game.Workspace.Values.WaitSpeed.Value)

	until minutes <= 0 and seconds <= 0

	if minutes <= 0 and seconds <= 0 then		
		-- Claimed Value
		for _, player in ipairs(game:GetService("Players"):GetPlayers()) do
			if (player) then
				player.ClaimedFolder.Claimed.Value = false
			end
		end
		-- Rep Values for local Buttons
		game.ReplicatedStorage.ShopEvents.LocalButtons.invisibilityButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.BunnyHopButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.FogButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.HighSpeedButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.LowGravityButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.invincibilityButton.Value = false

		-- Bought Values
		script.Parent.ShopItems.BunnyHopFolder.bought.Value = false
		script.Parent.ShopItems.invisivilityFolder.bought.Value = false
		script.Parent.ShopItems.FogFolder.bought.Value = false
		script.Parent.ShopItems.LowGravityFolder.bought.Value = false
		script.Parent.ShopItems.HighSpeedFolder.bought.Value = false
		script.Parent.ShopItems.invincibilityFolder.bought.Value = false
		-- Enabled Value example(BunnyHopEnabled)
		script.Parent.ShopItems.BunnyHopFolder.BunnyHopEnabled.Value = false
		script.Parent.ShopItems.invisivilityFolder.InvisibilityEnabled.Value = false
		script.Parent.ShopItems.FogFolder.FogEnabled.Value = false
		script.Parent.ShopItems.LowGravityFolder.LowGravityEnabled.Value = false
		script.Parent.ShopItems.HighSpeedFolder.HighSpeedEnabled.Value = false
		script.Parent.ShopItems.invincibilityFolder.invincibilityEnabled.Value = false
		-- Fog Back to normal ;)
		game.Lighting.FogEnd = 100000
		game.Lighting.FogStart = 0
		game.Lighting.OutdoorAmbient = Color3.fromRGB(128, 128, 128)
		-- Gravity Back to normal ;)
		game.Workspace.Gravity = 196.2
	end

	for i, player in pairs(game.Players:GetChildren())do
		player:LoadCharacter()
		wait(.1)
		player:LoadCharacter()
	end

	game.Workspace.Values.WaitSpeed.Value = 1
	game.Workspace.Values.SpeedMultiplier.Value = 1	


	game.Workspace.currentLevels:ClearAllChildren()
	studs = 0 
end

The event that doesn’t get fired is right after ‘endLevelClone’ and the ‘Be savage’ print statement.

You can have a sort of log for all players connected in to the remote event

On the server side you can keep a list of players
When a player joins the player will fire the event with certain data
The server can then add the player into the list

When this happens its basically letting the server know that the players remote event is connected and functional; meaning that the server can fire the client also.

Heres a rough idea:
(You will need to adapt this if used)

--- Server
local RE = game.ReplicatedStorage.RemoteEvent -- Just a example
local REPlayers = {}
RE.OnServerEvent:Connect(funcition(Data)
    if Data[1] == "RE Check In" then
        table.insert(REPlayers,Data[2])
    end
    if Data[1] == "RE Check Out" then
        table[table.find(REPlayers,Data[2])] = nil
    end
end)

--- Client Side
local RE = game.ReplicatedStorage.RemoteEvent

RE:FireServer({"RE Check In",game.Players.LocalPlayer})
-- Let the server know the script has loaded

-- The player can then opt out of games using this:
RE:FireServer({"RE Check Out",game.Players.LocalPlayer})

This means that you can sit out of games as well. This means you can see whos in the current game so if people try to glitch into the game from the lobby or something then you can tell they shouldn’t be there.

1 Like

But how is this gonna solve my problem of a remote event not firing because Roblox runs 2x faster than Roblox studio?

This means that the client will load in and then let the server know its loaded. This way it doesn’t matter about the running speed gap.

Both ends need to be loaded in order for client and server communication, no matter how fast they run this is absoloute.

If the script containing the remote event on the client side has not loaded then if the server was to fire the event to start a round the client will not have been able to receive the message.

1 Like

The problem is the round doesn’t need a remote event to start, the remote event I want to fire to the client is to change the UI for all the clients, and I am kind of confused. :confused:

Here is the client script to change some UI:

-- Player
local player = game.Players.LocalPlayer
-- Variables
local frame1 = script.Parent.Main.SideBarFrame.Frame1
local frame2 = script.Parent.Main.SideBarFrame.Frame2
local frame3 = script.Parent.Main.SideBarFrame.Frame3
local frame4 = script.Parent.Main.SideBarFrame.Frame4
local frame5 = script.Parent.Main.SideBarFrame.Frame5
local frame6 = script.Parent.Main.SideBarFrame.Frame6

game.ReplicatedStorage.SideBar.GiveColoursToClient.OnClientEvent:Connect(function(ColorTable, SizeTable)
	print("Checking Remote event is Fired")
	wait()
	function Refresh1()
		frame1.BackgroundColor3 = ColorTable[1]
	end
	
	function Refresh2()
		frame2.BackgroundColor3 = ColorTable[2]
	end
	
	function Refresh3()
		frame3.BackgroundColor3 = ColorTable[3]
	end
	
	function Refresh4()
		frame4.BackgroundColor3 = ColorTable[4]
	end
	
	function Refresh5()
		frame5.BackgroundColor3 = ColorTable[5]
	end
	
	function Refresh6()
		frame6.BackgroundColor3 = ColorTable[6]
	end
	
	repeat
		wait()
		Refresh1()
		Refresh2()
		Refresh3()
		Refresh4()
		Refresh5()
		Refresh6()
	until script.Disabled == true
end)

--for index, value in ipairs(ColorTable) do
	--frame1.BackgroundColor3 = value
	--print(index .. " = " .. tostring(value))
--end

and here is the Main script that passes on everything to change the Ui for all clients:

local level = game.ReplicatedStorage:WaitForChild("GeneratedLevels"):GetChildren()
local studs = 0
local endLevel = game.ReplicatedStorage.End

-- Wait Time Variables
local WaitTime1 = os.time() + 2
local WaitTime2 = os.time() + 2

local ColorTable = {}

wait(WaitTime1 - os.time())
while true do
	wait()
	local ColorTable = {}
	local SizeTable = {}
	for count = 1, 6 do
		for i, placeHolder in pairs(game.Workspace.PlaceHolders:GetChildren()) do
			local chosenLevel = level[math.random(1, #level)]:Clone()
			print(chosenLevel.Name)
			table.insert(SizeTable, UDim2.new(chosenLevel.SizeInfo.Size.Value,chosenLevel.SizeInfo.Size2.Value,chosenLevel.SizeInfo.Size3.Value,chosenLevel.SizeInfo.Size4.Value))
			table.insert(ColorTable, Color3.new(chosenLevel.ColorBar.Value/250,chosenLevel.ColorBar2.Value/250,chosenLevel.ColorBar3.Value/250))
			chosenLevel.PrimaryPart = chosenLevel.Floor
			chosenLevel:SetPrimaryPartCFrame(CFrame.new(placeHolder.Position)+ Vector3.new(studs, 0, 0))
			studs = studs - chosenLevel.studs.Value

			chosenLevel.Parent = game.Workspace.currentLevels
		end
	end

	local endLevelClone = endLevel:Clone()
	endLevelClone.PrimaryPart = endLevelClone.Floor
	endLevelClone:SetPrimaryPartCFrame(CFrame.new(game.Workspace.PlaceHolders.Floor.Position)+ Vector3.new(studs, 0, 0))
	endLevelClone.Parent = game.Workspace.currentLevels	
	print("Be savage")
	wait(WaitTime2 - os.time())
	game.ReplicatedStorage:WaitForChild("SideBar"):WaitForChild("GiveColoursToClient"):FireAllClients(ColorTable, SizeTable)


	local minutes = 6
	local seconds = 0

	local minutesVal = game.ReplicatedStorage:WaitForChild("TimerVal"):WaitForChild("minutesVal")
	minutesVal.Value = minutes

	local secondsVal = game.ReplicatedStorage:WaitForChild("TimerVal"):WaitForChild("secondsVal")
	secondsVal.Value = seconds

	local timer = game.ReplicatedStorage.Timer


	repeat
		if seconds <= 0 and secondsVal.Value <= 0 then
			minutes = minutes - 1
			seconds = 59

			minutesVal.Value = minutesVal.Value - 1
			secondsVal.Value = 59
		else
			seconds = seconds - 1
			secondsVal.Value = secondsVal.Value - 1
		end

		if seconds <= 9 then

			timer.Value = tostring(minutes)..":0"..tostring(seconds) else

			timer.Value = tostring(minutes)..":"..tostring(seconds)
		end

		wait(game.Workspace.Values.WaitSpeed.Value)

	until minutes <= 0 and seconds <= 0

	if minutes <= 0 and seconds <= 0 then		
		-- Claimed Value
		for _, player in ipairs(game:GetService("Players"):GetPlayers()) do
			if (player) then
				player.ClaimedFolder.Claimed.Value = false
			end
		end
		-- Rep Values for local Buttons
		game.ReplicatedStorage.ShopEvents.LocalButtons.invisibilityButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.BunnyHopButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.FogButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.HighSpeedButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.LowGravityButton.Value = false
		game.ReplicatedStorage.ShopEvents.LocalButtons.invincibilityButton.Value = false

		-- Bought Values
		script.Parent.ShopItems.BunnyHopFolder.bought.Value = false
		script.Parent.ShopItems.invisivilityFolder.bought.Value = false
		script.Parent.ShopItems.FogFolder.bought.Value = false
		script.Parent.ShopItems.LowGravityFolder.bought.Value = false
		script.Parent.ShopItems.HighSpeedFolder.bought.Value = false
		script.Parent.ShopItems.invincibilityFolder.bought.Value = false
		-- Enabled Value example(BunnyHopEnabled)
		script.Parent.ShopItems.BunnyHopFolder.BunnyHopEnabled.Value = false
		script.Parent.ShopItems.invisivilityFolder.InvisibilityEnabled.Value = false
		script.Parent.ShopItems.FogFolder.FogEnabled.Value = false
		script.Parent.ShopItems.LowGravityFolder.LowGravityEnabled.Value = false
		script.Parent.ShopItems.HighSpeedFolder.HighSpeedEnabled.Value = false
		script.Parent.ShopItems.invincibilityFolder.invincibilityEnabled.Value = false
		-- Fog Back to normal ;)
		game.Lighting.FogEnd = 100000
		game.Lighting.FogStart = 0
		game.Lighting.OutdoorAmbient = Color3.fromRGB(128, 128, 128)
		-- Gravity Back to normal ;)
		game.Workspace.Gravity = 196.2
	end

	for i, player in pairs(game.Players:GetChildren())do
		player:LoadCharacter()
		wait(.1)
		player:LoadCharacter()
	end

	game.Workspace.Values.WaitSpeed.Value = 1
	game.Workspace.Values.SpeedMultiplier.Value = 1	


	game.Workspace.currentLevels:ClearAllChildren()
	studs = 0 
end