Viewmodel module breaks when another player joins the game

As the title says. I am working on a game and we have a viewmodel for the hands of our avatar and it works perfectly for the first player to join the game, but if another player joins it wont work for them. It will still work for the player who initially joined, but for the other player/s it will just make their viewmodel hands float and outputs an error into the console saying, “Script 'ReplicatedStorage.Modules.ViewmodelHandler:168: attempt to index nil with ‘Color’”

Here is the script:

local ViewmodelHandler = {}

local PhysicsService = game:GetService("PhysicsService")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local UserInputService = game:GetService("UserInputService")
local Workspace = game:GetService("Workspace")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid", 1)
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart", 1)
local LeftArm = Character:FindFirstChild("Left Arm") or Character:FindFirstChild("LeftHand")
local RightArm = Character:FindFirstChild("Right Arm") or Character:FindFirstChild("RightHand")
local Camera = Workspace.CurrentCamera

local Miscs = ReplicatedStorage:WaitForChild("Miscs")
local Modules = ReplicatedStorage:WaitForChild("Modules")

local Viewmodels = Miscs.Viewmodels

local Utilities = require(Modules.Utilities)
local Spring = Utilities.Spring
local Thread = Utilities.Thread
local Math = Utilities.Math

local ViewmodelStorage = Camera:FindFirstChild("ViewmodelStorage")
if not ViewmodelStorage then
	ViewmodelStorage = Instance.new("Folder")
	ViewmodelStorage.Name = "ViewmodelStorage"
	ViewmodelStorage.Parent = Camera
end

local AimAlpha = script.AimAlpha

local GeneralSettings = {
	CanSway = true;
	CanBobble = false;
	CanBreathe = true;
	CanAim = true;
	CanRecoil = true;

	RecoilYRotMax = 16;
	RecoilZPosMax = 1;
	RecoilYPosMax = 0.5;
	
	AimSwingSensitivity = 0.75;
	AimAnimationWeight = 0.75;
	
	ApplyCharacterClothing = true;
	ApplyCharacterMesh = true;
}

--legends:
--[s]: speed
--[d]: damper
--[t]: target
--[p]: position
--[v]: velocity
local SpeedSpring = Spring.spring.new()
SpeedSpring.s = 16
local VelocitySpring = Spring.spring.new(Vector3.new())
VelocitySpring.s = 16
VelocitySpring.t = Vector3.new()
VelocitySpring.p = Vector3.new()
local SwaySpring = Spring.spring.new(Vector3.new())
SwaySpring.s = 10
SwaySpring.d = 0.75

local OffStates = {"Jumping", "PlatformStanding", "Ragdoll", "Seated", "FallingDown", "FreeFalling", "GettingUp", "Swimming", "Climbing"}
local OnStates = {"Running"}

local CurrentViewmodel
local CurrentConfigs
local CurrentFakeCamera
local OldCamCF

local Velocity = Vector3.new()
local Speed = 0
local Distance = 0

local RecoilPower = 0
local XRot = 0
local YRot = 0
local ZRot = 0
local YPos = 0
local ZPos = 0
local RecoilCFrame = CFrame.new()

local OffStateConnections = {}
local OnStateConnections = {}

local AimPointTable = {}
local CurrentAimPoint
local Offset

local HasAimPoints = false
local IsAiming = false
local Transparent = false

for _, state in pairs(OffStates) do
	table.insert(OffStateConnections, Humanoid[state]:Connect(function()
		active = false
	end))
end

for _, state in pairs(OnStates) do
	table.insert(OnStateConnections, Humanoid[state]:Connect(function(speed)
		active = (speed > 1)
	end))
end

