Collecting Objects Script

I’m encountering an issue with my mission system where collected items are appearing to all players, even though the mission should be specific to the player who triggered it. Here’s a brief overview of the problem:

Problem:

  • When a player starts a mission and collects an item, it incorrectly appears as if other players are also collecting the same item. This results in multiple players seeing the item as collected even though only one player should be able to collect it.
  • The issue seems to be related to the way items are being managed and displayed, affecting all players rather than being specific to the player who triggered the mission.

Objective:

  • The mission system should ensure that items to be collected are only visible to the player who initiated the mission. When a player collects an item, it should only update that player’s progress and visibility, not other players’.
  • The script needs to be updated so that it handles item collection and visibility locally for each player, preventing interference between players’ missions.

Current Script Setup:

Disabled LocalScript that gets triggered via a Dialogue where the user agrees to help:

-- LocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local playerGui = player:WaitForChild("PlayerGui")
local missionProgressEvent = ReplicatedStorage:WaitForChild("Bob_MissionProgress")
local missionCompleteEvent = ReplicatedStorage:WaitForChild("Bob_MissionComplete")
local startMissionEvent = ReplicatedStorage:WaitForChild("Bob_StartMission")
local completeValueEvent = ReplicatedStorage:WaitForChild("Bob_CompleteValues")
local prompt1 = game.Workspace.DialoguePrompts.Bobby1
local prompt2 = game.Workspace.DialoguePrompts.Bobby2
local prompt3 = game.Workspace.DialoguePrompts.Bobby3

-- Signal the server to start the mission
startMissionEvent:FireServer()

-- Get GUI elements
local missionGui = playerGui:WaitForChild("Bobby_MissionGui")
local bobbyProgress = missionGui:WaitForChild("Bobby_Progress")
local progressLabel = bobbyProgress:WaitForChild("ProgressLabel")
local missionLabel = bobbyProgress:WaitForChild("MissionLabel")
local powerCellImage = bobbyProgress:WaitForChild("PowerCellImage")
local bobbyComplete = missionGui:WaitForChild("Bobby_Complete")
local powerCellImage1 = bobbyComplete:WaitForChild("PowerCellImage1")
local completeLabel = bobbyComplete:WaitForChild("CompleteLabel")
local missionLabel1 = bobbyComplete:WaitForChild("MissionLabel1")

-- Initialize GUI elements' visibility and transparency
progressLabel.Visible = false
bobbyProgress.Visible = false
powerCellImage.Visible = false
missionLabel.Visible = false
bobbyComplete.Visible = false
powerCellImage1.Visible = false
completeLabel.Visible = false
missionLabel1.Visible = false

progressLabel.TextTransparency = 1
bobbyProgress.BackgroundTransparency = 1
powerCellImage.ImageTransparency = 1
missionLabel.TextTransparency = 1
bobbyComplete.BackgroundTransparency = 1
powerCellImage1.ImageTransparency = 1
completeLabel.TextTransparency = 1
missionLabel1.TextTransparency = 1

-- Create a TweenService instance
local TweenService = game:GetService("TweenService")

-- Progress bar elements
local progressFrame = bobbyProgress:WaitForChild("ProgressFrame")
local bar = progressFrame:WaitForChild("Bar")
bar:TweenSize(UDim2.new(0, 0, 1, 0), 'Out', 'Linear', 0.5) -- start with 0 width
bar.BackgroundTransparency = 1 -- make bar transparent
progressFrame.BackgroundTransparency = 1 -- make progress frame transparent

-- Function to update the progress bar
local function updateProgressBar(current, total)
	local powerCells = current
	local targetWidth = powerCells / total -- calculate new width proportionally

	-- Fade in the progress frame and bar
	local fadeInTweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)
	local progressFrameFadeInTween = TweenService:Create(progressFrame, fadeInTweenInfo, {BackgroundTransparency = 0})
	local barFadeInTween = TweenService:Create(bar, fadeInTweenInfo, {BackgroundTransparency = 0, Size = UDim2.new(targetWidth, 0, 1, 0)})
	progressFrameFadeInTween:Play()
	barFadeInTween:Play()
end

