Help with script to manage puzzles function runs twice what should only run once

so i have this script for my puzle gamethere some errors as first it handle all functions twice what makes player get thier data twice

client

local NetworkReplicator = require(game.ReplicatedStorage.Utility.SpecialTable.ClientReplicatorAPI)
local DataReplicationRemotes = game.ReplicatedStorage.DataReplicationRemotes.SendStatData
local SpecialTable = require(game.ReplicatedStorage.Utility.SpecialTable)
local NumberAbbreviator = require(game.ReplicatedStorage.Utility.NumberAbbreviator)
--local GamePlayerData = require(game.ReplicatedStorage.GameState.PlayerData)
--print(GamePlayerData)

local Players = game:GetService("Players")
local plr = Players.LocalPlayer
local CollectionService = game:GetService("CollectionService")
local completed = false
local running = false

local award = game:GetService("ReplicatedStorage").remotes.XCfromPuzzle

local function formatTime(seconds)
	local minutes = math.floor(seconds / 60)
	local remainingSeconds = seconds % 60
	return string.format("%02d:%02d", minutes, remainingSeconds)
end

local function startCountdown(player, title, time)
	local playerGui = player:FindFirstChild("PlayerGui")
	if not playerGui then return end

	local countdownGui = playerGui:WaitForChild("round") -- Ensure this is the correct GUI name
	if not countdownGui then return end

	local text =  countdownGui:FindFirstChild("back").roundbased.btimepuzle.btextleft
	local titleLabel = countdownGui:FindFirstChild("back").roundbased.atoppuzle.btext
	local timeLabel = countdownGui:FindFirstChild("back").roundbased.btimepuzle.ctime
	local progressBar = countdownGui:FindFirstChild("back").roundbased.cbar.innerbar -- Assuming progressBar exists
	if not titleLabel or not timeLabel or not progressBar then return end
	text.Text = 'time elapsed'

	timeLabel.TextColor3 = Color3.new(0, 0, 0)
	progressBar.BackgroundColor3 = Color3.new(0.219608, 0.643137, 0.356863)

	titleLabel.Text = title
	local remainingTime = time
	local initialTime = time

	while remainingTime > 0 do
		if not completed then
			timeLabel.Text = formatTime(remainingTime)
			progressBar.Size = UDim2.new(1 - (remainingTime / initialTime), 0, 1, 0) -- Update progress bar size

			if remainingTime <= 5 then
				timeLabel.TextColor3 = Color3.new(1, 0, 0) -- Red color
				progressBar.BackgroundColor3 = Color3.new(1, 0, 0) -- Red color
				if timeLabel.BackgroundTransparency == 0 then
					timeLabel.BackgroundTransparency = 0.2
				elseif timeLabel.BackgroundTransparency == 0.2 then
					timeLabel.BackgroundTransparency = 0
				end
				if progressBar.BackgroundTransparency == 0 then
					progressBar.BackgroundTransparency = 0.2
				elseif progressBar.BackgroundTransparency == 0.2 then
					progressBar.BackgroundTransparency = 0
				end			
			end

			task.wait(1)
			remainingTime -= 1
			if player.Character.Humanoid.Health == 0 then
	break
	end
		else
			break -- Exit the loop if the puzzle is completed
		end
	end

	if remainingTime == 0 and not completed then
		task.wait(0.5)
		if not completed then
			player.Character.Humanoid.Health = 0
		end
	end
	
	

if not completed then
		text.Text = 'time elapsed'
	titleLabel.Text = "<b> time is your enemy</b> no puzzle chosen"
	timeLabel.TextColor3 = Color3.new(0, 0, 0)
	progressBar.BackgroundColor3 = Color3.new(0.219608, 0.643137, 0.356863)
	completed = false
	timeLabel.Text = "00:00"
	progressBar.Size = UDim2.new(0, 0, 1, 0) -- Set progress bar to empty
end
	
end



local function handleFinish(player, xp, coins, nextlevel)
	if completed then return end
	if not completed then
		
	
	local playerGui = player:FindFirstChild("PlayerGui")
	if not playerGui then return end

	local countdownGui = playerGui:WaitForChild("round") -- Ensure this is the correct GUI name
	if not countdownGui then return end
	completed = true
		local text =  countdownGui:FindFirstChild("back").roundbased.btimepuzle.btextleft
