Introduction
After Roblox had announced the new feature of hiding particles of non-Tool objects in first-person mode, many people were dismayed to see that there was no special tag/property for exception handling when it came to hiding particles on certain objects. This problem was especially apparent for games whose weapons were not based on the Tool object such as a one I was helping develop.
For a while I had no solution to the problem until recently.
Part 1: Understanding How Particles are Hidden
All of the stock movement and camera controls you see when you open up a Baseplate are dictated by a ModuleScript named PlayerModule that is loaded by the LocalScript PlayerScriptsLoader.
The ModuleScript within PlayerModule named TransparencyController, as its name suggests, handles the transparency of objects on the client. First-Person particle exception handling is managed by function HasToolAncestor.
function TransparencyController:HasToolAncestor(object: Instance)
if object.Parent == nil then return false end
assert(object.Parent, "")
return object.Parent:IsA('Tool') or self:HasToolAncestor(object.Parent)
end
Therefore, we must change TransparencyController to manage particle hiding in first-person differently. Additionally, we must change PlayerScriptsLoader to override the default TransparencyController before initializing the PlayerModule.
Copy these scripts during runtime and paste them after stopping.
Part 2: What to Change
TransparencyController requires minimal change, only needing to add an additional exception for the HasToolAncestor function. For me, I added a check to see if a part’s ancestor’s name is Handle, as all custom weapons have an invisible Handle Part as the Parent for all of the weapon.
function TransparencyController:HasToolAncestor(object: Instance)
if object.Parent == nil then return false end
assert(object.Parent, "")
return object.Parent:IsA('Tool') or object.Parent.Name == "Handle" or self:HasToolAncestor(object.Parent)
end
In Roblox, if you place a script in StarterPlayerScripts/StarterCharacterScripts that has the name of a default script, your custom script will override the default one. Your modified PlayerScriptsLoader MUST be in StarterPlayerScripts before any players join for this to work.
To prevent having to manually replace all of the PlayerModule each time Roblox changes it, we will be adjusting PlayerScriptsLoader to override default PlayerModule ModuleScritps before requiring the PlayerModule only if custom versions exist.
Place your modified TransparencyController as a child of the PlayerScriptsLoader you will modify. PlayerScriptsLoader should be modified to replace all scripts in PlayerModule of the same name of its children before requiring PlayerModule. I will provide my code for example.
local plrs = game:GetService("Players")
--
local plr = plrs.LocalPlayer
local pMod = script.Parent:WaitForChild("PlayerModule")
--
for _, p in script:GetChildren() do
local m = pMod:FindFirstChild(p.Name, true)
if not m then
repeat m = pMod:FindFirstChild(p.Name, true); task.wait() until m
end
local par = m.Parent
m:Destroy()
p:Clone().Parent = par
end
require(pMod)
Part 3: Verify the Adjustments Work
If all is done correct, particles should now work in first-person if objects meet the given exception for hiding. Enjoy!