-- Function to fade in progress elements
local function fadeInProgressElements(current, total)
	-- Create a tween to fade in all elements simultaneously
	local fadeInTweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
	local fadeInTweens = {
		TweenService:Create(progressLabel, fadeInTweenInfo, {TextTransparency = 0}),
		TweenService:Create(bobbyProgress, fadeInTweenInfo, {BackgroundTransparency = 0}),
		TweenService:Create(powerCellImage, fadeInTweenInfo, {ImageTransparency = 0}),
		TweenService:Create(missionLabel, fadeInTweenInfo, {TextTransparency = 0}),
		TweenService:Create(progressFrame, fadeInTweenInfo, {BackgroundTransparency = 0}),
		TweenService:Create(bar, fadeInTweenInfo, {BackgroundTransparency = 0, Size = UDim2.new(current / total, 0, 1, 0)})
	}

	for _, tween in pairs(fadeInTweens) do
		tween:Play()
	end

	progressLabel.Text = string.format("You have collected %d/%d Alien Power Cells", current, total)
	progressLabel.Visible = true
	bobbyProgress.Visible = true
	powerCellImage.Visible = true
	missionLabel.Visible = true
	progressFrame.Visible = true
	bar.Visible = true

	print("Fading in progress elements: " .. current .. "/" .. total)
end

-- Function to fade out progress elements
local function fadeOutProgressElements(callback)
	local fadeOutTweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
	local fadeOutTweens = {
		TweenService:Create(progressLabel, fadeOutTweenInfo, {TextTransparency = 1}),
		TweenService:Create(bobbyProgress, fadeOutTweenInfo, {BackgroundTransparency = 1}),
		TweenService:Create(powerCellImage, fadeOutTweenInfo, {ImageTransparency = 1}),
		TweenService:Create(missionLabel, fadeOutTweenInfo, {TextTransparency = 1}),
		TweenService:Create(progressFrame, fadeOutTweenInfo, {BackgroundTransparency = 1}),
		TweenService:Create(bar, fadeOutTweenInfo, {BackgroundTransparency = 1, Size = UDim2.new(0, 0, 1, 0)})
	}

	local completedTweens = 0
	for _, tween in pairs(fadeOutTweens) do
		tween.Completed:Connect(function()
			completedTweens = completedTweens + 1
			if completedTweens == #fadeOutTweens then
				if callback then callback() end
			end
		end)
		tween:Play()
	end

	wait(0.5)  -- Wait for the tween to finish

	-- Hide the progress GUI elements regardless of whether current reaches total or not
	progressLabel.Visible = false
	bobbyProgress.Visible = false
	powerCellImage.Visible = false
	missionLabel.Visible = false
	progressFrame.Visible = false
	bar.Visible = false

	print("Fading out progress elements.")
end

-- Function to display progress
local function displayProgress(current, total)
	local function displayMissionComplete()
		-- Your code to display a message or UI indicating mission completion
		print("Mission complete!")
	end

	fadeInProgressElements(current, total)
	wait(2)  -- Show the message for 2 seconds

	if current == total then
		fadeOutProgressElements(displayMissionComplete)
	else
		fadeOutProgressElements()
	end
end

