For loop puts all models inside of 1 model

That error is saying NPC is nil. All you did by using FindFirstChild to access the “Character” child was prevent the index error from rising. The function call instead resulted in nil. You may be trying to access the “Character” child prematurely. Please send your full script(s)

hate to admit it but I really don’t understand that at all. I can send my scripts or I can send you the model link that I used for the prompt / UI service for the characters. which one would be best for you to help?

Your scripts are more relevant to the problem

here you go

local ShowUIEvent = game:GetService("ReplicatedStorage"):WaitForChild("HumanoidDescription")
local TryOutfitEvent = game:GetService("ReplicatedStorage"):WaitForChild("TryOutfit")
local Runs = game:GetService("RunService")
local CloseSound = script:WaitForChild("Close")
local WearSound = script:WaitForChild("Wear")
local WooshSound = script:WaitForChild("Woosh")
local viewportModelRotator = require(game.ReplicatedStorage.ViewportRotation)

local NPC = nil

----------------------------------[[ VIEWPORT PORTION ]]------------------------------

-- Settings
local OFFSET = CFrame.new(0,2.5,-7)

-- Services
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")

-- Objects
local ViewPort = script.Parent.ImageLabel:WaitForChild("ViewportFrame")
local Camera = Instance.new("Camera")
ViewPort.CurrentCamera	= Camera

local ValidClasses = {
	["MeshPart"] = true; ["Part"] = true; ["Accoutrement"] = true;
	["Pants"] = true; ["Shirt"] = true;
	["Humanoid"] = true;
}

local RenderObjects = table.create(25)

local function RemoveObject(Object)
	local Clone = RenderObjects[Object]
	if not Clone then return nil end

	RenderObjects[Object] = nil
	if Clone.Parent:IsA("Accoutrement") then
		Clone.Parent:Destroy()
	else
		Clone:Destroy()
	end

	--print("Removed",Object)
end

local function AddObject(Object)
	if not ValidClasses[Object.ClassName] then
		return nil
	end

	-- Create clone, regardless of Archivable
	local a = Object.Archivable
	Object.Archivable = true
	local RenderClone = Object:Clone()
	Object.Archivable = a

	if Object.ClassName == "MeshPart" or Object.ClassName == "Part" then
		RenderObjects[Object] = RenderClone

	elseif Object:IsA("Accoutrement") then
		RenderObjects[Object.Handle] = RenderClone.Handle

	elseif Object.ClassName == "Humanoid" then
		--Disable all states. We only want it for clothing wrapping.
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.FallingDown,			false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Running,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.RunningNoPhysics,	false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Climbing,			false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.StrafingNoPhysics,	false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Ragdoll,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.GettingUp,			false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Jumping,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Landed,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Flying,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Freefall,			false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Seated,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.PlatformStanding,	false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Dead,				false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Swimming,			false)
		RenderClone:SetStateEnabled(Enum.HumanoidStateType.Physics,				false)
		RenderClone.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
	end

	--print("Added",Object)

	return RenderClone
end

----------------------------------[[ EVENT PORTION ]]------------------------------


