Hello I have been working on an inventory system for about 40 hours and I have been working on this specific bug I have for 10 hours with no signs of progress. I have tried a lot of things but I cannot figure out why my inventory is dropping more than 1 of the item. I notice that it’s only doing it after picking up items in-game, where it then drops 6, or 8, or 10 of the item I drop but I don’t know why it does that.
https://medal.tv/games/roblox-studio/clips/fa8G1Onv3ehps/d13377ksNuDI?invite=cr-MSx4R0csNTgzMDQ2NzAs
Inventory Client Local Script:
local Player = game.Players.LocalPlayer
local UserInputService = game:GetService('UserInputService')
local HTTPService = game:GetService('HttpService')
local RunService = game:GetService('RunService')
local GetDataRemote = game.ReplicatedStorage:WaitForChild('GetData')
local EquipItemRemote = game.ReplicatedStorage:WaitForChild('EquipItem')
local DropItemRemote = game.ReplicatedStorage:WaitForChild('DropItem')
local RemoveItemRemote = game.ReplicatedStorage:WaitForChild('RemoveItem')
local RemoveSlottedItemRemote = game.ReplicatedStorage:WaitForChild('RemoveSlottedItem');
local ItemsModule = require(game.ReplicatedStorage:WaitForChild('Items'))
local PlayerInventory = script.Parent:WaitForChild('InventoryWindow')
local count = 1;
local PlayerData
local CurrentItemID
local ItemSelected = false
local CurrentItemType = PlayerInventory.RightFrame.Type
local CurrentItemTitle = PlayerInventory.RightFrame.Title
local inventoryIDCache = {}
local spinningObjects = {}
PlayerInventory.Visible = false
wait(5)
--Open/Close Inventory
UserInputService.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Keyboard then
if input.KeyCode == Enum.KeyCode.G then
if PlayerInventory.Visible == false then
if Player.PlayerGui.ScreenGui.InteractionInsignia.Visible == true then
Player.PlayerGui.ScreenGui.InteractionInsignia.Visible = false;
end
local openSound = game.ReplicatedStorage.OtherAssets:FindFirstChild('OpenBackpack');
openSound:Play()
PlayerInventory.Visible = true
elseif PlayerInventory.Visible == true then
local closeSound = game.ReplicatedStorage.OtherAssets:FindFirstChild('CloseBackpack');
closeSound:Play()
PlayerInventory.Visible = false
end
end
end
end)
function fade(object)
--this aint working
for i=0, 5 do
print(i)
object.TextTransparency = object.TextTransparency - 0.35; --todolater: need to evaluate if it's a text object or image object.
i += 1;
end
end
function EquipMessage(itemID)
warn('EquipMessage')
local textMessage = script.Parent.Frame.TextLabel;
textMessage.Text = itemID .. " equipped.";
textMessage.Visible = true;
textMessage:TweenPosition(UDim2.new(0.5, 0, 0, 0), "Out", "Quad", 1, false);
wait(0.2);
fade(textMessage);
wait(1)
textMessage.Visible = false;
warn('Jo');
textMessage:TweenPosition(UDim2.new(0.5, 0, 0.906, 0), "Out", "Quad", 0.001, false);
end
function DisplayItemInfo(FrameName)
local infoFrame = PlayerInventory.RightFrame
local itemType = infoFrame.Type
local viewport = infoFrame.ViewportFrame
viewport.Visible = true
CurrentItemTitle.Text = FrameName;
local itemConfiguration = ItemsModule:GetItemFromID(FrameName)
if itemConfiguration then
for i,v in pairs(itemConfiguration) do
if i == 'Type' then
CurrentItemType.Text = v
end
end
end
end
local function UpdateCanvasSize(Canvas, Constraint)
Canvas.CanvasSize = UDim2.new(0, Constraint.AbsoluteContentSize.X, 0, Constraint.AbsoluteContentSize.Y)
end
function Update()
if not PlayerData then
return
end
for itemID,v in pairs(PlayerData.Inventory) do
local itemConfiguration = ItemsModule:GetItemFromID(itemID)
if not itemConfiguration then
continue
end
--**[[ THIS IS FOR CREATING INVENTORY ITEM IN SCROLLING FRAME FROM PLAYER INVENTORY DATA
local InventoryItem = script.Parent.InventoryWindow.LeftFrame.ScrollingFrame:FindFirstChild(itemID)
if not InventoryItem then
InventoryItem = script.TemplateItem:Clone()
InventoryItem.Name = itemID
print(itemConfiguration)
print(itemConfiguration.Title)
for i,v in pairs(itemConfiguration.Title) do
print('title meant to be here')
InventoryItem.Title[i] = v
end
local model = game.ReplicatedStorage.GameItems:FindFirstChild(itemConfiguration.Model):Clone()
if model then
model:Clone()
if model:IsA("Model") then
model:SetPrimaryPartCFrame(itemConfiguration.Viewport.Model)
end
model.Parent = InventoryItem.ItemSquare.ViewportFrame
table.insert(spinningObjects, model)
local ViewportCamera = Instance.new('Camera')
ViewportCamera.CFrame = itemConfiguration.Viewport.Camera
InventoryItem.ItemSquare.ViewportFrame.CurrentCamera = ViewportCamera
else
warn("there is no model.");
end
InventoryItem.Parent = PlayerInventory.LeftFrame.ScrollingFrame
end
--**[[ THIS IS FOR RIGHT CLICKING INVENTORY ITEM TO BRING UP ITEM-SPECIFIC ACTIONS.
InventoryItem.MouseButton2Click:Connect(function()
if ItemSelected == false then
local itemType = ItemsModule:GetTypeFromID(InventoryItem.Name);
print(itemType);
if itemType == 'Shield' then
InventoryItem.ItemSquare.Equip1.Visible = true;
InventoryItem.ItemSquare.Drop.Visible = true;
InventoryItem.ItemSquare.Drop:TweenPosition(UDim2.new(0.5, 0, 0.5, 0), "Out", "Quad", 0.001, false);
InventoryItem.ItemSquare.Equip1.Text = 'Equip';
elseif itemType == 'Weapon' then
elseif itemType == 'Resource' then
end
end
end)
--**[[ THIS IS FOR HIGHLIGHTING AN ITEM WHEN PLAYER HOVERS MOUSE ON INVENTORY ITEM
--InventoryItem.MouseEnter:Connect(function()
-- if ItemSelected == false then
-- InventoryItem.Equip1Button.Visible = true
-- InventoryItem.Equip2Button.Visible = true
-- InventoryItem.DropButton.Visible = true
-- end
--end)
--**[[ ABOVE VICE VERSA
InventoryItem.MouseLeave:Connect(function()
if ItemSelected == false then
InventoryItem.ItemSquare.Equip1.Visible = false
InventoryItem.ItemSquare.Equip2.Visible = false
InventoryItem.ItemSquare.Drop.Visible = false
end
end)
InventoryItem.Quantity.Text = v
table.insert(inventoryIDCache, itemID)
end
local countHelper = 0;
for _, Frame in pairs(script.Parent.InventoryWindow.LeftFrame.ScrollingFrame:GetChildren()) do
print('At 182 ' .. os.time() .. count);
if Frame:IsA('ImageButton') then
print('yo');
if not table.find(inventoryIDCache, Frame.Name) then
warn('UH-OH');
Frame:Destroy()
end
local inventorySlot = Frame
local equip1Button = inventorySlot.ItemSquare:FindFirstChild('Equip1');
local equip2Button = inventorySlot.ItemSquare:FindFirstChild('Equip2');
local dropButton = inventorySlot.ItemSquare:FindFirstChild('Drop');
local shieldSlot = Player.PlayerGui.ScreenGui.InventoryWindow.RightFrame:WaitForChild('ShieldSlot');
--**[[ EQUIPPING ITEMS
equip1Button.MouseButton1Click:Connect(function()
local quantity = equip1Button.Parent.Parent.Quantity.Value.Value;
print(quantity);
if not Player.Character:FindFirstChild(equip1Button.Parent.Parent.Name) then
if not Player.PlayerGui.ScreenGui.InventoryWindow.RightFrame.ShieldSlot.ViewportFrame:FindFirstChildWhichIsA('Model') then
--player can equip more than 1 shield. need to add another check to see if there's a child in the character.
CurrentItemID = equip1Button.Parent.Parent.Name;
ItemSelected = false
PlayerInventory.Visible = false
if quantity <= 0 then
print('quanquan')
equip1Button.Parent.Parent:Destroy();--problem is we're destroying it without any consideration of how many of that item the player has.
end
equip1Button.Parent.Parent:Destroy();
EquipItemRemote:FireServer(CurrentItemID)
local itemType = ItemsModule:GetTypeFromID(CurrentItemID);
local Item = ItemsModule:GetItemFromID(CurrentItemID)
print(Item);
print(itemType);
local viewModel = Player.Character:WaitForChild(Item.ID):Clone()
if itemType == 'Shield' then
viewModel.Parent = Player.PlayerGui.ScreenGui.InventoryWindow.RightFrame.ShieldSlot.ViewportFrame;
viewModel:SetPrimaryPartCFrame(Item.Viewport.Model);
table.insert(spinningObjects, viewModel);
local viewportCam = Instance.new('Camera');
viewportCam.CFrame = Item.Viewport.Camera;
shieldSlot.ViewportFrame.CurrentCamera = viewportCam;
elseif itemType == 'Weapon' then
elseif itemType == 'Resource' then
end
EquipMessage(Item.ID);
end
end
end)
equip2Button.MouseButton2Click:Connect(function()
--this gets coded for different item functionalities, will come back to this
end)
--local item = ItemsModule:GetItemFromID(dropButton.Parent.Parent.Name);
--local quantity = dropButton.Parent.Parent.Quantity.Value.Value;
print('At 237 ' .. os.time() .. count);
dropButton.MouseButton1Click:Connect(function(item, quantity)
countHelper += 1
print(countHelper)
item = ItemsModule:GetItemFromID(dropButton.Parent.Parent.Name);
quantity = dropButton.Parent.Parent.Quantity.Value.Value;
--print('o');
print(quantity);
if quantity <= 1 then
ItemSelected = false;
DropItemRemote:FireServer(item.ID, quantity)
end
--print(item.Parent);
--PlayerInventory.Visible = false
--ItemSelected = false
--print(item.ID.. " is the current item ID");
--DropItemRemote:FireServer(item.ID, quantity) --PROBLEM IS THIS: FIRING LIKE 8+ TIMES FOR NO REASON.
end)
end
end
local Constraint = PlayerInventory.LeftFrame.ScrollingFrame.UIListLayout
PlayerInventory.LeftFrame.ScrollingFrame.CanvasSize = UDim2.new(0,Constraint.AbsoluteContentSize.X,0,Constraint.AbsoluteContentSize.Y)
end
--** [[REMOVING/DROPPING ITEMS FROM EQUIP SLOTS
for i,v in pairs(script.Parent.InventoryWindow.RightFrame:GetChildren()) do
if v:IsA('ImageButton') then
if v.Name == 'ClothingSlot' or v.Name == 'HelmetSlot' or v.Name == 'ShieldSlot' then
local dropbButton = v:WaitForChild('Drop');
local removeButton = v:WaitForChild('Remove');
local item
local reset = 1;
local dude = false;
removeButton.Parent.ViewportFrame.ChildAdded:Connect(function(model1)
print(model1);
item = model1;
end)
--local item = removeButton.Parent.ViewportFrame.
v.MouseButton2Click:Connect(function()
if item then
dropbButton.Visible = true;
removeButton.Visible = true;
end
end)
v.MouseLeave:Connect(function()
dropbButton.Visible = false;
removeButton.Visible = false;
end)
dropbButton.MouseButton1Click:Connect(function()
local viewItem;
for i,v in pairs(dropbButton.Parent.ViewportFrame:GetChildren()) do
if v:IsA('Model') then
viewItem = v;
end
end
print(viewItem);
DropItemRemote:FireServer(viewItem.Name);
local equipitem = Player.Character:WaitForChild(viewItem.Name);
equipitem:Destroy();
viewItem:Destroy();
end)
removeButton.MouseButton1Click:Connect(function()
if not dude then
dude = true;
print(item)
local equippedItem = Player.Character:WaitForChild(item.Name);
print(equippedItem);
item:Destroy();
RemoveSlottedItemRemote:FireServer(equippedItem); --removing it from the player's character
Update()
removeButton.Visible = false;
dropbButton.Visible = false;
wait(reset);
dude = false;
end
--need to destroy it from player character
--need to see if when we equip an item, is it still inside the player data. if not we need to make it so that it is so that when they leave the game the item will be equipped when they come back.
end)
end
end
end
local rotationCFrame = CFrame.Angles( 0, math.rad(0.8), 0 )
RunService.Heartbeat:Connect(function()
for i, object in ipairs( spinningObjects ) do
if (not object.Parent) then
table.remove(spinningObjects, i)
break
end
if object:IsA('Model') then
object:SetPrimaryPartCFrame( object:GetPrimaryPartCFrame() * rotationCFrame )
elseif object:IsA('BasePart') then
object.CFrame *= rotationCFrame
end
end
end)
--function that checks the area of the player around the player compared to the position of the dropped item that the
--player drops. but basically this function will check if the player is within this area or not, and we're gonna use
--this function to return a bool value because we want to evaluate directly below our "dropbutton function" whether or
--not the player is in proximity to the dropped item. if the player is not in proximity of the dropped item then
--it will keep running. we'll just word it like "if not ... then "
task.defer(function()
local oldDataJSON = ''
while task.wait(0.25) do
PlayerData = GetDataRemote:InvokeServer()
local newPlayerData = PlayerData and HTTPService:JSONEncode(PlayerData)
if newPlayerData ~= oldDataJSON then --If player picks up an item for example.
oldDataJSON = newPlayerData
task.defer(Update)
end
end
end)
RunService.RenderStepped:Connect(function()
if Player.Character then
local playerData = GetDataRemote:InvokeServer()
if playerData then
for i,v in pairs(script.Parent.InventoryWindow.LeftFrame.ScrollingFrame:GetChildren()) do
if v:IsA('ImageButton') then
local item = v.Name
if playerData.Inventory[item] <= 0 then
v:Destroy()
end
--v.MouseButton1Click:Connect(function()
-- v.ImageColor3 = Color3.new(0.784314, 1, 0.580392)
-- v.ItemSquare.ImageColor3 = Color3.new(0.443137, 0.635294, 0.411765)
-- local FrameName = v.Name
-- ItemSelected = true
-- DisplayItemInfo(FrameName)
--end)
end
end
end
end
end)
count = count + 1;
Server Handler:
local DataService = require(game.ServerStorage:WaitForChild('DataService'))
local GetDataRemote = game.ReplicatedStorage:WaitForChild('GetData')
local EquipItemRemote = game.ReplicatedStorage:WaitForChild('EquipItem')
local DropItemRemote = game.ReplicatedStorage:WaitForChild('DropItem')
local RemoveItemRemote = game.ReplicatedStorage:WaitForChild('RemoveItem')
local RemoveSlottedItemRemote = game.ReplicatedStorage:WaitForChild('RemoveSlottedItem')
GetDataRemote.OnServerInvoke = function(Player, Yield)
local profile = DataService:GetPlayerProfile(Player, false)
if profile then
return profile.Data
end
return nil
end
RemoveSlottedItemRemote.OnServerEvent:Connect(function(Player, itemID)
local playerProfile = DataService:GetPlayerProfile(Player)
if playerProfile then
for i,v in pairs(Player.Character:GetChildren()) do
if v == itemID then
v:Destroy();
end
end
end
end)
RemoveItemRemote.OnServerEvent:Connect(function(Player, itemID)
local playerProfile = DataService:GetPlayerProfile(Player)
if playerProfile then
--make a condition for when we're just wanting to remove the item from the slot, to go back to the inventory frame.
playerProfile.Data.Inventory[itemID] = nil
end
end)
--local gameItemsArray = game.ReplicatedStorage:WaitForChild('GameItems'):GetChildren()
DropItemRemote.OnServerEvent:Connect(function(Player, CurrentItemID, quantity)
local playerProfile = DataService:GetPlayerProfile(Player)
for i,v in pairs(game.ReplicatedStorage:WaitForChild('GameItems'):GetChildren()) do
if v.Name == CurrentItemID then
if quantity > 1 then
local droppedItem = v:Clone();
droppedItem.Parent = game.Workspace.EnvironmentAssets
droppedItem.PrimaryPart.CFrame = Player.Character.HumanoidRootPart.CFrame + Vector3.new(0, 0, -2)
droppedItem.PrimaryPart.Anchored = false
droppedItem.PrimaryPart.CanCollide = true;
elseif quantity <= 1 then
local droppedItem = v:Clone();
droppedItem.Parent = game.Workspace.EnvironmentAssets
droppedItem.PrimaryPart.CFrame = Player.Character.HumanoidRootPart.CFrame + Vector3.new(0, 0, -2)
droppedItem.PrimaryPart.Anchored = false
droppedItem.PrimaryPart.CanCollide = true;
end
--playerProfile.Data.Inventory[v] = playerProfile.Data.Inventory[v] - 1
end
end
for i,v in pairs(playerProfile.Data.Inventory) do
if i == CurrentItemID then
--if Player.PlayerGui.ScreenGui.InventoryWindow.
playerProfile.Data.Inventory[CurrentItemID] = playerProfile.Data.Inventory[CurrentItemID] - 1
end
end
end)
EquipItemRemote.OnServerEvent:Connect(function(Player, CurrentItemID)
local playerProfile = DataService:GetPlayerProfile(Player)
local gameItemsArray = game.ReplicatedFirst:WaitForChild('GameItems'):GetChildren()
for i,v in pairs(gameItemsArray) do
if v.ItemType.Value == 'Shield' and v.Name == CurrentItemID then
local clonedItem = v:Clone()
clonedItem.Parent = Player.Character
local newWeld = Instance.new('Weld')
newWeld.Parent = clonedItem.ArmPart
newWeld.Part0 = Player.Character.LeftLowerArm
newWeld.Part1 = clonedItem.ArmPart
--playerProfile.Data.Inventory[CurrentItemID] = playerProfile.Data.Inventory[CurrentItemID] - 1;
end
if v.ItemType.Value == 'Weapon' and v.Name == CurrentItemID then
end
if v.ItemType.Value == 'Resource' and v.Name == CurrentItemID then
print('you cant do that bro.')
end
end
end)