How would i fire a touched event on a client side object?

Sup scripters, im making a mission system and when a player touches the start part then its gonna show a bag via a function i made on a module script, when the player touches the start part it fires the client then it calls the function via the client, then back on the server, it detects the touch of the player of the bag, the problem is that i showed the bag on the client, which the server doesnt detect the bag, then it doesnt work.

I want some of your guys logic to implement that, if i spawn the bag on the server, then everyones gonna see, which is not my goal.

client:

local player = game.Players.LocalPlayer
local playerGui = player.PlayerGui

local startGui = playerGui:WaitForChild("MissionStart")
local endGui = playerGui:WaitForChild("MissionEnd")
local dialogue = playerGui:WaitForChild("Dialogue")

local replicatedStorage = game:GetService("ReplicatedStorage")

local missionLibrary = require(replicatedStorage.Modules.MissionLibrary)
local missionFunctions = require(replicatedStorage.Modules.MissionFunctions)

for _, missionFolder in pairs(replicatedStorage.Missions:GetChildren()) do
	if missionFolder.Name == "Test" then
		local startEvent = missionFolder.Events.StartMission
		local progressEvent = missionFolder.Events.ProgressMission
		local endEvent = missionFolder.Events.EndMission
		
		startEvent.OnClientEvent:Connect(function(startClone, bagClone, missionName, missionType)
			missionFunctions.Hide(startClone)
			missionFunctions.Show(bagClone)
			missionFunctions.startGui(startGui, missionName, missionType)
			missionFunctions.DialogueControl(dialogue, [[Get the <font color="rgb(255,255,0)">bag</font>.]])
		end)
		
		progressEvent.OnClientEvent:Connect(function(bagClone, objectiveClone)
			missionFunctions.Hide(bagClone)
			missionFunctions.Show(objectiveClone)
			missionFunctions.DialogueControl(dialogue, [[Deliver the bag to <font color="rgb(255,255,0)">Lil Pip</font>.]])
		end)
	end
end

server

local replicatedStorage = game:GetService("ReplicatedStorage")

local missionLibrary = require(replicatedStorage.Modules.MissionLibrary)
local missionFunctions = require(replicatedStorage.Modules.MissionFunctions)

for _, missionFolder in pairs(replicatedStorage.Missions:GetChildren()) do
	if missionFolder.Name == "Test" then
		local objectsFolder = workspace.Missions[missionFolder.Name]
		
		local startEvent = missionFolder.Events.StartMission
		local progressEvent = missionFolder.Events.ProgressMission
		local endEvent = missionFolder.Events.EndMission
		
		local missionName = missionLibrary.Missions[missionFolder.Name].Name
		local missionType = missionLibrary.Missions[missionFolder.Name].Type
		local completedDescription = missionLibrary.Missions[missionFolder.Name].CompletedDescription
		
		local timer = missionLibrary.Missions[missionFolder.Name].Timer
		local givesMoney = missionLibrary.Missions[missionFolder.Name].GivesMoney
		local givesExperience = missionLibrary.Missions[missionFolder.Name].GivesExperience
		
		local countdown = missionLibrary.Missions[missionFolder.Name].Countdown
		local moneyReward = missionLibrary.Missions[missionFolder.Name].MoneyReward
		local experienceReward = missionLibrary.Missions[missionFolder.Name].ExperienceReward
		
		local start = missionFolder.Objects.Start
		local bag = missionFolder.Objects:WaitForChild("Bag")
		local objective = missionFolder.Objects.Objective
		
		local startClone = start:Clone()
		local bagClone = bag:Clone()
		local objectiveClone = objective:Clone()
		
		startClone.Parent = objectsFolder
		bagClone.Parent = objectsFolder
		objectiveClone.Parent = objectsFolder
		
		missionFunctions.Hide(bagClone)
		missionFunctions.Hide(objectiveClone)
		
		local debounce1 = false
		local debounce2 = false
		
		startClone.Touched:Connect(function(hit)
			local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
			
			if player and not debounce1 then
				local character = hit.Parent
				
				local missionEnabled = character:WaitForChild("Missions")[missionFolder.Name].Enabled
				local missionRunning = character:WaitForChild("Missions")[missionFolder.Name].Running
				local missionCompleted = character:WaitForChild("Missions")[missionFolder.Name].Completed
				
				debounce1 = true
				
				if missionEnabled.Value == true then
					missionRunning.Value = true
					startEvent:FireClient(player, startClone, bagClone, missionName, missionType)
				end
				
				wait(5)
				
				debounce1 = false
			end
		end)
		
		bagClone.Touched:Connect(function(hit)
			local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)

			if player and not debounce2 then
				local character = hit.Parent

				local missionEnabled = character:WaitForChild("Missions")[missionFolder.Name].Enabled
				local missionRunning = character:WaitForChild("Missions")[missionFolder.Name].Running
				local missionCompleted = character:WaitForChild("Missions")[missionFolder.Name].Completed

				debounce2 = true
				
				if missionRunning.Value == true then
					progressEvent:FireClient(player, bagClone, objectiveClone)
				end

				wait(5)

				debounce2 = false
			end
		end)
	end