ShowUIEvent.OnClientEvent:Connect(function(NPCEvent)
	
	
	NPC = NPCEvent
	WooshSound:Play()
	script.Parent.Visible = true
	
	----------------------------------[[ VIEWPORT PORTION ]]------------------------------
	
	
	RunService.Heartbeat:Connect(function()
		if (not NPC:FindFirstChild("HumanoidRootPart")) or (not ViewPort.Visible) then
			return nil
		end

		-- Update camera
		Camera.CFrame = CFrame.new(NPC.HumanoidRootPart.CFrame:ToWorldSpace(OFFSET).Position, NPC.HumanoidRootPart.Position)

		-- Update objects
		for Original, Clone in pairs(RenderObjects) do
			if Original and Original.Parent then
				Clone.CFrame = Original.CFrame
			else
				RemoveObject(Original)
			end
		end
	end)

	local function HandleChar()
		--warn("Handle char")

		table.clear(RenderObjects)
		ViewPort:ClearAllChildren()

		local Viewmodel = Instance.new("Model")
		Viewmodel.Name = "PlayerViewmodel"
		Viewmodel.Parent = ViewPort

		local CharObjects = NPC:GetDescendants()
		for i, Object in pairs(CharObjects) do
			
			local RenderClone = AddObject(Object)
			if RenderClone then
				RenderClone.Parent = Viewmodel
			end
			
		end

		NPC.DescendantAdded:Connect(function(NewObject)
			local RenderClone = AddObject(NewObject)
			if RenderClone then
				RenderClone.Parent = Viewmodel
			end
		end)
		NPC.DescendantRemoving:Connect(function(OldObject)
			RemoveObject(OldObject)
		end)
		
		
	end
	
	HandleChar()
	
	----------------------------------[[ ACCESSORIES PORTION ]]------------------------------
	

	
	for _, Child in ipairs(script.Parent.ScrollingFrame:GetChildren()) do
		if Child:IsA("Frame") then
			Child:Destroy()
		end
	end

	local Accessories = {}
	local Accessories2 = {}

	local Backs = NPC.Humanoid:WaitForChild("HumanoidDescription").BackAccessory
	local BacksTable = Backs:split(",")
	for _, Back in ipairs(BacksTable) do
		if Back ~= 0 then
			if tonumber(Back) then
				table.insert(Accessories, Back)
			end
		end
	end	

	local Face = NPC.Humanoid:WaitForChild("HumanoidDescription").FaceAccessory
	local FaceTable = Face:split(",")
	for _, FaceAC in ipairs(FaceTable) do
		if FaceAC ~= 0 then
			if tonumber(FaceAC) then
				table.insert(Accessories, FaceAC)
			end
		end
	end	

	local Fronts = NPC.Humanoid:WaitForChild("HumanoidDescription").FrontAccessory
	local FrontsTable = Fronts:split(",")
	for _, Front in ipairs(FrontsTable) do
		if Front ~= 0 then
			if tonumber(Front) then
				table.insert(Accessories, Front)
			end
		end	
	end

	local Hairs = NPC.Humanoid:WaitForChild("HumanoidDescription").HairAccessory
	local HairsTable = Hairs:split(",")
	for _, Hair in ipairs(HairsTable) do
		if Hair ~= 0 then
			if tonumber(Hair) then
				table.insert(Accessories, Hair)
			end
		end
	end

	local Hats = NPC.Humanoid:WaitForChild("HumanoidDescription").HatAccessory
	local HatsTable = Hats:split(",")
	for _, Hat in ipairs(HatsTable) do
		if Hat ~= 0 then
			if tonumber(Hat) then
				table.insert(Accessories, Hat)
			end
		end
	end

	local Necks = NPC.Humanoid:WaitForChild("HumanoidDescription").NeckAccessory
	local NecksTable = Necks:split(",")
	for _, Neck in ipairs(NecksTable) do
		if Neck ~= 0 then
			if tonumber(Neck) then
				table.insert(Accessories, Neck)
			end
		end
	end

	local Shoulders = NPC.Humanoid:WaitForChild("HumanoidDescription").ShouldersAccessory
	local ShouldersTable = Shoulders:split(",")
	for _, Shoulder in ipairs(ShouldersTable) do
		if Shoulder ~= 0 then
			if tonumber(Shoulder) then
				table.insert(Accessories, Shoulder)
			end
		end
	end

	local Waists = NPC.Humanoid:WaitForChild("HumanoidDescription").WaistAccessory
	local WaistsTable = Waists:split(",")
	for _, Waist in ipairs(WaistsTable) do
		if Waist ~=  0 then
			if tonumber(Waist) then
				table.insert(Accessories, Waist)
			end
		end
	end

	local Face = NPC.Humanoid:WaitForChild("HumanoidDescription").Face
	if tonumber(Face) then
		table.insert(Accessories, Face)
	end	

	local Shirt = NPC.Humanoid:WaitForChild("HumanoidDescription").Shirt
	if tonumber(Shirt) then
		table.insert(Accessories, Shirt)
	end	

	local Pants = NPC.Humanoid:WaitForChild("HumanoidDescription").Pants
	if tonumber(Pants) then
		table.insert(Accessories, Pants)
	end	

	local GraphicTShirt = NPC.Humanoid:WaitForChild("HumanoidDescription").GraphicTShirt
	if tonumber(GraphicTShirt) then
		table.insert(Accessories, GraphicTShirt)
	end	
	
	local AdditionalAccessories = NPC.Humanoid:WaitForChild("HumanoidDescription"):GetAttribute("ExtraAccessories")
	if AdditionalAccessories then
		local ExtraTable = AdditionalAccessories:split(",")
		for _, Extra in ipairs(ExtraTable) do
			if Extra ~=  0 then
				if tonumber(Extra) then
					table.insert(Accessories, Extra)
				end
			end
		end
	end
	
	local BuggedAccessories = NPC.Humanoid:WaitForChild("HumanoidDescription"):GetAttribute("Priceless")
	if BuggedAccessories then
		local BuggedTable = BuggedAccessories:split(",")
		for _, Bugged in ipairs(BuggedTable) do
			if Bugged ~=  0 then
				if tonumber(Bugged) then
					table.insert(Accessories2, Bugged)
				end
			end
		end
	end

	local AddedTable = {}

	for _, ID in ipairs(Accessories) do
		if ID ~= 0 then
			if tonumber(ID) then
				if not table.find(AddedTable, ID) then
					table.insert(AddedTable, ID)
					local Template = script.Template

					local NewTemplate = Template:Clone()
					NewTemplate.ProductIDVal.Value = ID
					NewTemplate.AssetIcon.Image = "https://www.roblox.com/asset-thumbnail/image?assetId=" .. ID .. "&width=420&height=420&format=png"

					NewTemplate.Parent = script.Parent.ScrollingFrame
				end
			end
		end
	end
	
	print("Finished first table")
	
	for _, ID in ipairs(Accessories2) do
		print("Going through accessories2")
		if ID ~= 0 then
			print("ID ~= 0")
			if tonumber(ID) then
				print("Got ID")
				if not table.find(AddedTable, ID) then
					print("Creating button")
					table.insert(AddedTable, ID)
					local Template = script.Template

					local NewTemplate = Template:Clone()
					NewTemplate.ProductIDVal.Value = ID
					NewTemplate.AssetIcon.Image = "https://www.roblox.com/asset-thumbnail/image?assetId=" .. ID .. "&width=420&height=420&format=png"
					NewTemplate.Cost.Text = "Offsale"

					NewTemplate.Parent = script.Parent.ScrollingFrame
				end
			end
		end
	end
	
end)

