Caching and updating player data in the client

Storing the items inside the Client:

local replicatedStorage = game:GetService('ReplicatedStorage')

local remotes = replicatedStorage:WaitForChild('Remotes')

local functions = remotes:WaitForChild('Functions')
local checkClass = functions:WaitForChild('CheckClass')

local storedItems = checkClass:InvokeServer()

return storedItems

Server script which gets the data and returns it

function checkClass.OnServerInvoke(player)
	repeat wait() until dataReady
	
	local user = playersData[player.UserId]
	if not user then return end
		
	return user.Classes
end

Now this works fine, when the player joins. However, if this data gets updated, then the client will still have the old data to view. I’ve tried multiple things to update the data in the client, doing this in a separate module, but this does nothing anyway

storedItems = checkClass:InvokeServer()

Should I assume that your client-side code is contained within a ModuleScript? If so, your issue is that every subsequent require after an initial require of a ModuleScript returns the same thing.

When your ModuleScript first gets required, it runs the code above the return statement once. The return value of checkClass’s InvokeServer method is assigned to the storedItems variable and the ModuleScript is told to return storedItems whenever the ModuleScript is required. Now you see, the logic only runs once, it does not re-run. Every require after the first time will return what checkClass.InvokeServer returned said first time.

Ideally, you’d want to make a method for this module so that you can be getting updated results.

-- Module
local replicatedStorage = game:GetService("ReplicatedStorage")

local remotes = replicatedStorage:WaitForChild("Remotes")

local functions = remotes:WaitForChild('Functions')
local checkClass = functions:WaitForChild('CheckClass')

local storedItems = {}

function storedItems.Get()
    return checkClass:InvokeServer()
end

return storedItems

-- Other Script
local storedItems = require(module)

local currentStoredItems = storedItems.Get()

Putting your code in a function means that you can call it any time you want to get the new value of something. It doesn’t become static anymore. Instead of returning a value from something that’s only called once, you now have it in a function. In the function’s scope, it is told to run checkClass.InvokeServer each time the function Get is called. So with that, it returns a new value each time instead of the same thing each time.

I mostly placed it inside a casual ModuleScript-based approach since I like to be explicit about my code, but you can also return a function.

-- Module
return function()
    return checkClass:InvokeServer()
end

-- Script
local pollStoredItems = require(module) -- Returns the function

local storedItems = pollStoredItems() -- Calls the function that was returned from the module, assigns return value to variable

Hopefully that made sense. I don’t know how to explain it well, but I know how it works at the very least.

2 Likes
for _, v in pairs(storedItems) do
	if v.ID == classID then -- Error
	end
end

[attempt to index local 'v' (a function value)]
This is in a seperate script, which basically checks if the player has the class in their stored data. It worked before when the player rejoined, but with your code I get that error :confused:

1 Like

Which code did you try and what’s the value of storedItems?

Well with my code in the OP, stored items would be a table, looking like this:

	Classes = {
		Knight = {
			ID = 1,
			Owned = true,
			Weapons = {
				'Sword',
			},
			Armours = {
				'Griswold'
			},
			Equipped = {
				Weapon = 'Sword', 
				Armour = 'Griswold', 
			},
		},
		Archer = {
			ID = 2,
			Owned = true,
			Weapons = {
				'Bow'
			},
			Armours = {
				'Iron'
			},
			Equipped = {
				Weapon = 'Bow', 
				Armour = 'Iron', 
			},
		},
		Scout = {
			ID = 3,
			Owned = false,
			Weapons = {
				'Dagger'
			},
			Armours = {
				'Finn'
			},
			Equipped = {
				Weapon = 'Dagger', 
				Armour = 'Finn', 
			},
		},
		Hunter = {
			ID = 4,
			Owned = false,
			Weapons = {
				'Crossbow'
			},
			Armours = {
				'Bombo'
			},
			Equipped = {
				Weapon = 'Crossbow', 
				Armour = 'Bombo', 
			},
		},
	},

This is what user.Classes is (so that’s what’s returned from the server to the client, and this is what storedItems should equal)

Printing v prints a table.

I used the top code in your post, not sure what the bottom code is for/does?

EDIT Just tried with the bottom code as well, now it won’t even print table, now it says table expected, got function

1 Like

The problem is that you’re iterating through the storedItems module as opposed to the return value of the Get method. You need to call the method Get first so that the table can be returned from its call.

for _, v in pairs(storedItems.Get()) do
    -- do your thing
end

If you’re using my second suggestion of code, you’d just chop off the Get method and call the variable directly. It’s just a shorthand to the first block, but I wouldn’t recommend using it unless you understand what explicitly its doing (returning a function to be called, which then you can call that function to return something).

for _, v in pairs(storedItems()) do
    -- do your thing
end
3 Likes

Works now :smiley: thank you!

1 Like