Hey you all. I’m currently developing an obby game, and I am currently making an Inventory system of tools for it. Now more specifically, I want the server to prevent players from buying the tool again if they already equipped it or it is in their inventory. I also want the inventory to not cause bugs lol
The issues are 2 things. One issue is that whenever I try to purchase a tool I already own in my inventory(that I didn’t equip yet, which is in my inventory still), it still gives me that tool in my inventory again. When I equip that tool from my inventory, all tools of that same tool in my inventory are cleared out and I equip one of that tool.
Another issue is that after the first time purchasing and equipping a tool(Which works normally), from the second purchase and so on, it gives me the item in my inventory, but to the right of the inventory where you actually click the equip button, the button does not get its text updated. The text label for the tool’s name is also not visible. The thing that confuses me the most is that whenever I try to click the equip button, it gives me 2 of that tool, which is odd.
I tried making the checking of the inventory client-sided, but I still got the buggy inventory result. I thought about using a remote function, but after reading about it, I changed my mind because of many problems.
So here is the explorer:
Here is the local script named TempToolPurchaseMessage
--Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
--Variables
local plr = Players.LocalPlayer
local PurchaseEvent = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("ShopEvents"):WaitForChild("TempToolPurchase")
local ShopItemNamesEvent = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("ShopEvents"):WaitForChild("TempToolShopItemNames")
local AddToInventoryToolsEvent = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("ShopEvents"):WaitForChild("AddToInventoryTools")
local ToolEquipEvent = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("ShopEvents"):WaitForChild("TempToolEquip")
local TempToolInventoryList = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("ShopEvents"):WaitForChild("TempToolInventoryList")
local TempToolInventoryListReturn = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("ShopEvents"):WaitForChild("TempToolInventoryListReturn")
local MainFrame = plr:WaitForChild("PlayerGui"):WaitForChild("ShopGui"):WaitForChild("MainFrame")
local ToolShop = MainFrame:WaitForChild("ToolsShop")
local RoundFrame = ToolShop:WaitForChild("Frames"):WaitForChild("RoundFrame")
local KeepFrame = ToolShop:WaitForChild("Frames"):WaitForChild("KeepFrame")
local ScrollingFrame = ToolShop:WaitForChild("ScrollingFrame")
local Frames
local standardRoundToolNames1
local standardRoundToolDictionary1
--Add all tools from Server to Client
ShopItemNamesEvent.OnClientEvent:Connect(function(standardRoundToolNames, standardRoundToolDictionary, standardRoundViewportDictionary)
print(" Client received message to replicate all items to Gui !")
print(standardRoundToolDictionary)
print(standardRoundViewportDictionary)
--Make sure that all value types are valid
for i, name in pairs(standardRoundToolNames) do
if typeof(name) ~= "string" then print(" name not valid") return end
if typeof(standardRoundToolDictionary[name]) ~= "number" then print(" price not valid") return end
if (standardRoundViewportDictionary[name]:IsA("Part") ~= true) and (standardRoundViewportDictionary[name]:IsA("Model") ~= true) then print(" viewport Instance not valid") return end
end
print("Client Valid")
--Continue (All info will be saved on server script prior to firing this remote event, probably with some sort of dictionary or series of lists)
for i, toolName in pairs(standardRoundToolNames) do
local price = standardRoundToolDictionary[toolName]
local viewportItem = standardRoundViewportDictionary[toolName]:Clone()
local camera = Instance.new("Camera")
--Setting up viewport camera and viewportItem rotation
camera.Name = "ViewportCamera"
camera.CFrame = CFrame.new(Vector3.new(0, 1.5, 1.8), viewportItem.Position)
viewportItem.CFrame = CFrame.Angles(math.rad(340), math.rad(325), 0)
local newFrame = RoundFrame:Clone()
newFrame.Parent = ScrollingFrame
newFrame:WaitForChild("PriceLabel").Text = "Price: " .. price
--Viewport Frame
local viewport = newFrame:WaitForChild("ViewportFrame")
viewportItem.Parent = viewport
camera.Parent = viewport
viewport.CurrentCamera = camera
newFrame.Visible = true
--Handle Purchase on Client Side
local PurchaseButton = newFrame:WaitForChild("PurchaseButton")
PurchaseButton.MouseButton1Click:Connect(function()
PurchaseEvent:FireServer(toolName)
end)
end
end)
--Provides server with player's list of items in current inventory
TempToolInventoryList.OnClientEvent:Connect(function(plrTempToolInventory1)
--Make sure value type is valid
if typeof(plrTempToolInventory1) ~= "table" then return end
for i, v in pairs(plr:WaitForChild("PlayerGui"):WaitForChild("InventoryGui"):WaitForChild("MainFrame"):WaitForChild("ToolsFrame"):WaitForChild("ScrollingFrame"):GetChildren()) do
if v:IsA("Frame") then
local toolName = v:WaitForChild("OpenButton").Text
table.insert(plrTempToolInventory1, toolName)
end
end
TempToolInventoryListReturn:FireServer(plrTempToolInventory1)
end)
--Add purchases to inventory
AddToInventoryToolsEvent.OnClientEvent:Connect(function(toolName, standardRoundToolsNames, standardRoundToolsDictionary, standardRoundViewportDictionary)
print(" Client received message to put purchased item in the Inventory !")
print(standardRoundToolsDictionary)
print(standardRoundViewportDictionary)
--Make sure that all types are valid
if typeof(toolName) ~= "string" then print(" name not valid") return end
if typeof(standardRoundToolsDictionary[toolName]) ~= "number" then print(" price not valid") return end
if (standardRoundViewportDictionary[toolName]:IsA("Part") ~= true) and (standardRoundViewportDictionary[toolName]:IsA("Model") ~= true) then print(" viewport Instance not valid") return end
print("Client Valid")
--Variables
local inventoryToolsFrame = plr:WaitForChild("PlayerGui"):WaitForChild("InventoryGui"):WaitForChild("MainFrame"):WaitForChild("ToolsFrame")
local rightViewFrame = inventoryToolsFrame:WaitForChild("RightViewFrame")
local rightEquipButton = rightViewFrame:WaitForChild("EquipButton")
local viewportItem = standardRoundViewportDictionary[toolName]:Clone()
print(viewportItem.Name)
--Add tool to Inventory
local newInventoryFrame = inventoryToolsFrame:WaitForChild("Frames"):WaitForChild("ToolFrame"):Clone()
local OpenButton = newInventoryFrame:WaitForChild("OpenButton")
OpenButton.Text = toolName
print(OpenButton.Text)
--Viewport Frame
local camera = Instance.new("Camera")
camera.Name = "ViewportCamera"
camera.CFrame = CFrame.new(Vector3.new(0, 1.5, 1.8), viewportItem.Position)
viewportItem.CFrame = CFrame.Angles(math.rad(340), math.rad(325), 0)
local viewport = newInventoryFrame:WaitForChild("ViewportFrame")
viewportItem.Parent = viewport
camera.Parent = viewport
viewport.CurrentCamera = camera
newInventoryFrame.Visible = true
newInventoryFrame.Parent = inventoryToolsFrame:WaitForChild("ScrollingFrame")
--Handle when tool selected
OpenButton.MouseButton1Click:Connect(function()
--Right View Frame matches the tool selected
--Viewport
local rightFrameCamera = camera:Clone()
local rightViewportItem = viewportItem:Clone()
local rightViewport = rightViewFrame:WaitForChild("ViewportFrame")
rightFrameCamera.Parent = rightViewport
rightViewportItem.Parent = rightViewport
--Tool Name
rightViewFrame:WaitForChild("ToolName").Text = toolName
--Make the right view frame visible
rightViewport.Visible = true
rightEquipButton.Visible = true
--Handles when the Equip Button is clicked
rightEquipButton.MouseButton1Click:Connect(function()
--Removes item from user's inventory after equipped
for i, toolFrame in pairs(plr:WaitForChild("PlayerGui"):WaitForChild("InventoryGui"):WaitForChild("MainFrame"):WaitForChild("ToolsFrame"):WaitForChild("ScrollingFrame"):GetChildren()) do
if toolFrame:IsA("Frame") then
if toolFrame:FindFirstChild("OpenButton").Text == toolName then
print(" " .. toolFrame.Name)
toolFrame:Destroy()
end
end
end
--Makes the right view frame blank
local rightViewFrame = plr:WaitForChild("PlayerGui"):WaitForChild("InventoryGui"):WaitForChild("MainFrame"):WaitForChild("ToolsFrame"):WaitForChild("RightViewFrame")
local rightViewport = rightViewFrame:WaitForChild("ViewportFrame")
local rightEquipButton = rightViewFrame:WaitForChild("EquipButton")
local rightToolLabel = rightViewFrame:WaitForChild("ToolName")
rightViewport:ClearAllChildren() --Also modify properties
rightViewport.CurrentCamera = nil
rightEquipButton.Text = "None"
rightToolLabel.Text = "None"
rightViewport.Visible = false
rightEquipButton.Visible = false
rightToolLabel.Visible = false
--Tell server to give player the item
ToolEquipEvent:FireServer(toolName)
end)
end)
end)
Here is the server script named TempToolPurchaseManagement
--Services
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
--Modules
--Variables
local purchaseEvent = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("ShopEvents"):WaitForChild("TempToolPurchase")
local shopItemNamesEvent = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("ShopEvents"):WaitForChild("TempToolShopItemNames")
local AddToInventoryToolsEvent = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("ShopEvents"):WaitForChild("AddToInventoryTools")
local ToolEquipEvent = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("ShopEvents"):WaitForChild("TempToolEquip")
local TempToolInventoryList = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("ShopEvents"):WaitForChild("TempToolInventoryList")
local TempToolInventoryListReturn = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("ShopEvents"):WaitForChild("TempToolInventoryListReturn")
local ShopItems = ServerStorage:WaitForChild("ShopItems")
local standardItems = ShopItems:WaitForChild("StandardItems")
local standardRoundItems = standardItems:WaitForChild("Round")
local standardRoundTools = standardRoundItems:WaitForChild("Tools")
local ShopViewportItems = ReplicatedStorage:WaitForChild("ShopViewportItems")
local standardViewportItems = ShopViewportItems:WaitForChild("StandardItems")
local standardRoundItemViewports = standardViewportItems:WaitForChild("Round")
local standardRoundToolViewports = standardRoundItemViewports:WaitForChild("ToolViewports")
local standardRoundToolsNames = {}
local standardRoundToolsDictionary = {}
local standardRoundViewportDictionary = {}
local viewportTools = {}
for i, tool in pairs(standardRoundTools:GetChildren()) do
local info = tool:WaitForChild("Info")
local name = info:WaitForChild("Name").Value
local price = info:WaitForChild("Price").Value
--local currentCount = info:WaitForChild("currentCount").Value (Make sure currentCount is individual to each player)
table.insert(standardRoundToolsNames, name)
--Since the shop items are stored in the server, the values do not need to be deleted before sending messages to clients
--Viewport
local viewportSubject
local viewportFolder
for i, viewport in pairs(standardRoundToolViewports:GetChildren()) do
if viewport:WaitForChild("Name").Value == name then
viewportFolder = viewport
break
end
end
if viewportFolder:FindFirstChildWhichIsA("Part") then
viewportSubject = viewportFolder:FindFirstChildWhichIsA("Part"):Clone()
viewportSubject.Transparency = 0
viewportSubject.CanCollide = true
elseif viewportFolder:FindFirstChildWhichIsA("Model") then
viewportSubject = viewportFolder:FindFirstChildWhichIsA("Model"):Clone()
for i, part in pairs(viewportSubject:GetChildren()) do
part.Transprency = 0
part.CanCollide = true
end
end
viewportSubject.Name = name
viewportSubject.Position = Vector3.new(0, 0, 0)
viewportSubject.Parent = ReplicatedStorage
--table.insert(viewportTools, viewportSubject)
standardRoundToolsDictionary[name] = price
standardRoundViewportDictionary[name] = viewportSubject
end
print(standardRoundToolsDictionary)
print(standardRoundViewportDictionary)
--Provide Clients with Shop Item Names (Make sure to save info before firing the remote event, probably with a dictionary, making sure to delete info before remote event)
Players.PlayerAdded:Connect(function(plr)
--Handles StandardRoundTools
shopItemNamesEvent:FireClient(plr, standardRoundToolsNames, standardRoundToolsDictionary, standardRoundViewportDictionary)
end)
--Handle Purchases on Server Side
purchaseEvent.OnServerEvent:Connect(function(plr, toolName)
print(" Server Recieved Message to let the user Purchase item!")
--Makes sure that argument value is valid
if typeof(toolName) ~= "string" then return end
print("Server Valid")
local plrCash = plr:WaitForChild("leaderstats"):WaitForChild("Cash")
--Get the list of the items in the current inventory
local plrTempToolInventory = {}
TempToolInventoryList:FireClient(plr, plrTempToolInventory)
TempToolInventoryListReturn.OnServerEvent:Connect(function(plrTempToolInventory1)
--Make sure value types are valid
if typeof(plrTempToolInventory1) ~= "table" then return end
for i, v in pairs(plrTempToolInventory1) do
if typeof(v) ~= "string" then return end
end
plrTempToolInventory = plrTempToolInventory1
end)
local price = standardRoundToolsDictionary[toolName]
if (plrCash.Value >= price) and (not table.find(plrTempToolInventory, toolName)) and (not plr:WaitForChild("Backpack"):FindFirstChild(toolName)) then
--Makes the user pay for the item
plrCash.Value -= price
--Add to inventory
AddToInventoryToolsEvent:FireClient(plr, toolName, standardRoundToolsNames, standardRoundToolsDictionary, standardRoundViewportDictionary)
elseif table.find(plrTempToolInventory, toolName) then
print("Already own item in inventory:" .. toolName)
elseif plr:WaitForChild("Backpack"):FindFirstChild(toolName) then
print("Already equipped item: " .. toolName)
else
print("Not enough cash to purchase: " .. toolName)
end
end)
ToolEquipEvent.OnServerEvent:Connect(function(plr, toolName)
--Make sure that argument value is valid
if typeof(toolName) ~= "string" then return end
print("Server Valid")
--Gets the actual tool to give to the player
local toolModel
for i, tool in pairs(standardRoundTools:GetChildren()) do
if toolName == tool:WaitForChild("Info"):WaitForChild("Name").Value then
toolModel = tool:Clone()
end
end
--Gives the user the item
toolModel.Parent = plr:WaitForChild("Backpack")
print("Equipped: " .. toolModel.Name)
end)
Thanks for helping