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 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
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 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:
- 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
-
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.
-
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
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.