local function ViewmodelBob(a, r, baseWalkSpeed)
	local a, r = a or 1, r or 1
	local d, s, v = Distance * 6.28318 * 3 / 4, Speed, -Velocity
	--if s < baseWalkSpeed then
		local w = Vector3.new(r * math.sin(d / 4 - 1) / 256 + r * (math.sin(d / 64) - r * v.Z / 4) / 512, r * math.cos(d / 128) / 128 - r * math.cos(d / 8) / 256, r * math.sin(d / 8) / 128 + r * v.X / 1024) * s / 20 * 6.28318
		return CFrame.new(r * math.cos(d / 8 - 1) * s / 196, 1.25 * a * math.sin(d / 4) * s / 512, 0) * Math.FromAxisAngle(w)
	--else
		--local w = Vector3.new((r * math.sin(d / 4 - 1) / 256 + r * (math.sin(d / 64) - r * v.Z / 4) / 512) * s / 20 * 6.28318, (r * math.cos(d / 128) / 128 - r * math.cos(d / 8) / 256) * s / 20 * 6.28318, r * math.sin(d / 8) / 128 * (5 * s - 56) / 20 * 6.28318 + r * v.X / 1024)
		--return CFrame.new(r * math.cos(d / 8 - 1) * (5 * s - 56) / 196, 1.25 * a * math.sin(d / 4) * s / 512, 0) * Math.FromAxisAngle(w)
	--end
end

local function ViewmodelBreath(a)
	local d, s = os.clock() * 6, 2 * (1.2 - a)
	return CFrame.new(math.cos(d / 8) * s / 128, -math.sin(d / 4) * s / 128, math.sin(d / 16) * s / 64)
end

local function SetTextureTransparency(part, transparency)
	local p = part:GetChildren()
	for i = 1, #p do
		local v = p[i]
		if v:IsA("Texture") or v:IsA("Decal") then
			v.LocalTransparencyModifier = transparency
		end
	end
end

local function IsFirstPerson()
	return (Camera.Focus.p - Camera.CoordinateFrame.p).Magnitude <= 1
end

local function GetTool()
	return Character:FindFirstChildOfClass("Tool")	
end

function LoadAppearance(Viewmodel)
	local Viewmodel = Viewmodel
	Thread:Spawn(function()
		local Loaded = Player:HasAppearanceLoaded()
		while not Loaded do
			Loaded = Player:HasAppearanceLoaded()
			RunService.RenderStepped:Wait()
		end
		local HumanoidDescription = Humanoid:FindFirstChildOfClass("HumanoidDescription")
		while not HumanoidDescription do
			HumanoidDescription = Humanoid:FindFirstChildOfClass("HumanoidDescription")				
			RunService.RenderStepped:Wait()
		end
		if Viewmodel:FindFirstChild("Left Arm") and Viewmodel:FindFirstChild("Right Arm") then
			Viewmodel["Left Arm"].Color = LeftArm.Color
			Viewmodel["Right Arm"].Color = RightArm.Color
		end
		if GeneralSettings.ApplyCharacterClothing and not GeneralSettings.ApplyCharacterMesh then
			local Shirt = Character:FindFirstChild("Shirt")
			if Shirt then
				Shirt:Clone().Parent = Viewmodel
			end
		end
		if GeneralSettings.ApplyCharacterMesh then
			local successful, errorMessage = pcall(function()
				HumanoidDescription.ProportionScale = 0
				HumanoidDescription.BodyTypeScale = 0
				HumanoidDescription.HeightScale = 1
				HumanoidDescription.WidthScale = 1
				HumanoidDescription.DepthScale = 1
				Viewmodel.Humanoid:ApplyDescription(HumanoidDescription)
			end)
			if not successful then
				warn(errorMessage)
			else
				for _, Part in pairs(Viewmodel:GetDescendants()) do
					if Part:IsA("Accessory") or Part:IsA("ShirtGraphic") or Part:IsA("Pants") or (Part:IsA("Weld") and Part.Name == "HeadWeld") then
						Part:Destroy()
					else
						if not GeneralSettings.ApplyCharacterClothing and Part:IsA("Shirt") then
							Part:Destroy()
						end
					end
				end
			end
		end
	end)
end

