Custom material type listener using Humanoid.Touched keeps returning nil

So I am currently trying to modify CloneTrooper1019’s Realism module to accommodate custom materials outside of the standard Roblox materials.

Normally, the module uses Humanoid.FloorMaterial to detect the exact material that the player steps on, but since the custom materials would not register as Roblox materials, I created a CustomMaterial string attribute that will be detected by a Humanoid.Touched event.

So when a player steps on a part with a CustomMaterial attribute with a string value of “Carpet”, it’s supposed to pass that value to updateRunningSoundId to play the correct sound.

However, while it is able to print out the string attribute as seen in checkForCustomMaterial(), when it returns the string value to updateRunningSoundId(), it keeps returning nil.

Here is an excerpt from the RealismClient script of the module:

local function checkForCustomMaterial()
	local debounce = false
	humanoid.Touched:Connect(function(hit)
		if not debounce then
			debounce = not debounce
			
			local customAttr = hit:GetAttribute("CustomMaterial")

			if customAttr ~= nil then
				print(customAttr) -- this prints the attribute's name as intended
				return customAttr
			end
			
			debounce = not debounce
		end
	end)
end

local function updateRunningSoundId()
	local soundId = self.Sounds.Concrete
	local material = humanoid.FloorMaterial.Name

	local customMaterial = checkForCustomMaterial()
	print(customMaterial) -- even though the previous print() works, this keeps printing nil
	print()

	if customMaterial ~= nil then -- because customMaterial keeps returning nil, it doesn't play the proper walking sound
		material = customMaterial
	end
	
	if material ~= nil then
		if not self.Sounds[material] then
			material = self.MaterialMap[material]
		end

		if self.Sounds[material] then
			soundId = self.Sounds[material]
		end
	end
	
	running.SoundId = "rbxassetid://" .. soundId
end

If I return a value from checkForCustomMaterial() outside of the Humanoid.Touched event, it successfully goes into the customMaterial variable in updateRunningSoundId(). So I can’t understand why would it be unable to return the value if it is able to print the exact same value to the output?

Files and setup instructions below
realism_custom_materials_problem.rbxm (19.3 KB)

  • I’ve attached the Realism module and two carpet bricks for testing; one has the CustomMaterial (has a custom carpet texture on it) and one just uses the Roblox fabric material.
  • To set up, just place RealismServer in ServerScriptService and RealismClient in StarterPlayerScripts.

When you return customAttr, you’re returning the anonymous function inside the humanoid.Touched event, not the checkForCustomMaterial() function. Also for the sake of avoiding memory leaks and making the script a bit more straightforward, I would suggest this be done in reverse:

Listen for when Humanoid.FloorMaterial changes, and cast a ray down from the player’s PrimaryPart to check the part that’s currently underneath them. Check that part for a CustomMaterial attribute and call updateRunningSoundId(customMaterial).

Alternatively, because that probably would not work if two adjacent parts with the same Roblox material had different custom materials, you could probably make use of Humanoid.Touched like you already do in that script, but still keeping into account the process I mentioned above (Bind to Humanoid.Touched once, if hit part has CustomMaterial attribute, call updateRunningSoundId(customMaterial)).

1 Like