So a few weeks ago I successfully integrated the [islands] mapgen by TheTermos into Lazarr!
But lately, I noticed its loading times can screw up the spawning. The spawning area shows up too late, which was annoying.
Then I remembered the new Minetest feature about threaded mapgen and finally decided to give it a try. The rationale for this was that normal Lua mapgen slowed down the server because it was not threaded. So the threading feature was exposed to Lua. This makes complete sense. Great.
So I thought it will be difficult but it was not. The mapgen of the game is thankfully simple, so I just had to change few lines of code.
(By the way, here's the finished file: mapgen.lua)
Basically, these steps were needed:
1) Clean the mapgen code of any complex stuff that would
2) Instead of dofile-ing it, call it with mapgen.register_mapgen_script
3) Change minetest.register_on_generated because in the mapgen environment, this function takes a vmanip object as first parameter
4) Remove voxelmanip:write_to_map because this is not permitted nor needed in the mapgen environment
And that was basically it to transform my game, the mapgen already worked!
Well … Except there was a big thing missing. In my game, I use a function called generate_piece to put all the mapgen logic in. It's a global function because I also want to be able to re-generate a piece of the map when I reset a level, and this of course happens after mapgen time. My game is built in a way that levels can be put in (almost) any part in the world and be removed again.
So this created a small problem: Now my mapgen code is stuck in the mapgen environment, so how do I allow levels to call generate_piece again?
I briefly considered doing something extreme: Using a macro system like m4 for the first time in my life.
But I found a better solution:
I simply run the same script twice! Once with dofile in the global environment, once with minetest.register_mapgen_script. And in the script, I modified the code by checking if the code runs either in the global, or the mapgen environment. How do I check it? Like this:
Code: Select all
local IS_IN_MAPGEN_ENVIRONMENT = not minetest.global_exists("lzr_mapgen")
The script now does two things:
1) In the mapgen environment, calls minetest.register_on_generated (but the "special" one)
2) In the global environemnt, expose generate_piece into the global namespace so it can be used by the levels mod to regenerate a piece.
Now the only thing left to do is to make the small code adjustments with a few if statements to change the behavior of generate_piece.
Whew!
This setup now works, and I'm happy. There is only one bad thing left: I was forced to copy a global variable lzr_globals.DEEP_OCEAN_Z into the script, which means the game now has two copies of the value, which is redundant and ugly. Since it's not possible to give any data to the mapgen environment (apparently), I'm afraid there's no workaround.
Thankfully, it's only one variable, and I added BIG warnings to both copies to prevent me to inconsistently change the value when future me decides to have a brainfart. ;-)
After I did all of this, the game indeed seems to startup much faster, the critical delay at the start is basically gone. Nice!
------------------
One final comment: It's annoying I cannot pass any data to the mapgen environment. Not even a single number. It seems I can do that for async environment, but I haven't found a parameter or function for the mapgen environment. :-(
So any global variables that change mapgen behavior but also communicate it to other mods are not possible unless you copy them by hand (UGLY).
So for the next version I wish that you could pass data to mapgen environments, similar to how you can do that already with async environments.