function ViewmodelHandler:LoadAppearance()
	for _, child in pairs(CurrentViewmodel:GetDescendants()) do
		if child:IsA("Shirt") and GeneralSettings.ApplyCharacterClothing and not GeneralSettings.ApplyCharacterMesh then
			child:Destroy()
		end
	end
	LoadAppearance(CurrentViewmodel)
end

function ViewmodelHandler:RecoilViewmodel(value)
	RecoilPower = value
end

function ViewmodelHandler:SetAimEnabled(value, id, alignToAimPoint, tweenInfo)
	IsAiming = value
	if not alignToAimPoint then
		IsAiming = false
	end
	if HasAimPoints then
		CurrentAimPoint = AimPointTable[id].AimPoint
	end
	TweenService:Create(AimAlpha, tweenInfo, {Value = IsAiming and 1 or 0}):Play()
end

function ViewmodelHandler:SetViewmodelTransparent(Enabled)
	Transparent = Enabled
end

function ViewmodelHandler.SetUpViewmodel(viewmodelName)
	local Viewmodel
	if ViewmodelStorage:FindFirstChild("v_"..viewmodelName) then
		Viewmodel = ViewmodelStorage:FindFirstChild("v_"..viewmodelName)
	else
		Viewmodel = Viewmodels["v_"..viewmodelName]:Clone()
	end
	if Viewmodel and Viewmodel.PrimaryPart then
		CurrentConfigs = require(Viewmodel:FindFirstChild("Configs"))
		if Viewmodel:FindFirstChild("AimPoints") then
			if #Viewmodel.AimPoints:GetChildren() > 0 then
				local AimPoints = Viewmodel.AimPoints:GetChildren()
				table.sort(AimPoints, function(a, b)
					return tonumber(a.Name) < tonumber(b.Name)
				end)
				for i, v in ipairs(AimPoints) do
					table.insert(AimPointTable, {
						Id = i,
						AimPoint = v
					}) 
				end
				CurrentAimPoint = AimPointTable[1].AimPoint
				Offset = nil
				HasAimPoints = true
			end		
		end
		CurrentFakeCamera = Viewmodel:FindFirstChild("FakeCamera")
		for _, child in pairs(Viewmodel:GetDescendants()) do
			if child:IsA("Shirt") and GeneralSettings.ApplyCharacterClothing and not GeneralSettings.ApplyCharacterMesh then
				child:Destroy()
			end
			if not IsFirstPerson() then
				if child:IsA("Beam") or child:IsA("Trail") or child:IsA("ParticleEmitter") then
					if string.match(child.Name, "CHRG_") == nil and string.match(child.Name, "SmokeTrail") == nil and string.match(child.Parent.Name, "GunMuzzlePoint") == nil then
						child.Enabled = false
					end
				end
				if child:IsA("RodConstraint") or child:IsA("RopeConstraint") or child:IsA("SpringConstraint") then
					child.Visible = false
				end
				if child:IsA("BasePart") then
					child.LocalTransparencyModifier = 1
					SetTextureTransparency(child, 1)
				end
			else
				if child:IsA("Beam") or child:IsA("Trail") or child:IsA("ParticleEmitter") then
					if string.match(child.Name, "CHRG_") == nil and string.match(child.Name, "SmokeTrail") == nil and string.match(child.Parent.Name, "GunMuzzlePoint") == nil then
						child.Enabled = true
					end
				end
				if child:IsA("RodConstraint") or child:IsA("RopeConstraint") or child:IsA("SpringConstraint") then
					child.Visible = true
				end
				if child:IsA("BasePart") then
					child.LocalTransparencyModifier = 0
					SetTextureTransparency(child, 0)
				end
			end
			if child:IsA("BasePart") then
				PhysicsService:SetPartCollisionGroup(child, "Viewmodel")
			end
		end
		Viewmodel.PrimaryPart.Anchored = true
		if Camera.CameraType == Enum.CameraType.Custom then
			local Offset = CurrentConfigs and CurrentConfigs.Offset or CFrame.new(0, 0, 0)
			Viewmodel.PrimaryPart.CFrame = (Camera.CoordinateFrame * CFrame.new(0, 0, (Camera.FieldOfView / 90 - 1) * 0.3)) * Offset
		end
		Viewmodel.Parent = ViewmodelStorage
		LoadAppearance(Viewmodel)
		CurrentViewmodel = Viewmodel
		return Viewmodel
	end
	return nil