----------------------------------[[ CLOSE/TRY PORTION ]]------------------------------

local CloseButton = script.Parent:WaitForChild("Close")
local TryButton = script.Parent:WaitForChild("Try")

TryButton.Activated:Connect(function()
	TryOutfitEvent:FireServer(NPC)
	WearSound:Play()
end)

CloseButton.Activated:Connect(function()
	script.Parent.Visible = false
	CloseSound:Play()
end)
local ReplicatedFirst = game:GetService("ReplicatedFirst")
local ShowUIEvent = game:GetService("ReplicatedStorage"):WaitForChild("HumanoidDescription")
local TryOutfitEvent = game:GetService("ReplicatedStorage"):WaitForChild("TryOutfit")

local OutfitsFolder = ReplicatedFirst:WaitForChild("Outfits")
local Row1Folder = OutfitsFolder:WaitForChild("Row1")
local Row2Folder = OutfitsFolder:WaitForChild("Row2")
local Row3Folder = OutfitsFolder:WaitForChild("Row3")
local Row4Folder = OutfitsFolder:WaitForChild("Row4")
local Row5Folder = OutfitsFolder:WaitForChild("Row5")
local Row6Folder = OutfitsFolder:WaitForChild("Row6")
local CreatorPicksFolder = OutfitsFolder:WaitForChild("CreatorPicks")