text.Text = '<font color ="rgb(0,85,0)">completed</font>'
	local timeLabel = countdownGui:FindFirstChild("back").roundbased.btimepuzle.ctime
	timeLabel.TextColor3 = Color3.new(0, 0.333333, 0)
	local progressBar = countdownGui:FindFirstChild("back").roundbased.cbar.innerbar -- Assuming progressBar exists
	progressBar.BackgroundColor3 = Color3.new(0, 0.333333, 0)

	task.wait(0.1)
local checkpointNumber = nextlevel
	local number = math.random(1,10)
	local checkpointMap = game.Workspace:FindFirstChild("Checkpoints")
	local checkpoint = checkpointMap:FindFirstChild(tostring(checkpointNumber))

	--[[if number == 7 then
				if checkpoint and checkpoint:IsA("BasePart") then
					player.Character:SetPrimaryPartCFrame(checkpoint.CFrame)
				end
				
			task.wait(0.5)

		-- Trigger battle field
		print("Battle field should be triggered now")
		-- Save xp and money to award in battle
		
	else]]
		
		
			--NetworkReplicator.Subscribe(DataReplicationRemotes, function(PlayerStats)
		--local PlayerStats = GamePlayerData.Get(player)
				--PlayerStats.XP = xp -- are this posible on the client
				--PlayerStats.Coins = coins
				print(xp)
				local XP = xp
				local Coins = coins
				print(XP)
				award:FireServer(player, XP, Coins)
			local levelup =	playerGui:WaitForChild("LevelUpEtc")
			levelup.main.clevel.Visible = false
			levelup.main.Visible = true
				levelup.main.cxp.Visible = true
				levelup.main.cxp.b.Text = '<b> you got <font color="rgb(22,0,58)">xp</font> '..XP..'</b>'
				levelup.main.cxp.c.Text = '<b> you got <font color="rgb(225,225,0)">coins</font> '..coins..'</b>'

				-- Show XP frame and money
		--	end)
			
		if checkpoint and checkpoint:IsA("BasePart") then
			player.Character:SetPrimaryPartCFrame(checkpoint.CFrame)
		end
		print("Puzzle completed")
	end
	--end
end
local function onPromptTriggered(prompt, player)
	if not CollectionService:HasTag(prompt, "promptUnv1") then return end
completed = false
prompt.Parent.Parent.Parent.CanTouch = true
print(prompt)
print(prompt.Parent.Parent.Parent)
print(prompt.Parent.Parent.Parent.CanTouch)
	local title = prompt:GetAttribute("title") or "Default Title"
	local time = prompt:GetAttribute("Duration") or 100

	if player then
		startCountdown(player, title, time)
	end
end

local function onBellDragged(bell, player)
	if not CollectionService:HasTag(bell, "bellSOP") then return end
	for i,v in game:GetService("Workspace").puzles:GetDescendants() do
		if v:IsA("BasePart") and v:HasTag("doorSOP")then
			v.CanTouch = false
		end
	end
	local xp = bell:GetAttribute("xp") or 0
	local coins = bell:GetAttribute("money") or 0
	local nextlevel = bell:GetAttribute("nextStage") or 1

	if player then
		-- Run in a separate coroutine to prevent blocking the main thread
		coroutine.wrap(function()
			handleFinish(player, xp, coins, nextlevel)
		end)()
	end
end


-- Bind the function to all existing prompts with the tag
local taggedPrompts = CollectionService:GetTagged("promptUnv1")
for _, prompt in pairs(taggedPrompts) do
	if prompt:IsA("ProximityPrompt") then
		prompt.Triggered:Connect(function(player)
			onPromptTriggered(prompt, player)
		end)
	end
end

-- Listen for new prompts being added to the game
CollectionService:GetInstanceAddedSignal("promptUnv1"):Connect(function(instance)
	if instance:IsA("ProximityPrompt") then
		instance.Triggered:Connect(function(player)
			onPromptTriggered(instance, player)
		end)
	end
end)

local taggedBells = CollectionService:GetTagged("bellSOP")
for _, bell in pairs(taggedBells) do
	if bell:IsA("DragDetector") then
		bell.DragStart:Connect(function(player)
			onBellDragged(bell, player)
		end)
	end
end

