Inventory Module Problems

  1. What do you want to achieve? Keep it simple and clear!

I’m trying to fix my module inventory script. The problem is when i return the data to the player in local script it wont update reliably until you update it twice or multiple times.

Module Script

local inventory = {playerlist = {}}
local playerlist = inventory.playerlist

function inventory.AddPlayer(player)
	playerlist[player] = {
		inventory = {}
	}
end

function inventory.ReturnPlayer(player)
	return playerlist[player]
end

function inventory.AddItem(player, itemname, itemtype)
	local playerinventory = playerlist[player].inventory
	
	if playerinventory[itemname] then
		print("Item Found")
		playerinventory[itemname].amount += 1
	else
		local newitem = {
			itemname = itemname,
			itemtype = itemtype,
			amount = 1
		}
		playerinventory[itemname] = newitem
	end
	print(playerinventory)
end

function inventory.RemoveItem(player, itemname)
	local playerinventory = playerlist[player].inventory
	
	if playerinventory[itemname].amount <= 1 then
		playerinventory[itemname] = nil
		return
	end
	playerinventory[itemname].amount -= 1
end

return inventory

Sever Script

local remoteevent = game.ReplicatedStorage:WaitForChild("RemoteEvent")
local inventorymodule = require(game.ReplicatedStorage.Inventory)

game.Players.PlayerAdded:Connect(function(player)
    inventorymodule.AddPlayer(player)
end)
remoteevent.OnServerEvent:Connect(function(player)
	remoteevent:FireClient(player, inventorymodule.ReturnPlayer(player))
end)

Local Script

local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()

local inventory
local remoteevent = game.ReplicatedStorage:WaitForChild("RemoteEvent")
local uips = game:GetService("UserInputService")

function setUpPlayer()
	remoteevent:FireServer()
end

function UpdateInventory(inventoryData)
	print("Inventory Data ", inventoryData)
	inventory = inventoryData
	--print(inventory)
end

remoteevent.OnClientEvent:Connect(UpdateInventory)

setUpPlayer()

uips.InputBegan:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.H then
		remoteevent:FireServer()
		print(player.Name.. " Called Inventory ", inventory)
	end
end)

when you press H to print the inventory it sometimes shows its empty until you press it twice or multiple times even though InventoryData is updated which should set inventory to InventoryData from the local script.

the blue arrow is where I press H the first time, the red arrow is where I pressed H to print the inventory the 2nd time

1 Like

Hiya!

Okay it looks like there might be two things going on here. You may have the SignalBehaviour property of workspace set to ‘Deferred’. This means the RemoteEvent doesn’t actually fire until the InputBegan function resolves. You can see this because it prints player.Name .. "Called Inventory", inventory before it prints Inventory Data. Try sticking task.defer(function() print(...) end) around the print statement and seeing if this fixes the problem.

However there’s also the fact that inventory gets assigned to an empty table. In the local script the only way inventory gets assigned is through the UpdateInventory function, which suggests the RemoteEvent is actually returning an empty table. There might be something wrong with the way you’re adding items to the inventory. The function AddItem looks good, but it’s not clear from this post how the ‘Item’ actually ends up in your inventory. That process might be somehow being delayed for some reason, meaning the inventory is actually empty when the server sends it back to the client.

Just my thoughts! I hope these ideas are helpful :slight_smile:

1 Like

Hey, the output is actually scrolled down cause I have other prints happening including prints from this script. The Inventory Data does print, it runs at the start. Also it does show the updated inventory and not a empty table but doesnt set inventory to it until you press H twice.

The AddItem and RemoveItem work good without problems, its added using ClickDetector. I didn’t put it in here since the problem I think is local. In the picture you can see when I click the item. I don’t usually use task so I’m not sure how that works but shouldn’t it work fine whether if one prints first or the other? I am not sure what you mean by signalbehaviour I can’t seem to find that in workspace.

Add Item Script

local c = script.Parent.ClickDetector
local inventory = require(game.ReplicatedStorage.Inventory)
c.MouseClick:Connect(function(player)
	print("Clicked item")
	inventory.AddItem(player, "Item", "Resource")
end)

The Full Image

the yellow arrow is the startup
the blue arrow is where I press H the first time
the red arrow is where I press H the 2nd time, and it updates inventory that time

1 Like

Hm interesting… would you be willing to share a place file with these scripts in it so I can hop in and do some debugging? I reckon I’d be able to find the bug with a bit of experimenting

1 Like

Wait for the RemoteEvent response: Make sure to wait for the server response before proceeding with further actions. You can use remoteevent.OnClientEvent:Wait() to wait for the server to send the data back.

Check for nil values: Ensure that the inventory data received from the server is not nil before attempting to update the UI. You can add a check in the UpdateInventory function.

Print statements for debugging: Add more print statements for debugging in both the server and client scripts to see where the issue might be occurring.

Synchronize Client and Server Inventory Updates: Make sure that the server updates the inventory and fires the event only after the inventory is modified. This might involve changing the order of operations in your server script. In the inventory.AddItem function, you may want to move the remoteevent:FireClient call after updating the inventory.

Handling Player Disconnection: If a player disconnects, their data might still be present in the playerlist . It’s good practice to clean up this data when a player leaves the game to prevent potential memory leaks. You can use the PlayerRemoving event for this purpose:

Module script:

local inventory = {playerlist = {}}
local playerlist = inventory.playerlist

function inventory.AddPlayer(player)
    playerlist[player] = {
        inventory = {}
    }
end

function inventory.ReturnPlayer(player)
    return playerlist[player]
end

function inventory.AddItem(player, itemname, itemtype)
    local playerinventory = playerlist[player].inventory

    if playerinventory[itemname] then
        print("Item Found")
        playerinventory[itemname].amount = playerinventory[itemname].amount + 1
    else
        local newitem = {
            itemname = itemname,
            itemtype = itemtype,
            amount = 1
        }
        playerinventory[itemname] = newitem
    end
    print(playerinventory)

    return playerlist[player]
end

function inventory.RemoveItem(player, itemname)
    local playerinventory = playerlist[player].inventory

    if playerinventory[itemname].amount <= 1 then
        playerinventory[itemname] = nil
    else
        playerinventory[itemname].amount = playerinventory[itemname].amount - 1
    end

    return playerlist[player]
end

return inventory

Server script:

local remoteevent = game.ReplicatedStorage:WaitForChild("RemoteEvent")
local inventorymodule = require(game.ReplicatedStorage.Inventory)

game.Players.PlayerAdded:Connect(function(player)
    inventorymodule.AddPlayer(player)
end)

game.Players.PlayerRemoving:Connect(function(player)
    inventorymodule.playerlist[player] = nil
end)

remoteevent.OnServerEvent:Connect(function(player)
    local playerData = inventorymodule.ReturnPlayer(player)
    remoteevent:FireClient(player, playerData)
end)

Local Script:

local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()

local inventory
local remoteevent = game.ReplicatedStorage:WaitForChild("RemoteEvent")
local uips = game:GetService("UserInputService")

function setUpPlayer()
    local inventoryData = remoteevent:InvokeServer()
    UpdateInventory(inventoryData)
end

function UpdateInventory(inventoryData)
    if inventoryData then
        print("Inventory Data ", inventoryData)
        inventory = inventoryData

        for itemName, itemInfo in pairs(inventory.inventory) do
            print(itemName .. ": " .. itemInfo.amount)
        end
    else
        print("Received nil inventory data")
    end
end


remoteevent.OnClientEvent:Connect(UpdateInventory)

setUpPlayer()

uips.InputBegan:Connect(function(input)
    if input.KeyCode == Enum.KeyCode.H then
        setUpPlayer()
        print(player.Name .. " Called Inventory ", inventory)
    end
end)
1 Like

Yes this is the answer! The other stuff Vvshenok says is also really valuable, although that starts getting into changing quite a lot outside of the question you originally asked.

So the problem is that the RemoteEvent is asynchronous which means that when you call remoteevent:FireServer() it doesn’t immediately happen, so the OnClientEvent signal doesn’t fire until a little bit later. That means what happens in order is:

--> User Presses H
remoteevent:FireServer()
--> signal is sent to the server to return inventory data 
print(player.Name .. " Called Inventory ", inventory)
-- (inventory prints before update)
--> signal returns from server, triggering UpdateInventory
inventory = inventoryData
-- inventory is now up to date

If I was going to fix this with minimal changes, I would make it so that every time the player’s inventory changes on the server side, the server fires the client with the up to date inventory. (So, add remoteevent:FireClient() to the AddItem and RemoveItem functions in the inventory module script.) Then, when the user presses H you don’t need to fire the remote event as the up-to-date inventory is already stored locally.

1 Like

Thanks guys for helping me out, I thought yesterday that the remote event wasnt firing as fast as the print. I tried to put a wait in the UserInput today and that worked, putting the fireclient in the module script also worked and is the solution.

1 Like

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