Client not always recieving RemoteEvent

I’m making a game where the player gets morphed into a survivor/killer, and ui is supposed to appear on their screen depending on their role. For some reason, the client isn’t always recieving the message to make the ui visible. Here is some of the code:

  • Server Script Code
if player:FindFirstChild("IsKiller").Value == true then
				print("Morphing Killer")
				Morph.KillerMorph(player, "Test")
			else
				print("Morphing Survivor")
				Morph.SurvivorMorph(player, "MinWage")
			end
  • Module Script Code: (run on the server)
morphModule.KillerMorph = function(plr, killer)
	local charClone = Killers:FindFirstChild(killer):Clone()
	charClone.Name = plr.Name
	plr.Character:Destroy()
	plr.Character = charClone
	charClone.Parent = workspace
	charClone:FindFirstChild("HumanoidRootPart").Anchored = false
	charClone:MoveTo(plr.Character.HumanoidRootPart.Position)
	
	ShowMovesetGui:FireClient(plr, charClone)
	print("Firing to Client (Killer), "..plr.Name)
end
  • Client Code:
Events.ShowMovesetGui.OnClientEvent:Connect(function(character)
	print("Client recieved")
	
	local guiToShow = nil
	
	local coreName = character:FindFirstChild("CoreName")
	
	if coreName then
		for _, Gui in pairs(StarterGui.MovesetGui:GetDescendants()) do
			if Gui.Name == coreName.Value and Gui:IsA("Frame") then
				guiToShow = Gui
				--print("Name is equal")
			else
				--print("Name is not equal")
			end
		end
	end
	
	if guiToShow then
		guiToShow.Visible = true
	else
		return
	end
end)

Please help.
Thanks!

hey man, i think the better option here would be to avoid using remoteevents entirely and just networking states, then listening for those states on the client. for example, each player has their own states folder with something like a boolvalue named “Killer” inside, then use getpropertychangedsignal to listen for when the player is the killer, you could also add a childadded wait loop to check if a certain part was added that can confirm the player was morphed correctly inside of the players character.

also, please use generalized iteration & querydescendants.
generalized iteration makes it so that you don’t have to specify an iterator function, like pairs, ipairs, or next, and automatically picks the best for u. example: for key, value in table do ... end

querydescendants is a better more optimized version of getdescendants that allows for quicker & easier filtering between instances
i’m not too sure how multiple selectors work with it, but you could try somethiing like:

local CoreName = coreName.Value
local UI = StarterGui.MovesetGui:QueryDescendants(`#{CoreName} Frame`)[1]

the first selector here (#{CoreName} just gets every instance with that name, then the second thing is Frame which just filters it so that only Frame instances appear in the results. since querydescendants returns a table you index the result of htat by 1 and you have the UI without any for loops or anything.

good luck!

3 Likes

There’s no such thing: If server sends event, the client gets it (unless there are network issues, but that would appear in different and more noticeable areas also, like experience not loading and so on).

What can be an issue with the events: the receiver has not set listener yet.

For example, if you have this setup:

  1. event is “static” in, let’s say, ReplicatedStorage/Events/Event
  2. client does ReplicatedStorage.Events.Event.OnClientEvent(function() end)
  3. server does ReplicatedStorage.Events.Event:FireClient(player)

Then when you test this experience in studio, it’s impossible to be sure what’s being executed first 2. or 3. because of race conditions.

That’s a nice topic.
And since you, i am sure, like puzzles, leaving finding solution for you.
Thank you!

2 Likes

If client isnt almost receiving remote event, i would look into the server code. Specifically findfirstchild is killer. Because if it wont find it, it wont fire. You are certainly hitting a runtime condition here like @af_2048 said, however i would look into the server code if you havent yet.

Alternatively, we can evade remote events which is good in my opinion and follow @ruinedcenturies way by having a boolean and get a listener in.

ok figured out the missed remote thing, two things going on. one, KillerMorph reads HumanoidRootPart.Position AFTER destroying the old character which can just error and kill the rest of the function before it even gets to FireClient. two, if the morph happens before the client script connects (like right on spawn) the event just gets dropped, FireClient doesnt queue for late listeners

module script fix:

morphModule.KillerMorph = function(plr, killer)
	local charClone = Killers:FindFirstChild(killer):Clone()
	if not charClone then
		warn("No killer model found for:", killer)
		return
	end
	charClone.Name = plr.Name

	local oldChar = plr.Character
	local spawnPos = oldChar and oldChar:FindFirstChild("HumanoidRootPart") and oldChar.HumanoidRootPart.Position

	charClone.Parent = workspace
	plr.Character = charClone

	local hrp = charClone:FindFirstChild("HumanoidRootPart")
	if hrp then
		hrp.Anchored = false
		if spawnPos then
			charClone:MoveTo(spawnPos)
		end
	end

	if oldChar then
		oldChar:Destroy()
	end

	plr:SetAttribute("PendingMovesetGui", charClone.Name)
	ShowMovesetGui:FireClient(plr, charClone)
	print("Firing to Client (Killer), " .. plr.Name)
end

same thing for SurvivorMorph just swap the model lookup

client side just gotta catch the case where it already happened before we connected:

local function applyMoveset(character)
	local guiToShow = nil
	local coreName = character:FindFirstChild("CoreName")

	if coreName then
		for _, gui in pairs(StarterGui.MovesetGui:GetDescendants()) do
			if gui.Name == coreName.Value and gui:IsA("Frame") then
				guiToShow = gui
				break
			end
		end
	end

	if guiToShow then
		guiToShow.Visible = true
	end
end

Events.ShowMovesetGui.OnClientEvent:Connect(applyMoveset)

if player.Character then
	applyMoveset(player.Character)
end
player.CharacterAdded:Connect(applyMoveset)

also also double check this localscript is in StarterPlayerScripts and not inside the character model, if its under the character it dies every morph/respawn and takes the connection with it which honestly couldve been causing half the missed cases on its own

1 Like