-- Function to display mission completion
local function displayMissionComplete()
	wait(0.5)  -- Wait for the progress fade out tweens to finish
	completeValueEvent:FireServer()
	-- Only set visibility to false if they are currently visible
	if progressLabel.Visible then
		progressLabel.Visible = false
	end
	if bobbyProgress.Visible then
		bobbyProgress.Visible = false
	end
	if powerCellImage.Visible then
		powerCellImage.Visible = false
	end
	if missionLabel.Visible then
		missionLabel.Visible = false
	end

	-- Create a tween to fade in the complete label, PowerCellImage1, Bobby_Complete, and missionLabel1
	local fadeInTweenInfo = TweenInfo.new(1.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)  -- Increased duration from 1 second
	local fadeInTweens = {
		TweenService:Create(completeLabel, fadeInTweenInfo, {TextTransparency = 0}),
		TweenService:Create(powerCellImage1, fadeInTweenInfo, {ImageTransparency = 0}),
		TweenService:Create(bobbyComplete, fadeInTweenInfo, {BackgroundTransparency = 0}),
		TweenService:Create(missionLabel1, fadeInTweenInfo, {TextTransparency = 0})
	}

	completeLabel.TextTransparency = 1
	powerCellImage1.ImageTransparency = 1
	bobbyComplete.BackgroundTransparency = 1
	missionLabel1.TextTransparency = 1

	completeLabel.Text = "You Collected All Alien Power Cells. Head back to Bobby the Hippy for a Reward!"
	completeLabel.Visible = true
	powerCellImage1.Visible = true
	bobbyComplete.Visible = true
	missionLabel1.Visible = true

	for _, tween in pairs(fadeInTweens) do
		tween:Play()
	end
	
	completeValueEvent:FireServer()
	prompt1.ProximityPrompt.Enabled = false
	prompt2.ProximityPrompt.Enabled = false
	prompt3.ProximityPrompt.Enabled = true
	print("Displaying mission completion message.")
	wait(3)  -- Show the message for 5 seconds
	-- Create a tween to fade out the complete label, PowerCellImage1, Bobby_Complete, and missionLabel1
	local fadeOutTweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
	local fadeOutTweens = {
		TweenService:Create(completeLabel, fadeOutTweenInfo, {TextTransparency = 1}),
		TweenService:Create(powerCellImage1, fadeOutTweenInfo, {ImageTransparency = 1}),
		TweenService:Create(bobbyComplete, fadeOutTweenInfo, {BackgroundTransparency = 1}),
		TweenService:Create(missionLabel1, fadeOutTweenInfo, {TextTransparency = 1})
	}

	for _, tween in pairs(fadeOutTweens) do
		tween:Play()
	end

	wait(0.5)  -- Wait for the tween to finish
	completeLabel.Visible = false
	powerCellImage1.Visible = false
	bobbyComplete.Visible = false
	missionLabel1.Visible = false
end

-- Connect events
missionProgressEvent.OnClientEvent:Connect(displayProgress)
missionCompleteEvent.OnClientEvent:Connect(displayMissionComplete)

The ServerScript:

-- ServerScript
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local collects = game.Workspace.Collects
local prompt1 = game.Workspace.DialoguePrompts.Bobby1
local prompt2 = game.Workspace.DialoguePrompts.Bobby2
local prompt3 = game.Workspace.DialoguePrompts.Bobby3

local MISSION_PARTS_COUNT = 10

local missionParts = {}
local playerProgress = {}
local collectedParts = {}

local missionProgressEvent = ReplicatedStorage:WaitForChild("Bob_MissionProgress")
local missionCompleteEvent = ReplicatedStorage:WaitForChild("Bob_MissionComplete")
local startMissionEvent = ReplicatedStorage:WaitForChild("Bob_StartMission")
local completeValueEvent = ReplicatedStorage:WaitForChild("Bob_CompleteValues")

-- Sound IDs
local PART_COLLECTED_SOUND_ID = "rbxassetid://8864375838"
local MISSION_COMPLETE_SOUND_ID = "rbxassetid://3198076659"

-- Function to create mission parts
local function createMissionParts()
	for i = 1, MISSION_PARTS_COUNT do
		local part = collects["PowerCell_".. i]
		part.Size = part.Size
		part.Position = part.Position
		part.Parent = collects
		part.Transparency = 0
		part.PointLight.Enabled = true
		part.CanTouch = true
		table.insert(missionParts, part)
		print("Created part: ".. part.Name)
	end
end

-- Function to handle player join
local function onPlayerJoin(player)
	playerProgress[player.UserId] = 0
	collectedParts[player.UserId] = {}
	print("Player joined: ".. player.Name)
end

-- Function to handle player leave
local function onPlayerRemoving(player)
	playerProgress[player.UserId] = nil
	collectedParts[player.UserId] = nil
	print("Player left: ".. player.Name)
end

-- Function to play and delete sound after it finishes
local function playAndDeleteSound(soundId, parent)
	local sound = Instance.new("Sound")
	sound.SoundId = soundId
	sound.Parent = parent
	sound:Play()

	sound.Ended:Connect(function()
		sound:Destroy()
	end)
end