end

local function RenderViewmodel()
	if CurrentViewmodel and CurrentViewmodel.PrimaryPart then
		if CurrentFakeCamera then
			if IsFirstPerson() then
				local NewCamCF = CurrentFakeCamera.CFrame:ToObjectSpace(CurrentViewmodel.PrimaryPart.CFrame)
				if OldCamCF then
					--Camera.CFrame = Camera.CFrame * NewCamCF:ToObjectSpace(NewCamCF)
					local _, _, Z = NewCamCF:ToOrientation()
					local X, Y, _ = NewCamCF:ToObjectSpace(OldCamCF):ToEulerAnglesXYZ()
					Camera.CFrame = Camera.CFrame * CFrame.Angles(X, Y, -Z)
				end
				OldCamCF = NewCamCF
				--else
				--Camera.CFrame = Camera.CFrame
			end		
		end
		for _, child in pairs(CurrentViewmodel:GetDescendants()) do
			if not IsFirstPerson() then
				if child:IsA("Beam") or child:IsA("Trail") or child:IsA("ParticleEmitter") then
					if string.match(child.Name, "CHRG_") == nil and string.match(child.Name, "SmokeTrail") == nil and string.match(child.Parent.Name, "GunMuzzlePoint") == nil then
						child.Enabled = false
					end
				end
				if child:IsA("RodConstraint") or child:IsA("RopeConstraint") or child:IsA("SpringConstraint") then
					child.Visible = false
				end
				if child:IsA("BasePart") then
					child.LocalTransparencyModifier = 1
					SetTextureTransparency(child, 1)
				end
			else				
				if child:IsA("Beam") or child:IsA("Trail") or child:IsA("ParticleEmitter") then
					if string.match(child.Name, "CHRG_") == nil and string.match(child.Name, "SmokeTrail") == nil and string.match(child.Parent.Name, "GunMuzzlePoint") == nil then
						child.Enabled = not Transparent
					end
				end
				if child:IsA("RodConstraint") or child:IsA("RopeConstraint") or child:IsA("SpringConstraint") then
					child.Visible = not Transparent
				end
				if child:IsA("UnionOperation") or child:IsA("MeshPart") or child:IsA("BasePart") then
					local TransMod = Transparent and 1 or 0
					child.LocalTransparencyModifier = TransMod
					SetTextureTransparency(child, TransMod)
				end
			end
		end
		local Tool = GetTool()
		if Tool then
			for _, child in pairs(Tool:GetDescendants()) do
				if not IsFirstPerson() then
					if child:IsA("Beam") or child:IsA("Trail") or child:IsA("ParticleEmitter") then
						if string.match(child.Name, "CHRG_") == nil and string.match(child.Name, "SmokeTrail") == nil and string.match(child.Parent.Name, "GunMuzzlePoint") == nil then
							child.Enabled = true
						end
					end
					if child:IsA("RodConstraint") or child:IsA("RopeConstraint") or child:IsA("SpringConstraint") then
						child.Visible = true
					end
					if child:IsA("BasePart") then
						child.LocalTransparencyModifier = 0
					end
					SetTextureTransparency(child, 0)
				else
					if child:IsA("Beam") or child:IsA("Trail") or child:IsA("ParticleEmitter") then
						if string.match(child.Name, "CHRG_") == nil and string.match(child.Name, "SmokeTrail") == nil and string.match(child.Parent.Name, "GunMuzzlePoint") == nil then
							child.Enabled = false
						end
					end
					if child:IsA("RodConstraint") or child:IsA("RopeConstraint") or child:IsA("SpringConstraint") then
						child.Visible = false
					end
					if child:IsA("BasePart") then
						child.LocalTransparencyModifier = 1
					end
					SetTextureTransparency(child, 1)
				end
			end			
		end	
	end
