Saving procedurally generated, modifiable worlds

This is more of a “how would I go about …” question than it is a “how do I code …” question.

Lets say I have a world that is procedurally generated given a seed, the world is about the size of the default Baseplate in Studio. In my script, trees, rocks, and flowers are placed around the world. The player will be able to place buildings like houses, and plant things like flowers within this world on a fixed grid. Also on this grid, the player should be able to terraform the world. The player can chop down trees and destroy rocks.

I know one way to store this data would be to use AssetService:CreatePlaceAsync() and SavePlaceAsync, but I’m not sure if this is deemed as a legacy way of saving large amounts of world data.

Some other problems with system would be:

  • If a player had built something inappropriate, it’s under my account as a published place
  • If I update the game’s code, I would have to update the scripts and content under every subplace
    • Or, I would have to make my game use require() and a lot of InsertService (not sure if required scripts can come with children that are Models and not scripts)…
  • There’s a ton of places being made, and it seems messy to fill up my game’s subplaces with user-made places.

You’ll definitely want to use DataStore Services for Saving/Loading data.

If you’re generating a world deterministically through a seed, you can reduce your total save amount by only saving the changes in the world and not everything that has been generated.

For saving/loading in general, you’ll want to reduce the amount you’re saving by only saving as little as possible. Some methods of reducing content is to make lookup tables.

‘1’ = Mesh1,
‘2’ = Mesh2,
‘3’ = Mesh3,
etc…

Now you’d only need to save small strings instead of full MeshID’s.
Then you’d basically end up just saving a really big array of all your world objects in your DataStore full of metadata.
You’d probably need to split it up into different sections for each usecase in the datastore to keep things simple. 1 section for all your world objects, 1 section for all the terrain changes, 1 section for all the changes in world flora/fauna, etc…

Saving/Loading is very open-ended, I hope this helps a bit

1 Like

this can become extremely unwieldy to try to maintain by hand, so I recommend generating it on a per save basis at save time via serialization, then at load do a deserialization step to turn it back into your normal table format.

To maximize your data serialized in a single key you’ll want to use a bitbuffer. Base128 is the most efficient you can get in Roblox, because any characters after that use 2 bytes to represent each character. You can take it a step further and lower the precision of your numbers down from 64bit floats to smaller floats, or even down to integers thanks to the grid.

This thread is very helpful.

1 Like

Thanks for your reply. I think I’ve got an idea for buildings and structures down (since they’re predetermined, all I have to do is record position within the grid and rotation). My main concern at this point is the modifiable terrain. For more context as to how I want to handle the terrain, it’s currently thought of like a layered cake, akin to Animal Crossing: New Horizons, where you can go up only 3 layers, and terraforming the 1st layer downward creates water, like the rivers you see in the game.

Best visualized like this, the greener the area, the higher the terrain is:
image

Is the best way to go about this to:

  1. Generate the world with its seed
  2. Keep track of what has been modified from the original, with this, apply to generated world on session load
  3. Finally, do the rest of work and load props and buildings
1 Like

This is exactly how Animal Crossing, Minecraft, and basically every PCG’d level sandbox game works. :+1:

1 Like