local MainFolder = game:GetService("Workspace"):WaitForChild("Main")
local Outfits = MainFolder:WaitForChild("Outfits")
local Row1 = Outfits:WaitForChild("Row1")
local Row2 = Outfits:WaitForChild("Row2")
local Row3 = Outfits:WaitForChild("Row3")
local Row4 = Outfits:WaitForChild("Row4")
local Row5 = Outfits:WaitForChild("Row5")
local Row6 = Outfits:WaitForChild("Row6")
local CreatorPicks = Outfits:WaitForChild("CreatorPicks")

wait(1)
local CharactersArray = ReplicatedFirst:WaitForChild("Outfits"):WaitForChild("Row1Characters"):GetChildren()
local PodiumsArray = Row1:GetChildren()

for index, character in CharactersArray do
	
	local podium = assert(PodiumsArray[index], "Insufficent number of podiums.")
	character.Parent = podium
end
local ReplicatedFirst = game:GetService("ReplicatedFirst")
local ShowUIEvent = game:GetService("ReplicatedStorage"):WaitForChild("HumanoidDescription")
local TryOutfitEvent = game:GetService("ReplicatedStorage"):WaitForChild("TryOutfit")

local OutfitsFolder = ReplicatedFirst:WaitForChild("Outfits")
local Row1Folder = OutfitsFolder:WaitForChild("Row1")
local Row2Folder = OutfitsFolder:WaitForChild("Row2")
local Row3Folder = OutfitsFolder:WaitForChild("Row3")
local Row4Folder = OutfitsFolder:WaitForChild("Row4")
local Row5Folder = OutfitsFolder:WaitForChild("Row5")
local Row6Folder = OutfitsFolder:WaitForChild("Row6")
local CreatorPicksFolder = OutfitsFolder:WaitForChild("CreatorPicks")

local MainFolder = game:GetService("Workspace"):WaitForChild("Main")
local Outfits = MainFolder:WaitForChild("Outfits")
local Row1 = Outfits:WaitForChild("Row1")
local Row2 = Outfits:WaitForChild("Row2")
local Row3 = Outfits:WaitForChild("Row3")
local Row4 = Outfits:WaitForChild("Row4")
local Row5 = Outfits:WaitForChild("Row5")
local Row6 = Outfits:WaitForChild("Row6")
local CreatorPicks = Outfits:WaitForChild("CreatorPicks")

--Row1:FindFirstChild("DistancePart"):Destroy()
Row2:FindFirstChild("DistancePart"):Destroy()
Row3:FindFirstChild("DistancePart"):Destroy()
Row4:FindFirstChild("DistancePart"):Destroy()
Row5:FindFirstChild("DistancePart"):Destroy()
Row6:FindFirstChild("DistancePart"):Destroy()
CreatorPicks:FindFirstChild("DistancePart"):Destroy()

wait(1)
for _, v in ipairs(Row1Folder:GetChildren()) do
	if v:IsA("Model") and v.Name == "Podium" then
		
		
		v.Parent = Row1
	end
end


task.wait(3)
for _, v in ipairs(Row1:GetChildren()) do
	if v:IsA("Model") then

		local newProximityPrompt = Instance.new("ProximityPrompt")
		newProximityPrompt.ActionText = ""
		newProximityPrompt.HoldDuration = 0.5
		newProximityPrompt.MaxActivationDistance = 5
		newProximityPrompt.Parent = v:WaitForChild("ProximityPart")

		local takeScript = v:WaitForChild("ProximityPart"):WaitForChild("takeScript")
		takeScript.Parent = v:WaitForChild("ProximityPart"):WaitForChild("ProximityPrompt")

		print("made prompt")

		newProximityPrompt.Triggered:Connect(function(Player)

			local NPC = takeScript.Parent.Parent.Parent:FindFirstChild("Character")
			local Character = Player.Character
			ShowUIEvent:FireClient(Player, NPC)
		end)

		TryOutfitEvent.OnServerEvent:Connect(function(Player, NPC)

			local Character = Player.Character
			if NPC == takeScript.Parent.Parent.Parent.Character then
				local Desc = takeScript.Parent.Parent.Parent.Character.Humanoid:GetAppliedDescription()
				if Desc and Character then
					Character:WaitForChild("Humanoid"):ApplyDescription(Desc)
				end
			end
			
			newProximityPrompt.Enabled = false
			task.wait(0.1)
			newProximityPrompt.Enabled = true
		end)
	end