-- Function to handle part collection
local function onPartCollected(player, part)
	local playerId = player.UserId
	local partName = part.Name

	-- Check if the collectedParts table has been initialized for this player
	if not collectedParts[playerId] then
		collectedParts[playerId] = {}
	end

	-- Check if the part has already been collected by this player
	if collectedParts[playerId][partName] then
		return
	end

	-- Mark the part as collected by this player
	collectedParts[playerId][partName] = true

	local currentProgress = playerProgress[playerId] or 0
	local newProgress = currentProgress + 1

	playerProgress[playerId] = newProgress
	print(player.Name.. " collected a part. Progress: ".. newProgress.. "/".. MISSION_PARTS_COUNT)

	-- Play part collected sound
	playAndDeleteSound(PART_COLLECTED_SOUND_ID, player.Character)

	missionProgressEvent:FireClient(player, newProgress, MISSION_PARTS_COUNT)

	part:Destroy()

	if newProgress == MISSION_PARTS_COUNT then
		print(player.Name.. " has completed the mission!")

		-- Play mission complete sound
		playAndDeleteSound(MISSION_COMPLETE_SOUND_ID, player.Character)

		missionCompleteEvent:FireClient(player)
	end
end

-- Function to connect parts
local function connectParts()
	for _, part in ipairs(missionParts) do
		part.Touched:Connect(function(hit)
			local character = hit.Parent
			local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
			if humanoidRootPart then
				local player = Players:GetPlayerFromCharacter(character)
				if player then
					onPartCollected(player, part)
				end
			end
		end)
	end
end

-- Handle mission start
startMissionEvent.OnServerEvent:Connect(function(player)
	if #missionParts == 0 then
		prompt1.ProximityPrompt.Enabled = false
		prompt2.ProximityPrompt.Enabled = true
		prompt3.ProximityPrompt.Enabled = false
		createMissionParts()
		connectParts()
	end
end)

completeValueEvent.OnServerEvent:Connect(function(player)
	player.MissionValue.Bob.Value = player.MissionValue.Bob.Value + 1
end)

Players.PlayerAdded:Connect(function(player) --Already completed
	wait(1)
	if player.MissionValue.Bob.Value >= 1 then
		prompt1.ProximityPrompt.Enabled = false
		prompt2.ProximityPrompt.Enabled = false
		prompt3.ProximityPrompt.Enabled = true
	end
end)
-- Connect player join and leave events
Players.PlayerAdded:Connect(onPlayerJoin)
Players.PlayerRemoving:Connect(onPlayerRemoving)

print("MissionScript loaded successfully.")

and the MissionData Store Script:

local players = game.Players
local playerData = require(game.ReplicatedStorage.MissionData)

local function SavePlayerData(player)
	playerData.savePlayerData(player)
end

players.PlayerAdded:Connect(function(player)
	local mission = Instance.new("Folder", player)
	mission.Name = "MissionValue"
	
	local bob = Instance.new("NumberValue", mission)
	bob.Name = "Bob"
	
	local pData = playerData.loadPlayerData(player, function(data)
		if data then
			for _, value in ipairs(player:GetDescendants()) do
				if value:IsA("NumberValue") or value:IsA("StringValue") or value:IsA("BoolValue") then
					if data[value.Name] then
						value.Value = data[value.Name]
					end
				end
			end
		else
			print("MissionData has an error")
		end
	end)
	
	while task.wait(15) do
		SavePlayerData(player)
	end
end)

players.PlayerRemoving:Connect(function(player)
	SavePlayerData(player)
	print("MissionData has been saved.")
end)

Would appreciate any help! :+1:

Since you’re creating the parts on the server obviously everyone will see it. So create the mission parts on the client instead if you want only the player to see it

Is there a way I can make the objects from this part of the Server Script appear locally for players who’ve triggered the Mission?

-- Function to create mission parts
local function createMissionParts()
	for i = 1, MISSION_PARTS_COUNT do
		local part = collects["PowerCell_".. i]
		part.Size = part.Size
		part.Position = part.Position
		part.Parent = collects
		part.Transparency = 0
		part.PointLight.Enabled = true
		part.CanTouch = true
		table.insert(missionParts, part)
		print("Created part: ".. part.Name)
	end
end

You can just create the parts on the local script so that only the local player can see it