Speeding up RemoteFunctions?

Hard to see from a video, but when I click the arrows, it takes around 0.5 seconds for the side bar to pop up. This is because I have to fire a RemoteFunction to the server to check to see what items a player has, so that way it can show the list of items with accurate labels (prices for items that the player does not own yet)

com-video-to-gif%20(8)

function createItems(opened)
	clearButtons()
	
	for _, item in pairs(classes[selectedClass][opened]:GetChildren()) do
		local itemButton = Instance.new('ImageButton')
		itemButton.BackgroundTransparency = 1
		itemButton.Name = item.Name
		itemButton.Size = UDim2.new(0.875, 0, 0.125, 0)
		itemButton.SizeConstraint = 'RelativeXX'
		itemButton.ZIndex = 2
		itemButton.Image = 'rbxassetid://295943235'
		itemButton.ImageColor3 = Color3.fromRGB(150, 150, 150)
		itemButton.ScaleType = 'Slice'
		itemButton.SliceCenter = Rect.new(10, 10, 20, 20)
		
		local name = Instance.new('TextLabel')
		name.AnchorPoint = Vector2.new(0, 0.5)
		name.BackgroundTransparency = 1
		name.Name = 'Label'
		name.Position = UDim2.new(0.05, 0, 0.5, 0)
		name.Size = UDim2.new(0.55, 0, 0.6, 0)
		name.ZIndex = 2
		name.Font = 'GothamBold'
		name.Text = item.Name
		name.TextColor3 = Color3.fromRGB(255, 255, 255)
		name.TextScaled = true
		name.TextXAlignment = 'Left'
		
		local hasItem, equipped = checkClassItem:InvokeServer(selectedClass, opened, item.Name)
		
		if hasItem then
			if equipped then
				local equip = Instance.new('TextLabel')
				equip.AnchorPoint = Vector2.new(1, 0.5)
				equip.BackgroundTransparency = 1
				equip.Name = 'Cost'
				equip.Position = UDim2.new(1, 0, 0.5, 0)
				equip.Size = UDim2.new(0.275, 0, 0.6, 0)
				equip.ZIndex = 2
				equip.Font = 'GothamBlack'
				equip.Text = 'Equipped'
				equip.TextColor3 = Color3.fromRGB(255, 255, 255)
				equip.TextScaled = true
				equip.TextXAlignment = 'Left'
			end
		else
			createCost(itemButton, name)
		end
		
		name.Parent = itemButton
		itemButton.Parent = scrolling
	end
end

Problem lying here:

local hasItem, equipped = checkClassItem:InvokeServer(selectedClass, opened, item.Name)

This:

  1. checks to see if they own the item and
  2. if that item is the currently equipped item.

Another problem, is since it’s slow to respond, if I click both the weapon and armour buttons before the function has returned, then it crates buttons for both the sword and armour.

This is what’s called at the top of the createButtons to remove the previous buttons from the list.

function clearButtons()
	for _, button in pairs(scrolling:GetChildren()) do
		if button:IsA('ImageButton') then
			button:Destroy()
		end
	end
end

How can I go about speeding this process up?

1 Like

So, I would say, have the client already know what weapons the player has, and have the server update the client everytime the weapons changes

8 Likes

Hmmm sounds like a good idea, not sure how I would go about storing that in the client tho.

Thinking if firing the RemoteFunction when the player joins, then somehow organising that into a table or array

If the client was the only one that held a table/array of weapons, couldn’t that be manipulated (never trust the client?) to give the player more weapons?

Here’s my unprofessional solution to this:
Have the client request a copy of the player’s items once the scripts load or something.
Each time the server’s version of the player’s items change, it will update the client to change it’s buttons or whatever.
As for storing it in the client? i’m not sure what’s the problem here, you can store it in the server, just make a similar copy of that and use it in the client.

If you verify on the server each weapon, you could verify and set the weapon to a default if they have an invalid weapon.

2 Likes

The client is holding a copy of the actual table/array of weapons, the client is just using it so the user can visualize the table without delay.

5 Likes

Ah, okay - I didn’t realize that there was an implied server-side verification step.

1 Like

I’m sure the client can see the weapons they have, so just use that. If they exploit; who cares - just make sure they actually own the weapon when equipping it on the server.

Otherwise, just give them a table of stuff they have on game join and whenever a new tool is given to them, let them know.

Since there can be 2 different ‘categories’ (weapons/armour) not sure how to get the function to fire for each one seperately??

Add to the fact that if there’s a dozen classes, each with their own Weapons/Armour, I’d have to fire the function a ton of times just to get all the data in the player

The weapons they have are being stored in a data store, so they can’t see what items they have without going to the server to access their data store

Put all the data in one event.
EG

{
 Armor = {},
 Weapons = {},
 Etc= {}
}
1 Like

Ok, so I have this implemented in my game in a similar way on another account.
Now, if I was very stupid I would tell you to make two modulescripts and just use another parameter in the remote function to see which array you are modifying.

So that’s exactly what I’m going to tell you. Do that.

What I got setup is this:

storedItems = checkClassItem:InvokeServer()

StoredItems is just an empty table module. Then checkClassItem() should be returning 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', 
			},
		},
	},

Which contains all the classes + any weapons a player will have unlocked

EDIT However, the use of the StoredItems module is kinda redundant, I could just do storedItems = {} inside the current script anyway

1 Like

What you’ll want to do then is this suggestion:

I think modulescripts are mainly used for organizing code and having a shared table, yes, it is redundant, but if you want other localscripts to be able to access this table I would use modulescripts.

My backpack script uses metatables for methods, like AddToBackpack, ClearBackpack, RemoveFromBackpack

local methods = {}
methods.__index = methods

function methods:foo()
self.Index1 = "Hello"
end

local backpack = setmetatable({}, methods)
return backpack
1 Like

How can I get the stored items to change when the player has purchased something, etc.?

This is fired when it’s called (which is when the player joins)

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

Then this is the what is returned

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

When a player buys an item basically, they have to rejoin the server for it say it’s be brought basically, because the datas only being set when they join, but Idk how to re-set it again. I tried doing this

storedItems = checkClass:InvokeServer() -- storedItems == require(script.Parent.StoredItems)

after they make a purchase, but nothing happened

that delay is because your first deleteing every item and then recreating them. what you could do instead is creating a cache that contains previously created labels. if an item doesnt have a label yet make one, if the item is out of the list remove it. this is my tactic on this issue

1 Like

Rip, just adding in more buttons now and it’s taking forever for them to load :confused:

What would be the most efficient way to go about caching them then? I’ve managed to cache the data, so it doesn’t take long to get what items the player has, but yea, creating the buttons is causing a huge slow down, even with only 4-5 buttons it can take 2-3 seconds to load them all up