Spawn and Collect Item Client-Side

(Sorry for the last topic, I accidentally clicked create topic)

I’m trying to make a collectible item that’s only visible on the client-side, just like Grass Cutting Incremental, which has each person having their own field and own grass to cut specific to them.

What I want to do is spawn blocks client-sided, so when a player touches a block, it adds a coin. It works fine like i want, but there are 3 problems:

  1. When there are over 3-4k blocks the game starts to lag, collects it after 2-3 seconds
  2. Table gaps (never seen it before), like this:
--[1] =  ▶ {...},
--[2] =  ▶ {...},
--[3] =  ▶ {...},
--[4] = nil,
--[5] = nil,
--[6] =  ▶ {...},
--[7] =  ▶ {...},
--[8] =  ▶ {...},
--[9] =  ▶ {...},
--[10] =  ▶ {...},
  1. The way i’m doing is it exploitable?

Server:

--// Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

--// Variables
local blocks = {}

local function BlockAmount(player)
	
	local number = 0
	
	for ID, info in pairs(blocks[player.UserId]) do
		number+=1
	end
	
	return number
end

Players.PlayerAdded:Connect(function(player)
	
	-- adds player to the block's table
	blocks[player.UserId] = {}
	
	-- create leaderstats
	local folder = Instance.new("Folder")
	folder.Name = "leaderstats"

	local cash = Instance.new("NumberValue")
	cash.Name = "Cash"
	cash.Parent = folder

	folder.Parent = player
	
	-- block's loop
	task.spawn(function()
		
		local ID = 0
		while player.Parent do
			
			if BlockAmount(player) < 4000 then
				ID += 1

				-- block info
				local block = {}
				block.Type = "Basic"
				block.ID = ID
				block.Position = Vector3.new(math.random(-50, 50), 2, math.random(-50, 50))
				block.Value = 10

				-- store block info
				table.insert(blocks[player.UserId], block)

				-- tell the player to spawn a block
				ReplicatedStorage.Remotes.Spawn:FireClient(player, block)
			end
			
			task.wait()
		end
	end)
end)

Players.PlayerRemoving:Connect(function(player)
	
	-- destroy player block's
	blocks[player.UserId] = nil
end)


ReplicatedStorage.Remotes.Collect.OnServerInvoke = function(player, pos, ID)
	
	for block, info in pairs(blocks[player.UserId]) do
		
		if info.ID == ID then
			if info.Position == pos then

				player.leaderstats.Cash.Value += info.Value
				blocks[player.UserId][block] = nil

				return true
			end
		end
		
	end

	return false
end

Client:

--// Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")

ReplicatedStorage.Remotes.Spawn.OnClientEvent:Connect(function(blockInfo)
	
	-- create block
	local block = ReplicatedStorage.Blocks:FindFirstChild(blockInfo.Type):Clone()
	block.Position = blockInfo.Position
	block.Parent = workspace.Blocks
	
	-- when player touches block then
	block.Touched:Connect(function(hit)
		
		local character = hit.Parent:FindFirstChild("Humanoid")
		
		if character then
			
			-- make sure the block is in the same position as it was originally generated
			local canCollect = ReplicatedStorage.Remotes.Collect:InvokeServer(block.Position, blockInfo.ID)
			if canCollect then
				
				if block then
					block:Destroy()
				end
			end
		end
	end)
end)

Would not recommend doing this on the client, hackers would easily be able to manipulate the system.

Sorry for the late reply, I know that, but for the type of game I’m doing this is really necessary, as I said I’m trying to make something like Grass Cutting Incremental.

The code you provided seems to be working as intended, but it has some issues that might cause problems in the future. Let’s go over each of the issues you mentioned:

  1. Performance degradation with over 3-4k blocks: This issue is expected as the more blocks that are added to the game, the more memory and processing power it requires to keep track of them. You can optimize your code by reducing the number of blocks that are spawned or by using a more efficient algorithm to keep track of the blocks.
  2. Table gaps: This issue is caused by the way Lua handles table inserts and removals. When you remove an item from a table, it leaves a gap in the table, which may cause issues with table iteration. To solve this issue, you can use the table.remove function to remove items from the table, which will automatically shift the items in the table to fill the gaps.
  3. Exploits: The code you provided does not have any obvious exploits, but you should always be careful when handling client-side data as it can be modified by malicious users. One way to prevent exploits is to validate the data on the server-side before processing it.

Aside from the issues you mentioned, there are also some improvements you can make to your code to make it more efficient:

  1. Use a for loop instead of a while loop to iterate over the blocks. This will reduce the number of function calls and improve performance.
  2. Use a dictionary instead of a table to store the block information. This will make it easier to look up blocks by their ID and improve performance.
  3. Use a remote event to notify the server when a block is touched instead of invoking a remote function. This will reduce the number of remote function calls and improve performance.
1 Like

Thank you for your reply! I made some changes, with what you said and it’s working perfectly, thank you so much!

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