Help with making winner the same for all clients

heya! I have been creating a roulette type screen for a commission and I am not quite sure how to go about making the winner the same for all clients?

server script:

local function generatePattern()
	local pattern = {}
	math.randomseed(tick())
	local currentCoin = "Robux"
	local startingIndex = math.random(1, 14)
	for i = startingIndex, startingIndex + 29 do
		if (i - startingIndex) % 14 == 13 then
			table.insert(pattern, "Diamond")
		else
			table.insert(pattern, currentCoin)
		end
		if currentCoin == "Robux" then
			currentCoin = "Tix"
		else
			currentCoin = "Robux"
		end
	end
	return pattern
end




local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RequestWinnerData = ReplicatedStorage:WaitForChild("RequestWinnerData")
local RouletteWinner = ReplicatedStorage:WaitForChild("RouletteWinner")
local function determineWinner(rouletteFrameData, redLine)
	for _, coin in ipairs(rouletteFrameData) do


		
			print(coin.name)
			if redLine >= coin.left and redLine <= coin.right then
				return coin.name -- return the instance itself instead of its name
			
		end
	end
	return nil
end

function RequestWinnerData.OnServerInvoke(self, rouletteFrameData, redLineX)
	--local coinDataTable = {}
	--for _, coin in ipairs(rouletteFrameData) do
	--	if coin.Name == "StarterGear" then
	--		else
	--		print(coin.Name)
	--		local coinLeft = coin.AbsolutePosition.X
	--		local coinRight = coinLeft + coin.AbsoluteSize.X
	--		print(coinLeft)
	--		print(coinRight)
	--		print(redLineX)
	--		table.insert(coinDataTable, {name = coin.Name, left = coinLeft, right = coinRight})
	--	end
	--end

	local winnerInstance = determineWinner(rouletteFrameData, redLineX)
	if winnerInstance then
	

		return winnerInstance -- return the name of the instance if it was found
		
	end
	return nil
end






while true do
	wait(2)

	if game.ReplicatedStorage.GlobalValues.Roulette.Rolling.Value == true then

	else


		local countdownTime = 5 -- Set the duration of the countdown here (in seconds)

		local function countdown()
			local startTime = os.clock()
			local currentTime = os.clock()
			local timeRemaining = countdownTime

			while timeRemaining > 0 do
				currentTime = os.clock()
				timeRemaining = countdownTime - (currentTime - startTime)
				if timeRemaining < 0 then
					timeRemaining = 0
				end

				game.ReplicatedStorage.GlobalValues.Roulette.Timer.Value = timeRemaining
				print(string.format("Time remaining: %.2f seconds", timeRemaining))
				wait(0.01) -- Update interval (lower value for more frequent updates, higher value for less frequent updates)
			end

			print("Countdown completed!")
			game.ReplicatedStorage.GlobalValues.Roulette.Rolling.Value = true
			game.ReplicatedStorage.Assets.Events.Roulette.StartGame:FireAllClients(generatePattern())
			wait(10)
			game.ReplicatedStorage.GlobalValues.Roulette.Rolling.Value = false

		end

		countdown()







	end
end

local script:

local TweenService = game:GetService("TweenService")

local Rolling = game:GetService("ReplicatedStorage"):WaitForChild("GlobalValues"):WaitForChild("Roulette"):WaitForChild("Rolling")


local ScreenGui = script.Parent
local RouletteFrame = ScreenGui:WaitForChild("RouletteFrame")
local CoinStorage = RouletteFrame:WaitForChild("CoinStorage")
local RedLine = RouletteFrame:WaitForChild("RedLine")

local speed = math.random(50,100)
local slowDuration = math.random(7,15)
local spacing = 0


local linetable = {}
table.insert(linetable,RedLine.AbsolutePosition.X)






local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RequestWinnerData = ReplicatedStorage:WaitForChild("RequestWinnerData")







local function createCoins(pattern)
	
	for _, coin in ipairs(RouletteFrame:GetChildren()) do
		if coin:IsA("ImageLabel") then
			coin:Destroy()
		end
	end
	
	local totalWidthOffset = 0
	for i, coinType in ipairs(pattern) do
		totalWidthOffset = totalWidthOffset + CoinStorage:FindFirstChild(coinType).Size.X.Offset + spacing
	end
	totalWidthOffset = totalWidthOffset - spacing -- Remove the extra spacing

	local totalWidthScale = totalWidthOffset / RouletteFrame.AbsoluteSize.X

	local startXScale = 0

	for i, coinType in ipairs(pattern) do
		local coin = CoinStorage:FindFirstChild(coinType):Clone()
		coin.Position = UDim2.new(startXScale + (i - 1) * (coin.Size.X.Scale + spacing / RouletteFrame.AbsoluteSize.X), 0, 0.5, 0)
		coin.Name = coinType .. "_" .. tostring(i)
		coin.Parent = RouletteFrame
	end
