require(game.ReplicatedFirst.ReadyModule) local shopGui = script.Parent _G.ShopGui = shopGui local shopFrame = shopGui.Items local shopMaterial = shopGui.CashLabel local shopBackButton = shopGui.BackButton local shopSearch = shopGui.Search -- Parts local partsStore = _G.Storage:WaitForChild("Parts") local namedFrames = {} local directNamedFrames = {} local folders = {} local currentFolder = partsStore local currentTerm = "" local function createItemFrame(item) local defaultFrame = shopFrame.Grid.ItemFrame defaultFrame.Visible = false -- Create ViewportFrame and put a camera in local itemFrame = defaultFrame:Clone() itemFrame.Parent = shopFrame itemFrame.ItemLabel.Text = item:GetAttribute("Name") or item.Name itemFrame.Visible = true if not item:HasTag("ConnectorObject") then itemFrame.PolyLabel:Destroy() end itemFrame.NewLabel:Destroy() itemFrame.Name = item:GetAttribute("Name") or item.Name local viewportFrame = itemFrame.ViewportFrame local camera = Instance.new("Camera") camera.Parent = viewportFrame viewportFrame.CurrentCamera = camera item = item:Clone() item.Parent = viewportFrame item:PivotTo(item:GetAttribute("Rotation") or CFrame.identity) local distance local cameraRotation = 45 if item:IsA("BasePart") then distance = item.Size.Magnitude elseif item:IsA("Model") then if not item.PrimaryPart then warn(item:GetFullName().." has no PrimaryPart, please set one!") item.PrimaryPart = item:FindFirstChildWhichIsA("BasePart") end distance = item:GetExtentsSize().Magnitude end local function rotateCamera() camera.CFrame = CFrame.fromEulerAnglesYXZ(-0.8,math.rad(cameraRotation),0) camera.CFrame = camera.CFrame + camera.CFrame.LookVector * -(distance/1.2) end rotateCamera() local mouseInside = false viewportFrame.MouseEnter:Connect(function() mouseInside = true viewportFrame.BackgroundColor3 = Color3.new(0.75,0.75,0.75) while wait() and mouseInside do cameraRotation = cameraRotation + 0.33 rotateCamera() end end) viewportFrame.MouseLeave:Connect(function() mouseInside = false viewportFrame.BackgroundColor3 = Color3.new(1,1,1) end) return itemFrame end local function clearItems() for _,item in pairs(shopFrame:GetChildren()) do if item:IsA("Frame") then item.Parent = nil -- Now is this a good idea or not... end end end local f = string.find local l = string.lower local function loadSearch(term) clearItems() wait() term = l(term) for _,info in pairs(namedFrames) do if f(l(info[1]),term,1,true) then -- A crude search if anything info[2].Parent = shopFrame end end for _,info in pairs(directNamedFrames) do if f(l(info[1]),term,1,true) then -- A crude search if anything info[2].Parent = shopFrame end end end shopSearch.FocusLost:Connect(function(enter, inputObject) if enter then -- add a quick enter end end) local function loadFolder(folder) currentFolder = folder clearItems() wait() for _,frame in pairs(folders[folder]) do frame.Parent = shopFrame end end shopSearch.Changed:Connect(function() if currentTerm == shopSearch.Text then return end currentTerm = shopSearch.Text if #shopSearch.Text > 0 then loadSearch(shopSearch.Text) else loadFolder(currentFolder) end end) local existing = {} local t = 200 local function registerItem(item) if existing[item] then return end existing[item] = true if item:HasTag("DoNotPlace") then return end local isFolder = item:IsA("Folder") local isPart = item.Parent:IsA("Folder") and (item:IsA("Model") or item:IsA("BasePart")) if isFolder or isPart then local model = item if isFolder then local smallestOrder = t+1 local smallestItem for _,child in pairs(item:GetDescendants()) do if not (child.Parent:IsA("Folder") and (child:IsA("BasePart") or child:IsA("Model"))) then continue end local order = child:GetAttribute("Order") or t if order < smallestOrder then smallestOrder = order smallestItem = child end end model = smallestItem end if not model then warn(item:GetFullName().." has no children.") return end local frame = createItemFrame(model) frame.LayoutOrder = item:GetAttribute("Order") or t folders[item.Parent] = folders[item.Parent] or {} -- Make sure the folder exists table.insert(folders[item.Parent],frame) if isPart then if item:GetAttribute("Name") then table.insert(namedFrames,{item:GetAttribute("Name"),frame}) end table.insert(directNamedFrames,{item.Name,frame}) frame.InputEnded:Connect(function(inputObject) if inputObject.UserInputType == Enum.UserInputType.MouseButton1 or inputObject.UserInputType == Enum.UserInputType.Touch then _G.Events.Pick:Fire(item) if item.Parent:IsA("Folder") and item.Parent:HasTag("AutoBack") then loadFolder(item.Parent.Parent) end end end) else frame.ItemLabel.Text = item.Name frame.InputEnded:Connect(function(inputObject) if inputObject.UserInputType == Enum.UserInputType.MouseButton1 or inputObject.UserInputType == Enum.UserInputType.Touch then loadFolder(item) end end) end end end local function loadStore() for _,item in pairs(partsStore:GetDescendants()) do registerItem(item) end loadFolder(currentFolder) end shopBackButton.MouseButton1Click:Connect(function() local parent = currentFolder.Parent if currentFolder == partsStore then parent = partsStore end loadFolder(parent) end) loadStore()