--Listen for new bells being added to the game
CollectionService:GetInstanceAddedSignal("bellSOP"):Connect(function(instance)
	if instance:IsA("DragDetector") then
		instance.DragStart:Connect(function(player)
			onBellDragged(instance, player)
		end)
	end
end)

it also dont makes the ui visible

well after that it fires a remote event to handle the data

server

--local RunTimeManager = require(script.Parent.EventDatabase)
	local GamePlayerData = require(game.ReplicatedStorage.GameState.PlayerData)
local SpecialTable = require(game.ReplicatedStorage.Utility.SpecialTable)
local EventDatabase = require(game.ServerScriptService.Managers.EventDatabase)

	
	local PuzleData = game:GetService("ReplicatedStorage").remotes.XCfromPuzzle

PuzleData.OnServerEvent:Connect(function(player: Player, XP, Coins) 
	local PlayerStats = GamePlayerData.Get(player)
	print(XP)
	--print("xp = : "..XP)
	PlayerStats.XP += XP
	PlayerStats.Coins += Coins
end)

well it doesnt update the data becouse it corupted it when sending to the server it xp and coins objects become the player object in some way on the client it is the amounth xp

1 Like

When you use FireServer, you do not need to specify the player on the client. Only during the connection

Looking at your server script,

award:FireServer(player, XP, Coins)

Should be

award:FireServer(XP, Coins)

The Player is the one that fired the event, and is always the first thing. https://create.roblox.com/docs/scripting/events/remote#server-client

And how to make the client script only run once each time triggered or dragged and is the server script save for exploiters or can they add Anny value to fire with the remote event

PuzleData.OnServerEvent:Connect(function(player: Player, XP, Coins) 
	local PlayerStats = GamePlayerData.Get(player)

Also here it needs the player object to handle data for the Play
Er

Exploiters are able to add data and fire the event themselves, so it is recommended to validate inputs on the server.

If possible, you would want to handle how much XP the player gets, and data like that on the server.

But it’s get from a atributes on the client but idk how to check if player really got it and dragged the bell what now fires twice in some way.

Like in the bell is a dragdetor with attributes next level xp coins I don’t want people to exploit it and it function runs twice what I think because it double triggered but if I remove one of them the entire script doesn’t work.

I tried without Player it can’t the Play er find on the server than and one of the arguments become invalid in some way I added a server check but there also
edit on the function it works but in the anti exploit whereever i set the player it will always kick them able if they meet the not exploiting becouse one of the arguments become invalid and if im not use the player it doesnt work cuz i need to check the player on the server

It seems to be I think the way the remote function goes back I hope it stops here cuz before it kicked them also

But the main issue is
The code runs twice because it’s trigger is twice but if I do one it doesn’t work

It’ll get the player from the .OnServerEvent

award:FireServer(XP, Coins)

However, this can remain the same as it will get the player. This should fix issue with them being invalid.

PuzleData.OnServerEvent:Connect(function(player: Player, XP, Coins) 

It works but the issue with the script is still that it runs twice

-- Bind the function to all existing prompts with the tag
local taggedPrompts = CollectionService:GetTagged("promptUnv1")
for _, prompt in pairs(taggedPrompts) do
	if prompt:IsA("ProximityPrompt") then
		prompt.Triggered:Connect(function(player)
			onPromptTriggered(prompt, player)
		end)
	end
end

-- Listen for new prompts being added to the game
CollectionService:GetInstanceAddedSignal("promptUnv1"):Connect(function(instance)
	if instance:IsA("ProximityPrompt") then
		instance.Triggered:Connect(function(player)
			onPromptTriggered(instance, player)
		end)
	end
end)

local taggedBells = CollectionService:GetTagged("bellSOP")
for _, bell in pairs(taggedBells) do
	if bell:IsA("DragDetector") then
		bell.DragStart:Connect(function(player)
			onBellDragged(bell, player)
		end)
	end
end

--Listen for new bells being added to the game
CollectionService:GetInstanceAddedSignal("bellSOP"):Connect(function(instance)
	if instance:IsA("DragDetector") then
		instance.DragStart:Connect(function(player)
			onBellDragged(instance, player)
		end)
	end
end)

I tried removing one of them but then the whole scrostopd working it’s because it are two but can you explain how to fix this so there need only one trigger function

I fixed it v return the event triggered instance so I used I,

No it still runs twice it’s in startergui can that be the case I has another script In rs but it didn’t run it does in sps

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.