end



local function moveCoins(pattern)
	local fastDuration = math.random(4,10)
	local decayRate = .95 -- You can adjust this value between 0 and 1 to change the smoothness of the glide
	local frameWidth = RouletteFrame.Size.X.Offset

	local speed = math.random(35,75)
	local function moveOneStep()
		for _, coin in ipairs(RouletteFrame:GetChildren()) do
			if coin:IsA("ImageLabel") then
				local newPosScale = coin.Position.X.Scale - speed / RouletteFrame.AbsoluteSize.X
				if newPosScale + coin.Size.X.Scale < 0 then
					--	local seed = game:GetService("ServerScriptService"):WaitForChild("Games"):WaitForChild("Roulette"):WaitForChild("Handler"):WaitForChild("GetSeed"):Invoke()
					newPosScale = newPosScale + (#pattern * (coin.Size.X.Scale + spacing / RouletteFrame.AbsoluteSize.X))
				end
				coin.Position = UDim2.new(newPosScale, 0, .05, 0)
			end
		end
		wait()
	end

	for _ = 1, fastDuration * 15 do
		moveOneStep()
	end

	while speed > 0.1 do -- gradually decrease speed to near 0
		moveOneStep()
		speed = speed * decayRate -- apply exponential decay to speed
	end
	moveOneStep() -- make sure the coins end up in the correct positions
end





game:GetService("ReplicatedStorage"):WaitForChild("Assets"):WaitForChild("Events"):WaitForChild("Roulette"):WaitForChild("StartGame").OnClientEvent:Connect(function(pattern)

	createCoins(pattern)
	moveCoins(pattern)





	Rolling.Value = true
	local ReplicatedStorage = game:GetService("ReplicatedStorage")
	local RouletteWinner = ReplicatedStorage:WaitForChild("RouletteWinner")
	--local HttpService = game:GetService("HttpService")

	-- create rouletteFrameData table
	
	local coinData = {}

	for _, coin in ipairs(RouletteFrame:GetChildren()) do
		if coin:IsA("ImageLabel") then
			
		--	print(coin.Name)
			local coinLeft = coin.AbsolutePosition.X
			local coinRight = coinLeft + coin.AbsoluteSize.X
			table.insert(coinData, {name = coin.Name, left = coinLeft, right = coinRight})
			end
			
	end



	
	--print(RouletteFrame.Parent.Name)
	
	-- pass rouletteFrameDataJSON to remote function
	local winner = RequestWinnerData:InvokeServer(coinData, script.Parent.RouletteFrame.RedLine.AbsolutePosition.X)

	-- Perform any necessary actions with the winnerx

	--print(winner)
	
	print("Winner is: " .. winner) 
	script.Parent.TextLabel.Text = winner
	Rolling.Value = false
	table.clear(coinData)







end)


while true do
	wait(.01)
	script.Parent.Timer.Text = game.ReplicatedStorage.GlobalValues.Roulette.Timer.Value

end


--print(rouletteFrameData)

i have tried to start the games with the same random intervals for the speed and slowing down but players with smaller screen resolutions get a different winner. All Uis units are set to Scale and they all have aspect ratio constraints.

1 Like

One way you could do this is by:
Making it determine the winner fully on the serverside rather than relying on the client to invoke a server event and then you could fire a remote event for all the clients using :FireAllClients function and passing the winner value as an argument for the client

2 Likes

use an remote event here a example

ReplicatedStorage.Event_Path:FireAllClients

here a doc for this

yes, but the way determineWinner() is done, it determines the winner by checking which coin is touching the red line within the GUI.

If i was to make it determine the winner by randomly choosing, I do not quite know how I would make it move and stop on that specific coin.

same obstacle as I stated in reply to the previous response. :persevere:

Im pretty sure every other roulette/coinflips determine it randomly on the server and play an animation on the client. So you should make an fixed animation for it that you can control which side it lands on

A fixed animation basically ruins the meaning of a roulette… if I use a fixed animation you would probably be able to tell what the winner was after a while of playing.

heres an example of what i want to achieve:

in-game there’s a random roulette which is different every time.

Well if you want it to look like theirs maybe make it randomly spin for a bit then revert backwards to the nearest correct coin position with a tween

I could, but that would result in the pattern to be different for every player.

my main issue is that the roll is different for players with different resolution screens. I would like to know if there’s anything I could modify/add to prevent that?

You could either do it by adding an UIAspectRatioConstraint manually or (my personal preference) using a plugin like AutoScale Lite which does it automatically

They already contain UiAspectRatioConstraints… Still.