I want to put some thoughts on the worldgen for discussion:
1. I went through some of the interfaces and there seem to be a lot of interfaces which are completely tied to facetedWorldGeneration:
The WorldGenerator contains a method getWorld(), which is basically getSeaLevel + stuff for faceted generation (World). The term "World" seems to be wrong to me too: Why do i have to create chunks but also have to know how to create a "World"?
->(a) We could probably replace the method with getSeaLevel and put all the faceted stuff in the faceted provider.
2. The generator has to place the blocks in the chunk, means there is a likely some converting required, from world to local coordinates.
->(b) Can we rewrite the api in a way, that world generation depends only on world coordinates? It could still be something like: generate(AnyRegion region) but region could have only a .setSomething(Vector3i worldPosition, Something) and encapsulate the internal storage and world->local converting.
3. Facets and borders can get really confusing:
Take a facet with a noise-based distribution of spawnpoints as example. If the spawned structure can raise over chunk borders, you need to extend the chunk facet region.
Now for to Chunks A and B, each chunk will generate the same noise for the region, both may have an overlapping spawnpoint near their border and each chunk will generate only the blocks included in its region. Most of the time with stuff like: for each block of the structure -> if the block is in my chunk region -> place block.
This gets even worse for trees, which are generated by L systems.
If a tree covers N chunks, the entire L system is computed N times but only the blocks from the n-th chunk are set.
More fun for 2D-Data like a heightmap: Instead of calculating the heightmap once for each x-z axis, we calculate the heightmap for each x-z-y chunk
Means: If you have two chunks on top of each other, both will generate the same heightmap from the same noise, instead of reusing the data.
->(c) Can we find a way to "inverse" the process and remove all borders and facets from the "per chunk" view? I think we still need a border/max size info per facet, but maybe we can implement a way to reuse/cache the facet data globally instead of per-chunk.
Probably a goode usecase for the last one is a rainforest: Large trees may cover mutliple chunks in any direction and any size (why not have a super rainforest with 10 chunks height ) Trees are generated by a subsystem which is expensive enough to save the data for one tree instead of calculating it again and again.
One Idea how to solve this:
We ask the worldgenerator if there are blocks to place for a tree. The generator checks first the TreeSpawnPointFacet in each direction, covering an area as big as the maximum tree size (to be configured in the facet or somewhere). If the information is not present, the facet is exended by the required chunks. Internally, we can cache the information per-chunk but maybe limited for n chunks or for xyz time intervals.
If there is a tree spawnpoint in a distance that the tree may spawn into the current chunk, the tree is entirely generated and the blocks are put into a cache - also per chunk - (imaginary data structure, like a facet but with a different caching mechanism).
Afterwards, the rasterizer picks the blocks from the cache and places them (likely we can clear the cache for this chunk afterwards).
If we now go to the next chunk, there is already the cache calculated for the tree on the spawn position. We may resolve other trees (and probably need a merge strategy with conflicting blocks in the cache) but if we raster the trees in the chunk, we can use the existing blocks.
If world generation is paused and the game is restarted while a tree is only generated to 50%, the next time parts of it are required, we regenerate the cache for all not-generated chunks.
This would also enable to cache 2D data like heightmaps in a different/more efficient way than 3d-Data like spawn positions for object.
I did no proof-of-concept implementation so far but wanted to discuss the ideas first.
Thanks for any replies/ideas/stuff i missed
1. I went through some of the interfaces and there seem to be a lot of interfaces which are completely tied to facetedWorldGeneration:
The WorldGenerator contains a method getWorld(), which is basically getSeaLevel + stuff for faceted generation (World). The term "World" seems to be wrong to me too: Why do i have to create chunks but also have to know how to create a "World"?
->(a) We could probably replace the method with getSeaLevel and put all the faceted stuff in the faceted provider.
2. The generator has to place the blocks in the chunk, means there is a likely some converting required, from world to local coordinates.
->(b) Can we rewrite the api in a way, that world generation depends only on world coordinates? It could still be something like: generate(AnyRegion region) but region could have only a .setSomething(Vector3i worldPosition, Something) and encapsulate the internal storage and world->local converting.
3. Facets and borders can get really confusing:
Take a facet with a noise-based distribution of spawnpoints as example. If the spawned structure can raise over chunk borders, you need to extend the chunk facet region.
Now for to Chunks A and B, each chunk will generate the same noise for the region, both may have an overlapping spawnpoint near their border and each chunk will generate only the blocks included in its region. Most of the time with stuff like: for each block of the structure -> if the block is in my chunk region -> place block.
This gets even worse for trees, which are generated by L systems.
If a tree covers N chunks, the entire L system is computed N times but only the blocks from the n-th chunk are set.
More fun for 2D-Data like a heightmap: Instead of calculating the heightmap once for each x-z axis, we calculate the heightmap for each x-z-y chunk
Means: If you have two chunks on top of each other, both will generate the same heightmap from the same noise, instead of reusing the data.
->(c) Can we find a way to "inverse" the process and remove all borders and facets from the "per chunk" view? I think we still need a border/max size info per facet, but maybe we can implement a way to reuse/cache the facet data globally instead of per-chunk.
Probably a goode usecase for the last one is a rainforest: Large trees may cover mutliple chunks in any direction and any size (why not have a super rainforest with 10 chunks height ) Trees are generated by a subsystem which is expensive enough to save the data for one tree instead of calculating it again and again.
One Idea how to solve this:
We ask the worldgenerator if there are blocks to place for a tree. The generator checks first the TreeSpawnPointFacet in each direction, covering an area as big as the maximum tree size (to be configured in the facet or somewhere). If the information is not present, the facet is exended by the required chunks. Internally, we can cache the information per-chunk but maybe limited for n chunks or for xyz time intervals.
If there is a tree spawnpoint in a distance that the tree may spawn into the current chunk, the tree is entirely generated and the blocks are put into a cache - also per chunk - (imaginary data structure, like a facet but with a different caching mechanism).
Afterwards, the rasterizer picks the blocks from the cache and places them (likely we can clear the cache for this chunk afterwards).
If we now go to the next chunk, there is already the cache calculated for the tree on the spawn position. We may resolve other trees (and probably need a merge strategy with conflicting blocks in the cache) but if we raster the trees in the chunk, we can use the existing blocks.
If world generation is paused and the game is restarted while a tree is only generated to 50%, the next time parts of it are required, we regenerate the cache for all not-generated chunks.
This would also enable to cache 2D data like heightmaps in a different/more efficient way than 3d-Data like spawn positions for object.
I did no proof-of-concept implementation so far but wanted to discuss the ideas first.
Thanks for any replies/ideas/stuff i missed