OnClientEvent not working

there are no errors in the output and I put the serverscript in ServerScriptService and the LocalScript in StarterPlayerScripts so it should work

please let me know what is wrong in the comments, thanks
I’ve adjusted the scripts to only include the relevant parts of the script

Server Script

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local ProductHandler = ReplicatedStorage:WaitForChild("ProductHandler")

local Rooms = workspace.Rooms
local Floor1 = Rooms.Room0001

local playersTouched = {}

local function onTouchTrigger(hit, roomNumber)
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)

	-- Check if the player exists and has not already touched the object
	if player then
		
		local hasDisplay = spawnPositions[tostring(roomNumber)]
		
		if hasDisplay then
			ProductHandler:FireClient(player, hasDisplay) -- idk if it sends this
			print("has place to put display") -- prints this in the output properly
		else
			warn("No place to put display")
		end
		
	end
	
end

Client Script

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local MoveAdornee = ReplicatedStorage:WaitForChild("ProductHandler")

MoveAdornee.OnClientEvent:Connect(function(player)
	print(player)
end)
2 Likes

What do you mean with this? Is this the remote event?

yeah wait ill expand the client script

mb here’s more context

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local MoveAdornee = ReplicatedStorage:WaitForChild("ProductHandler")

MoveAdornee.OnClientEvent:Connect(function(player)
	print(player)
end)

Where did you define spawnPositions? maybe because it does not exist It can not trigger the producthandler

its in a table above i didn’t show you
and btw that part works

image

That seems odd…
Where is the Client Script located?
My first idea would be to create a Script with RunContext set to Client.
Edit: And obviously to copy the content of the ClientScript into the new modified Script.

On the server script, when you’re declaring the path to the remoteEvent, using WaitForChild, is not efficient, because on the server-side, those things already exist, and replicatedStorage replicates it to all of the client, and then you can make use of it that way.

There could probably some other underlying things, your code seems to be clean…

but try doing this:

On Server script:

local ProductHandler = game.ReplicatedStorage.ProductHandler

On local script, try doing this:

local moveAdornee = game.ReplicatedStorage:WaitForChild("ProductHandler")

I’m not sure why you named it differently here, as moveAdornee, but probably related to your game anyways.

On the localScript, we use WaitForChild because sometimes the instance we are trying to find for might not have been replicated from the Server, since you declared it already once, in this case, it will wait for a child named “ProductHandler” (It will wait until a child with that name is found i.e., added)

But the “WaitForChild” method finds what it needs, it directly makes reference to it, and that goes into your variable, which is moveAdornee in this case,

Simply put, after something with that name is found, it will just become as and it goes ino your move adornee variable, example:

local moveAdornee = game.ReplicatedStorage.ProductHandler 

And that’s efficient since it doesn’t use the WaitForChild method all the time anymore, in other words, the moveAdornee variable will only have what I’m showing above, and that’s actually great! Because “WaitForChild” method is usually not very optimized, and once it (WaitForChild) found what it needs and from now on, the variable will hold the path to it as I show in the above code snippet.

P.S., are you sure all of the names are correct? Are all of the variables before you connect it to “OnServerEvent” being defined? Put one print statement like:

local Players = game:GetService("Players")


local MoveAdornee = game.ReplicatedStorage:WaitForChild("ProductHandler")

print("Passed: 0")

MoveAdornee.OnClientEvent:Connect(function(player)
	print(player)
end)

If everything goes well till down there, then the “Passed: 0” should be shown in the output.

StarterPlayerScripts I already said in the og post

I’ve adjusted the names to make it suit the script and the remote event does fire from the server (breakpoint testing), but the client doesn’t recieve the script at all and it cannot run a single print statement, so I believe that’s where the problem lies. How can I fix that?

Updated Server Script:

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local module = require(ReplicatedStorage.KeysModule)

local ProductHandler = ReplicatedStorage.ProductHandler

local Rooms = workspace.Rooms
local Floor1 = Rooms.Room0001

local playersTouched = {}

local spawnPositions = {
	
	["Room0001"] = {297.945, 3.261, -37.309},
	["Room0002"] = {3,3,3},
	["Room0003"] = {3,3,3},
	["Room0004"] = {3,3,3},
	["Room0005"] = {3,3,3},
	["Room0006"] = {3,3,3},
	["Room0007"] = {3,3,3}
}


local function onTouchTrigger(hit, roomNumber)
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)
	
	print(hit, roomNumber)
	-- Check if the player exists and has not already touched the object
	if player and not table.find(playersTouched, {roomNumber, player.UserId}) then
		-- Mark this player as having touched the object
		table.insert(playersTouched, {roomNumber, player.UserId})
		
		-- If the roomNumber contains a position to put the display
		local hasDisplay = spawnPositions[tostring(roomNumber)]
		
		if hasDisplay then
			ProductHandler:FireClient(player, hasDisplay) -- sends properly to client
			print("has place to put display") -- prints this
		else
			warn("No place to put display")
		end
		
	end
	
	
end

Updated Client Script

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local ProductHandler = ReplicatedStorage:WaitForChild("ProductHandler")
local gui = script.Parent
local RevealHint = gui.Frame.RevealHint
local SkipStage = gui.Frame.SkipStage

local player = Players.LocalPlayer

print("Passed: 0")

ProductHandler.OnClientEvent:Connect(function(player)
	print(player)
end)

Update: I put the script under the GUI which it regularly refers to in StarterGui and it now works :slight_smile:

1 Like

Nice!

Following up on the solution, it’s great to see StarterGUI working for you!

  • StarterGUI is a convenient way to replicate GUI elements to each player’s PlayerGUI. This ensures the script persists even if the character resets

  • In contrast, StarterCharacterScripts replicate local scripts to the player’s character model, which can be temporary. This might be why your script wasn’t running initially

  • StarterPlayerScripts offer similar benefits to StarterGUI for local scripts that interact with the player’s character

Each player has their own PlayerGUI, but the starterGUI is a convenient way to replicate the GUI items from server to each player’s PlayerGUI. You can see each player’s PlayerGUI in the explorer >> Players >> PlayerGUI

You probably had it under your starterCharacterScripts or something temporary.

If it’s starterCharacterScripts, then that localScript gets replicated to,

workspace.Player1

The player1 is the name of the player, and it is actually a Model, because it is the character of the player, that exists in the workspace, when you put a localScript in starterCharacterScripts, your localScript goes under it!

And, that’s a bit of temporary, if your character is reset or changed, then the script gets deleted, and so and so (which can give unexpected behaviors sometimes), but again the localScript gets replicated back to your character.

But when you keep it in StarterGUI, you are not making a reference to the StarterGUI, but the player’s GUI which isn’t temporary in that way or so and so, and those little edge-cases are covered!

Due to the limitations of starterCharacterScripts (which replicates localScripts to player’s character model that exists within the workspace, like when they die, or so and so), there are some edge-cases, which makes this not so convenient.

There is another thing called starterPlayerScripts that does the exact thing, and works just like StarterGUI, and it doesn’t have those limitations like starterCharacterScripts does, and thus, it easily overcomes the edge-cases, in your case the edge-case is something at that spike of moment, your localScript wasn’t existing, but putting it in StarterGUI, you were able to overcome it.

Edge-cases (or unexpected behaviors) are scary and can be frustrating in Roblox (and in general, programming or game development), but it’s all fine, we just have to know how they work at the deep-level, and the way we get to know is actually by developing something like this and overcoming it the way you did.

Edge cases like these can be confusing, but understanding them helps us become better developers. So, Good job on figuring it out! :smile: