:InvokeServer() works in studio, but not on published experience

I’m going straight to the point…
I’m developing a inventory system that invokes a remote function to receive a table of the players inventory. I’ve been successful and it works in studio, but as you can imagine it doesn’t when I publish and play the experience.

I’ve done some debugging before opening this topic. So let me classify them:

  • The Invoke should return a dictionary with two keys Hotbar and Inventory
  • It returns a empty table in when playing it as a experience.
  • The only error is claiming the non existence of the two keys

I hope someone here knows about this issue or can give some information regarding this.
Thanks

1 Like

Could you provide code or specific error messages? This is pretty vague.

There really isn’t any need for code.

local data = rf:InvokeServer(plr)
--'rf' is the RemoteFunction

This simply returns a empty table when published and tested.
The code in itself work, since it is running in studio.

What is in the table?

This is the intended return

But when testing is done on the website, I get nothing.

Is it a race condition?

I can’t really help you without code, as I don’t know what you’re doing.

1 Like

Ok, so what I’m doing is I’m firing a invoke to the server, where the player requests for it’s Hotbar and Inventory, this is in all fairness the basic steps for a system I’m creating in order to prevent exploiters from being able to use items that they don’t own.
The table that they invoke looks something like this

{
    ["Hotbar"] = {}; // Hotbar content(dictionary)
    ["Inventory"] = {}; //Inventory of content(normal table)
}

This works great… well only in studio.
Outside of studio I get an error, which goes in lines of… (index nil with "Hotbar")

Looking at the debug console and some print statements, what is happening is that I get a empty table with no data inside.

I know you can’t really help me without code, but I don’t think this is a code related issue. As everything runs in studio perfectly and in all fairness I don’t know what I could really provide in terms of code, but I guess I could provide the small portion that causes the error.

function retrieveInventory()
	local data = rf:InvokeServer(plr)

	for i,v in pairs(data["items"]["Hotbar"]) do  -- This line creates the error
       ...
    end
end

It isn’t a race condition, because I actually did a manual invoke. Where I manually invoked the server, when the game was fully loaded.

The results didn’t change.

Would you also be willing to share the partial code for the server side invoked function too?

Currently there’s not enough information to really figure out what’s going on. There’s really not much that can be done other than for you to spam print statements on the serverside invoke function to output the table’s state at each checkpoint in your code.

1 Like

There really isn’t much to the server side code either…

rf.OnServerInvoke = function(plr) --'rf' as mentioned before is the remote function
	return inventory["Players"][plr] --Accessing the players inventory data
end

The player get’s their inventory assigned when .PlayerAdded, thus many times there isn’t a issue.
I will print this on the server side, and debug logs on server side to see any issue.

Thanks again

Well, are you absolutely certain that the player will request the data after it is loaded into the inventory table?

I made a similar system and my solution was to push the inventory to the client instead of having the client request the inventory.

1 Like

It is probably better to send the inventory data as a remote event to the client only after it loads on the server, not ask to retrieve it when the client loads which will usually be before the server recognizes the player (unless in studio where ping is much lower, if not zero). If you need to get hotbar and inventory often then you really shouldn’t use a remote function as the client has to wait for a response, which really shows how bad your ping may be.

Well what’s now new is that it .PlayerAdded actually didn’t run fast enough, or didn’t even run at all, I forgot to mention that all this server code was in a module script. I don’t know whether that makes a difference or not.

Race conditions!

Have you tried pushing the inventory to the client when it’s ready like I’ve shown above? This can help avoid unnecessary network requests and also reduces your attack surface. It’s not like there’s anything to exploit in a simple table retrieval—unless you’re using metatables—but still.

I mean I might remake this inventory system, now that I look at it. There is some improvements that could be made.

Pushing inventory, isn’t really that far off from what I’m doing, already. It’s just a different approach since I’m not using your standard roblox tools. It’s a customised inventory. So I didn’t expect to come to a solution on first try.

Thanks anyway

1 Like

As mentioned by everyone else, there is a good chance your code is affected by race conditions, which means that

inventory["Players"][plr]

is being indexed before it could be assigned to a value. There are many factors that could be causing it. However, we don’t have full info on the script. The solution I will suggest is to yield the function until a valid input is received.

rf.OnServerInvoke = function(plr) --'rf' as mentioned before is the remote function
	while not inventory["Players"][plr] do warn("Waiting on", plr, "inventory index") wait() end
	return inventory["Players"][plr] --Accessing the players inventory data
end

Hope it works!

1 Like

Thank you for the idea, but I later fixed the issue.
It was completely unrelated to invokes, but more so with my data store handling, which I didn’t mention how I handled what so ever.

I used a pcall function in order verify whether there was already data under the user’s ID.

local s,e = pcall(function()
    data = inventoryDs:GetAsync(USERID) -- Mostly pseudo
end

In studio the script would work as intended and create an error. But for some reason when actually playing the game on the website, it return’s nil meaning the execution was successful, but not really :sob:

I still thank you for your time.
(Ironic how I created a race condition, and still denied the fact there was any)

I’m glad you fixed the issue, however from my understanding this can be very vulnerable. For example, an exploiter can fire the same remote event with custom inventory tools, resulting in them receiving free tools.

Uh no that isn’t how my script works, the use of a RemoteFunction, allows for me to have trust worthy data on the server and untrustworthy data on the client. They simply can view what their inventory and hotbar has, and can’t customise their inventory.

My overall plan is to create a unique key for each player’s items every time they join the server. Every time a item is being used, a remote event is sent, along with the key. If the key is not received then the player is likely exploiting, thus punish.

I don’t think there is problem with this system, a client shouldn’t be able to perform any nefarious tasks, such as using items that they don’t own.

Ah, I thought it would set rather than get their inventory.