Hundreds of parts cause a LOT of lag

You could utilise the ‘Debris’ service to clean up old heads.

local Game = game
local Workspace = workspace
local Debris = Game:GetService("Debris")

local HeadClone = Head:Clone() --'Head' is a reference to a head.
HeadClone.CFrame = CFrame.new(0, 0, 0) --Move the head.
Debris:AddItem(HeadClone, 30) --Schedule for the head to be removed after 30 seconds.
HeadClone.Parent = Workspace
1 Like

Sorry if this is not a Script (Lighting)
You can, setting the lightings (example turn of shadows, and other shaders)
or better if the heads were not a union or meshed parts

or you can change the material to Smooth Plastic, to turn of the hidden PBR effect
or set do not use ShadowMap and Voxel.
but if you are going to use future, turn of the Light Shadows from lights (if you do have them)

2 Likes

How about creating a render distance system

1 Like

Use remotes and put everything on the clients side, to allow other players to see everyone elses heads use FireAllClients().

Could you supply some sample code? It would make it easier to help you.

1 Like
event.OnServerEvent:Connect(function(player)
	local char = player.Character
	local head = char:WaitForChild("Head")
	
	local headFolder = player.Character:WaitForChild("headContainer")
	h.Value += 1*m.Value
	
	local c = head:Clone()
	c.Parent = headFolder
	c.CanCollide = false
	c.Name = player.Name.."Head"
end)

Inside a server script

1 Like

The thing is that I already destroy the heads after they sell so

1 Like

You would do something like:

Server script:

Event.OnServerEvent:Connect(function(player)
 -- put whatever sanity checks here
    Remote:FireAllClients()
end)

On local script:

Remote.OnClientEvent:Connect(function(player)
        -- head code stuff goes here
	local character = player.Character
	local head = character:WaitForChild("Head")
	
	local headFolder = character:WaitForChild("headContainer")
	h.Value += 1*m.Value
	
	local c = head:Clone()
	c.Parent = headFolder
	c.CanCollide = false
	c.Name = player.Name.."Head"
end)

Something like this, I haven’t tested this in studio.

This way your storing the heads on all the clients individually instead of storing it on the server. Make sure you have sufficient sanity checks though so players cant exploit by firing the remotes illegally.

1 Like

Sorry for responding so late but would “Remote” be a different RemoteEvent or a RemoteFunction?

1 Like

Yes Remote is a different remote event.

You can see more on Remote events here:

Fire a remote from client to server, when server receives, it fires another remote with FireAllClients with the hard as a parameter, the client will clone the head and destroy the original one on the server

So I tried this method and these are the results…

  1. The heads only still show for the player
  2. They don’t disappear when you sell…
event.OnClientEvent:Connect(function()
	local c = head:Clone()
	c.Parent = headFolder

end)

Sell script:

			for _, v in pairs(folder:GetChildren()) do
				if v:IsA("Part") then
					v:Destroy()
				end
			end

The way your system should be set up, is every time the player wishes to perform a certain action, whether it be to sell a head, buy a head etc, you should always be telling the server to tell all other clients to also perform this action.

The reason why you would first tell the server that player1 has sold a head, is so the server can authenticate the sale, basically to check there’s no illegal business going on here (exploits), after the server has completed the necessary checks, you should then go and fire this command (which player1 initiated) to all other clients, player’s 2 and 3 etc, which would be to sell player1’s head.

Everything mentioned above can only be done using remote events, I suggest you thoroughly learn remote events to better your scripting knowledge.

So to my understanding, I need to create another remote event for selling and then fire that to then which activated the sell script?

For example:

event.OnClientEvent:Connect(function()
	for _, v in pairs(folder:GetChildren()) do
		if v:IsA("Part") then
			v:Destroy()
		end
	end
end)

Yes, player1 would press the “sell head” gui button, upon that button being clicked, you should fire a remote event to the server telling the server: player1 has attempted to sell his head! then the server will check to see if player1 is allowed to sell his head, if player1 is allowed to sell his head, then you would fire another remote (this time to all clients) telling all other players on their own clients to delete player1’s head.

It’s touch for this game but I get the point. But how would I check if the player is “allowed” to sell their head?

That depends on how your game is setup, one way could be checking if the player has enough cash to buy a head? check if the player owns a head?, I would recommend first trying to get the remote event communication working first before we go into how the server can do checks.

Before all the security checks to see if a player is allowed to do an action, can you help me first with the head cloning issue? The cloned heads only show on the local player and won’t show for anyone else.

That’s what I have been explaining, any action that involves heads, whether it be creating, cloning or selling, has to go through this system if you want no lag and all players to see it.

No I get that I have to use multiple RemoteEvents, but you never clearly explained how I can make it so the heads are cloned on the client side but still shows for everyone else. All you told me to use is Remote.OnClientEvent:Connect(function(player) but that did nothing to help. It made it worse as it made the heads not even show for other players.

This is the same problem that Slither .io Simulator tries to solve, and it is hard. The max I can CFrame is about 2,500 parts per heartbeat before it drops below 30fps and there is a lot of tricks I used to tweak the performance.

Suggest to read this post on Lag Prevention and one key bit of information there is in the 3rd-to-last paragraph where it mentions that parts parented to Cameras, among other things, will not replicate any of the usual properties. Slither uses this technique to parent thousands of spheres to folders inside the Camera, which short circuits a lot of replication.

Careful what you wish for, because then without replication in place, you need to take over the positioning of the parts yourself. Each client will need to render hundreds of heads for themselves and all of the other players, every frame. Each client will need to upload their stream of heads position data to the server by firing a RemoteEvent. Server then aggregates all these feeds and publishes a feed of all of each players’ heads positions and fire a remote 20x per second. All clients will need to connect to that and reposition all of each players heads based on that feed. If the exact position isn’t important then you’ll be able to transmit much less information, perhaps just the initial position and velocity and size and theme for the heads might get you pretty far. Just send the minimum properties in your packets, and don’t ever send Part instances or references to huge Player or Character structures in your events.

Once you set up a heartbeat callback to process the positioning each frame, you can optimize it by careful use of task.defer() to separate the heartbeat into a prepare and present phase. Do all the maths in your Heartbeat callback and use task.defer for your CFraming. Get familiar with the microprofiler and you’ll be able to tell that the CPU and GPU can optimize a large batch of only CFrame operations versus having to do maths CFrame maths CFrame maths CFrame which is how us human beings mostly like to write code.

One more trick I can give you is if you reach a threshold of say a thousand parts you can start skipping the rendering of certain parts on certain frames. Simple use of distance formula (Vector3.Magnitude) to filter out some parts from being rendered in some frames, can go a long way.

2 Likes