end

I know some of it’s formatted horrible so don’t attack me on that please :sob: but that’s all the scripts that relate to the character. everything else is just little effects for marketplace service when they purchase something which has no correlation to the character so I decided to leave those out

If you already had that array from @Ziffixture, can’t you just? I presume your podiums are named “Podium1” and so on and so forth.

local index_str = string.remove(takeScript.Parent.Parent.Parent.Name, "Podium")
local NPC = characters[tonumber(index_str)]

my podiums are all named “Podium” there are no numbers involved

Try naming them from 1 to 28 or do it automatically via a script. It should work. Otherwise, you would have to create a function that finds the player, but I don’t know how that would work.

Hello, there is a simple fix to this. Put all the podiums into a folder and the characters into another folder, ill refer to podiumFolder and characterFolder in the script, but make sure to change it to whatever the actually folder is located and named:

local charFolder = game.workspace.characterFolder:GetChildren()
for i, podium in pairs(podiumFolder:GetChildren()) do
 charFolder[i].Parent = podium
end

Explanation:
The for loop goes through each individual podium and sets the value of “podium” to that object, then we can use that podium variable to set the character’s parent to it since there are 28 podiums and 28 characters that means the first character will be set to the first podium, the second with second and so on.
This way you won’t have to change the names of the podium or characters.

but I’m not trying to find the player? if you think by “character” I mean the players character, that isn’t right. It’s a character model that would hold accessories, hair and what not

Your system seems extremely disorganized. Why don’t we hop into a Discord server like Roblox Studio Community or HiddenDevs, that way we can solve this issue more effectively. Additionally, you can add me @Ziffix

I’m pretty sure this is just going to do what Ziffixture already fixed for me. where all my characters would just go into one podium, he fixed that for me with a very similar script. my issue now is I get a error saying that Character isn’t a valid member of the podium for some reason and that’s what we’re trying to figure out right now

The characters wouldn’t go into one podium cause the parents of each character are set different from eachother.

They were referring to the original issue, not your code

1 Like

My mistake, the code I gave would automatically give the character model instead of the player. My bad.

alright that works, thank you. and yes it’s very disorganized but I’m used to it now :sob:I’ll add you right now my user is @unsinless

A whopping two hours later, we’ve arrived at a solution.

Here’s what went wrong:

Original problem:

  1. The original problem was patched with the following code:
local characters = -- Array of characters
local podiums    = -- Array of podiums

for index, character in characters do
    local podium = assert(podiums[index], "Insufficient number of podiums.")
  
    character.Parent = podium
end

Additional problems

  1. The code responsible for moving mannequins to podiums was client-sided. When the client requested to view the mannequin’s clothes, the server would attempt to access the mannequin at the podium. Of course, the mannequin isn’t there. This was patched by moving the code to the server. Doing so returned issues with mannequin loading, and after experimenting with streaming modes, Workspace.StreamingEnabled was eventually turned off.

  2. The mannequins were hand-positioned to a random set of podiums and left in ReplicatedStorage. As they were parented to their new podiums in workspace, their position would remain at another. This lead to an additional issue with outfit display requests showing the wrong mannequin. This was patched by retrofitting the podiums with parts that set a position and orientation a mannequin should assume when parented to that podium.

Additional improvements were made to the system all-around

4 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.