end

and sorry for the long script, the part that i want to work is most the bagClone touched event and progress event on client event, thats all!

To prevent exploits, you shouldn’t handle spawning and touch events on client.
Instead, spawn a invisible bag on the server, and make if visible to a specific player using a local script.
Then when the nag is touched, check if the toucher is the target player.

Edit fixed typos

1 Like

wow that makes sense… although i will need to create more 2 functions to just hide instead of changing the cantouch, or i could just completely take off the cantouch thing and set it manually everytime

You could make a bag model invisible from the begining if you want to save some time

sorry but im kinda confused, how would i check if the player is not the one who started the mission?

I’m not sure what will work best for your game. You’ll have to figure out the best method.
Here are some ideas though

  • Create a attribute on the bag object with the player’s name stored
  • Store the bag instance’s target player in a table in on the server script

edit: added a link

well, i tried something and it didnt work, but i think im close and i think you could help me

on the client script, i referenced the enabled, running and completed variables that are stored on the player and, whenever the events are fired, the script checks if the mission running variable is false, if so, it hides the bag locally, however, i think i messed up something and its not detecting

startEvent.OnClientEvent:Connect(function(startClone, bagClone, missionName, missionType)
			if missionRunning.Value == false then
				missionFunctions.Hide(bagClone)
				bagClone.CanTouch = false
			end
			
			missionFunctions.Hide(startClone)
			startClone.CanTouch = false
			
			missionFunctions.startGui(startGui, missionName, missionType)
			missionFunctions.DialogueControl(dialogue, [[Get the <font color="rgb(255,255,0)">bag</font>.]])
		end)
local missionEnabled = character:WaitForChild("Missions")[missionFolder.Name].Enabled
		local missionRunning = character:WaitForChild("Missions")[missionFolder.Name].Running
		local missionCompleted = character:WaitForChild("Missions")[missionFolder.Name].Completed

i think if i tried the ideas you stated above it would just return the same way, i think im doing something wrong while detecting

here, i took a screenshot and when you start the mission it changes to mission running only for the player who is with the mission running set to true

and as you can see above, the bag shows up to the player that didnt start the mission

If I understand correctly, this event is only sent to the person who started the event.
Other players don’t receive that event, so the code that hides that bag doesn’t run for them.

Instead to avoid complexity I recommend making the base model of the bag invisible, and instead of hiding the bag, show the bag once the event is called

could i use a fireserver on a playeradded event, and on the server, get the bool values, tie it to a heartbeat to check if the player has the missionrunning set to true?

because i think that having two models of the samething will complicate a bit things and to say the truth, everything is already so complicated, and i would have to change the main logic of my script, basically rewrite it

I haven’t seen all of your games scripts so I can’t say for sure but
checking the state of the player every heartbeat will work.
I’m not sure what you mean by having 2 of the same model. Also it might just be a typo but fireServer doesn’t work on servers. Use fireClient instead

yea it was just a test or something it was unintentional, but mind i ask, if i pass the player argument to the client, and check by there if it was the player, if not the player, then it will hide, would it work?

and im creating the script on a brand new baseplate to pass it later to my main game

Sure, but that might cause flickering glitches.
Since the bag is created first, and the event to hide it comes next, due to network latency, other players might see a bag show up for a moment and disappear few seconds later.
Instead, like I’ve been saying, it’s better to have the base model of the bag invisible, and turn visibility on on the client side

oh. my. god.

i think im the dumbest person ever, i could just set the can touch to true on the server, since when you touch the bag it only fires when the mission running is set to true, that its set to true when you start the mission, man thanks for make me realize a dumb oversight!

1 Like

Before you read this you have to have
1.server script in start part
2.RemoteEvents in ReplicatedStorage
3.local scripts in ReplicatedFirst
Why?
3.1 bc you don’t have to clone your local scripts inside player’s character
3.2 you can control it by remoteevents
3.3 don’t mess with player’s gui,character,inventory
3.4 ReplicatedFirst replicates to the client before anything else in the game

1.start part i don’t know how do you do start part it might be touched part to start the game so after player touched part then fireclient(player)
2.client script spawn money bag(warn:players can exploit it by make it spawn more) and make touched event in client scripts if player touchs it then it fire back to server and add money in server side