end

function ViewmodelHandler:CullViewmodel(viewmodel)
	if viewmodel and viewmodel.PrimaryPart then
		if CurrentViewmodel == viewmodel then
			CurrentViewmodel = nil
			CurrentConfigs = nil
			CurrentFakeCamera = nil
			OldCamCF = nil
			CurrentAimPoint = nil
			Offset = nil
			HasAimPoints = false
			table.clear(AimPointTable)
			AimAlpha.Value = 0
		end
		viewmodel.PrimaryPart.CFrame = CFrame.new(math.huge, math.huge, math.huge) * CFrame.Angles(0, 0, 0)
	end
end

function ViewmodelHandler:DestroyViewmodel(viewmodel)
	if viewmodel then
		if CurrentViewmodel == viewmodel then
			CurrentViewmodel = nil
			CurrentConfigs = nil
			CurrentFakeCamera = nil
			OldCamCF = nil
			CurrentAimPoint = nil
			Offset = nil
			HasAimPoints = false
			table.clear(AimPointTable)
			AimAlpha.Value = 0
		end
		viewmodel:Destroy()		
	end
end

Player.CharacterAdded:Connect(function(character)
	Character = character
	Humanoid = Character:WaitForChild("Humanoid", 1)
	HumanoidRootPart = Character:WaitForChild("HumanoidRootPart", 1)
	LeftArm = Character:FindFirstChild("Left Arm") or Character:FindFirstChild("LeftHand")
	RightArm = Character:FindFirstChild("Right Arm") or Character:FindFirstChild("RightHand")
	for i, v in pairs(OffStateConnections) do
		if v then
			v:Disconnect()
		end
		table.remove(OffStateConnections, i)
	end
	for i, v in pairs(OnStateConnections) do
		if v then
			v:Disconnect()
		end
		table.remove(OnStateConnections, i)
	end
	for _, state in pairs(OffStates) do
		table.insert(OffStateConnections, Humanoid[state]:Connect(function()
			active = false
		end))
	end
	for _, state in pairs(OnStates) do
		table.insert(OnStateConnections, Humanoid[state]:Connect(function(speed)
			active = (speed > 1)
		end))
	end
end)

