Is there any way to make super-efficient parts, similar to how minecraft works?

Well I didn’t test the performance difference, so I don’t know if it’s better.

1 Like

This is a good idea, but if we take a minecraft chunk (16 x 255 x 16), that would still be 65536 parts per chunk at their maximum and I think that would still cause lag.

I’ll test it later but I feel like that would only work once I can lower performance impact on a single chunk. All the generation I’ve done is small scale and it still decides to lag out at a point

A way to be more efficient is to implement culling.

So any parts that are not visible (none of it’s neighbours are air) are simply not rendered in or in this case, the part for the block is not created.

This way instead of thousands of redundant blocks you only have the blocks that the player can see which obviously makes it more efficient.

4 Likes

If you’re trying to make efficient parts like minecraft, a chunk-loading system would be the way to go.

Minecraft isn’t actually the most anti-lag game. I would argue that it actually is too precise; a lot of blocks are rendered precisely whenever it is loaded to the player, even if the player is not close to or looking at those blocks.

This is obviously filtered out by their chunk-loading system, which is what I would suggest doing. Have it be a sort of system that the player can decide how many chunks they want to load in dynamically.

2 Likes

I see a way I could go with this, but I have one other question.

Say I were to implement the culling feature, and not render / not place the blocks that are not visible. If I were to store redundant blocks in a table, for example, how can I make sure that the table does not get too large / take up too much memory?

1 Like

This might not be the best solution, but I would assign the information of a block type like material, colour, and more to an Integer value. When a new chunk loads, store all the blocks in that specific chunk as an Integer with the Vector3 (can be a relative position, can be a world position) instead of as a BasePart in a table. When the chunk needs to be loaded again after the blocks despawn, generate the blocks based on the Integers and place them at the Vector3 position.

1 Like

What I’d recommend (this is basically what Minecraft does, so I’m assuming your world is voxel):

  • Chunks: Your “world” is stored in a 3d matrix (table with tables with tables). The client uses a remote event to request chunks then removes the memory of the chunks a little bit after it doesn’t need them anymore
  • As someone said, culling. Hide/remove textures and parts that aren’t in view.
  • Don’t create blocks that aren’t on “the surface”. If the block is surrounded by blocks, it’s not needed. Adding on to this, if a texture is next to a block it isn’t needed either.
  • If you’re using textures, you can also use greedy meshing. Consume everything - how greedy meshing works

If you’re making triangle terrain, you should use culling and chunks (or something similar – send the terrain from the server).

Edit:
image (First image I found on google)
This is what I mean by hiding parts that aren’t on the surface. A Roblox version would show part tubes with no textures though. Don’t use transparent parts and textures.


To answer your topic title’s question, yes. Elttob, the person who wrote the greedy meshing article, created BLOX, which, from the player’s perspective, has hundreds of thousands of parts.

2 Likes

Minecraft generates meshes for each chunk and doesn’t render the faces that are hidden behind blocks to reduce lag and as far as I know Roblox has no built in way of doing this. However there probably is still ways of improving performance like not rendering parts when they are behind other ones.

I was also thinking about doing something similar a while ago. my ideas were something along the lines of getting a “plane” mesh 1 faced mesh and putting a decal/texture on it. and like the other suggestions you need to have a good system to only load the faces that can be visible. You could even go as far to store data on the client about the terrain and only load it when visible ( maybe you do raycasts to an area of blocks ) or another system.

This has actually already been made by a smart person who made an uncopylocked Minecraft clone on Roblox. Sadly, it got reuploaded everywhere so I don’t know who made the original copy. Here is an example uncopylocked place that I found: Minecraft UNCOPYLOCKED - Roblox

You can see what techniques are used there to optimize the game as much as possible. By the way, always store block data on the server and have the client request the info whenever they get far enough. This way the server can generate the terrain using a Seed, store it in its database, and any changes made will only replicate to players who have that chunk loaded.

1 Like

oh yea I understand why I was thinking you sould send small amounts of data on the client, so it could handle some of the workload trying to limit the amount rendered.

The solution to this problem is voxels. You cannot create them yourself, but you can use Roblox’s Terrain, which is a voxel system. I know Roblox’s Terrain is not what you want, but you will not be able to compete in the same scale or efficiency without the infrastructure that Terrain has.

Have you looked into StreamingEnabled?
It will probably help with performance in this situation and works similar to Minecraft chunks.

Ohhh I completely forgot about this ima go mess around with it and see what I can do.

Thanks!

No problem, It can be a bit finicky and I noticed that Adornees do not work with it enabled, but that isn’t that big of a deal.

1 Like

Alright, so by using the culling technique I was able to make a 144 * 128 * 144 area that runs at a smooth framerate:


However, there are two issues:

  1. Roblox is using a LOT of memory to store these giant arrays. If this were to be scaled larger (i.e. players can load chunks as they go) this could probably end up crashing a server or slowing it to a crawl
    image
  2. I think this same issue is also why roblox studio makes me force quit instead of being able to just click stop, because it can’t clean up the massive table. Is there any solution to this?

My tables are currently formatted as mapArray[x][y][z] = blockID. Is this inefficient? I appreciate all of the help so far!

Wow! That’s a lot of memory. I think some of that is coming from having both an array and parts.

What I’d recommend:

  • Client sided parts: No parts on the server, just the mapArray (so the server doesn’t have both the array AND the parts). Then send chunks to the client for viewing and physics.
  • This might be difficult, but regenerating chunks and only saving changes made to chunks (like how Minecraft creates an infinite world).

What you can do to trouble shoot:

  • To test if the memory problem is caused by the array, try this code or something similar on the server:
local mapArray = {}
for x = 1, 144 do
	mapArray[x] = {}
	for y = 1, 128 do
		mapArray[x][y] = {}
		for z = 1, 144 do
			mapArray[x][y][z] = math.random(1,64)
		end
	end
end

game:GetService("RunService").Heartbeat:Connect(function()
	print(mapArray[math.random(1,144)][math.random(1,128)][math.random(1,144)])
end)

You’ll notice that the server seems to be doing fine (quick tip, you can press F9 to view some useful info, like server stats). This means the problem is probably having so many parts on the server, so client sided parts should fix your problem.

I highly recommend using the built in Terrain if you can. It handles these optimizations for you. You can create your own generator for it.

If you insist on doing it with parts, you can look at how Roblox optimized their terrain data storage for inspiration.

As for rendering the parts, though… it would require a lot of work. You’ll definitely need some kind of culling, but you also don’t have access to the kind of low level functionality that most games that do this sort of thing use, so it’ll never be as fast as ROBLOX’s terrain.

3 Likes

Add another note: yes. This is creating a whole new object for each row, and for each voxel.

Store everything in one contiguous array and access things with index math

When you use noise (optionally) you can provide a specific seed. Provided the same seed, your game will always have the same terrain. So what i recommend is that you only save data about chunks which have been modified by players and use the same seed for generated unmodified chunks