RunService.RenderStepped:Connect(function(dt)
	if CurrentViewmodel and CurrentViewmodel.PrimaryPart and Character and Humanoid and HumanoidRootPart then		
		local MouseDelta = UserInputService:GetMouseDelta()
		
		RecoilPower = RecoilPower > 0.1 and Math.Lerp(RecoilPower, 0, dt * 11) or 0
		SwaySpring.t = Vector3.new(VelocitySpring.v.Z / 1024 / 32 + VelocitySpring.v.Y / 1024 / 16 + (MouseDelta.Y / 10) / 1024 * 3 / 2, VelocitySpring.v.X / 1024 / 32 + (MouseDelta.X / 10) / 1024 * 3 / 2, -(MouseDelta.X / 10) / 1024 * 3 / 2)
		local RelativeVelocity = CFrame.new().VectorToObjectSpace(HumanoidRootPart.CFrame, HumanoidRootPart.Velocity)
		SpeedSpring.t = (active and Humanoid.Health > 0) and (Vector3.new(1, 0, 1) * RelativeVelocity).Magnitude or 0
		VelocitySpring.t = RelativeVelocity
		Speed = SpeedSpring.p
		Distance = Distance + dt * SpeedSpring.p
		Velocity = VelocitySpring.p
		
		YRot = Math.Lerp(YRot, GeneralSettings.RecoilYRotMax * RecoilPower, RecoilPower == 0 and dt * 7 or dt * 6) + Math.Lerp(XRot, Math.Randomize(2) * RecoilPower, RecoilPower == 0 and dt * 7 or dt / 2)
		XRot = Math.Lerp(XRot, Math.Randomize(1.3) * RecoilPower, RecoilPower == 0 and dt * 7 or dt * 3)
		ZRot = Math.Lerp(ZRot, Math.Randomize(5) * RecoilPower, RecoilPower == 0 and dt * 7 or dt / 3)
		YPos = Math.Lerp(YPos, GeneralSettings.RecoilYPosMax * RecoilPower, RecoilPower == 0 and dt * 7 or dt * 0.4)
		ZPos = Math.Lerp(ZPos, GeneralSettings.RecoilZPosMax * RecoilPower, RecoilPower == 0 and dt * 7 or dt * 0.9)
		RecoilCFrame = CFrame.new(0, YPos, ZPos) * CFrame.Angles(math.rad(YRot), XRot, ZRot)
		
		local AimOffset = CFrame.new() --* CFrame.new(0, -1.5, 0)
		local AimCFrame = CFrame.new()
		local CF = CFrame.new()
		CF = Camera.CoordinateFrame * CFrame.new(0, 0, (Camera.FieldOfView / 90 - 1) * 0.3)
		if GeneralSettings.CanSway then
			CF = CF * Math.FromAxisAngle(SwaySpring.v)
		end
		if GeneralSettings.CanBobble then
			CF = CF * ViewmodelBob(0.7 - 0.3 * AimAlpha.Value, 1 - 0.8 * AimAlpha.Value, Humanoid.WalkSpeed)
		end
		if GeneralSettings.CanBreathe then
			CF = CF * ViewmodelBreath(AimAlpha.Value)
		end
		if GeneralSettings.CanAim then
			if IsAiming then
				MouseDelta = MouseDelta * GeneralSettings.AimSwingSensitivity
			end
			if CurrentAimPoint then
				Offset = (Offset or CFrame.new()):Lerp(CurrentViewmodel.PrimaryPart.CFrame:ToObjectSpace(CurrentAimPoint.CFrame * AimOffset):Inverse(), math.clamp(1 - GeneralSettings.AimAnimationWeight, 0, 1))
				AimCFrame = AimCFrame * AimCFrame:Lerp(Offset, AimAlpha.Value)
			end
		end
		if GeneralSettings.CanRecoil then
			CF = CF * RecoilCFrame
		end
		local Offset = CurrentConfigs and CurrentConfigs.Offset or CFrame.new(0, 0, 0)
		local Offst = Math.Interpolator(Offset)
		CF = CF * Offst(1 - AimAlpha.Value)
		if Camera.CameraType == Enum.CameraType.Custom then
			local CamOffset = -Humanoid.CameraOffset
			local ShakeX = math.clamp(CamOffset.X * 0.5, -0.25, 0.25)
			local ShakyY = math.clamp(CamOffset.Y * 0.5, -0.25, 0.25)
			local ShakeZ = math.clamp(CamOffset.Z * 0.5, -0.25, 0.25)
			CurrentViewmodel.PrimaryPart.CFrame = CF * AimCFrame * CFrame.new(ShakeX, ShakyY, ShakeZ)
		end
		RenderViewmodel()
	end
end)

return ViewmodelHandler

THIS IS THE PROBLEM LINE:

	if Viewmodel:FindFirstChild("Left Arm") and Viewmodel:FindFirstChild("Right Arm") then
			Viewmodel["Left Arm"].Color = LeftArm.Color
	                Viewmodel["Right Arm"].Color = RightArm.Color
	end

We have already tried changing the ''FindFirstChild" to “WaitForChild”, but we didnt have any luck with that and still got the error.

Something to note, our game doesnt automatically spawn the players. The player joins to a screengui containing a team select and only spawns in when they select a team. We tried it with this system disabled and it did work, however we have no idea what is causing it not to work especially since we tried “WaitForChild” and it still didnt work, and it still doesnt explain why it works for one player, but not the others who join after them.

Does anyone have any ideas?

1 Like