-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lua on each mapgen thread #13092
Lua on each mapgen thread #13092
Conversation
Oh wow this is awesome. This could make Spiraling Down playable again (currently mapgen takes avg. 200 ms per chunk; it is hard to optimize it further). It would be great if the mapgen didn't block the main thread. |
Thanks for investing your time and knowledge in such a complicated task @sfan5! |
b1ebf14
to
067fd4b
Compare
This might also make fractured faster - and perhaps fractured-style-layering more viable across other games. |
This PR needs to be rebased to work with the latest mtirrlicht |
It would be nice to have a way to send data/code to the lua environment. Perhaps that is possible with writing a lua script to the world directory and then calling it from the mapgen environment? My usecase is to adapt luamap to run on the separate thread, but the whole point of luamap is to let other mods register mapgens using luamap's simplified API (which means less control, but also less confusion for noob modders) So, I want to build my own API around the mapgen API. Currently that seems to be thwarted since globals are not available. Perhaps |
In your case I would require the other mod to call |
Ah, so, I set up the luamap functions in the mapgen environment under a lumap global, and then other mods will be able to see the luamap global. |
I just found out that minetest.get_perlin_map is not available in the environment, only PerlinNoiseMap |
apparently minetest.get_mapgen_setting_noiseparams is not available either, which would be good to include for consistency |
Apparently minetest.registered_biomes is missing |
mapgenmods.zip |
minetest.generate_decorations(vm) is missing, I'm not sure about generate_ores I can't convert theTermos's islands mapgen until that's fixed Concise list of things that I'm aware of that are missing in order of importance:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've now tested this with Spiraling Down. It required quite a few changes, but nothing that wasn't doable in an hour.
The effect is amazing. Finally the main thread is free to do actual game logic again.
One caveat: Lua mapgens like to use singlenode. This means that mapblocks not generated yet will temporarily be air until the Lua register_on_generated
has finished, which is problematic because the player probably has already dropped through a few blocks by then.
Other caveats: OOMing, lighting bugs, "couldn't grab block we just generated".
This is supposed to be impossible, the block doesn't leave the server until the callbacks are done.
reproducer please |
Here's a hackypatch.txt (Git patch) for https://github.com/spiraling-down/game latest master. Fly around quickly until the error appears on your screen. |
I've seen similar behavior before on single-threaded lua mapgen before. |
59a43fe
to
fd17164
Compare
I see there have been updates; its not entirely clear what effect they have. What's changed, and is it time to experiment with this again (have some of the above issues mentioned been fixed, so its time to test its limits again?) |
I added a bunch of APIs you were missing but I'll ping you if you can re-test. |
Well, first thing I notice is that minetest.get_perlin_map is still missing. Is that intentional? All get_perlin_map does is to wrap PerlinNoiseMap by adding the world seed to the seed of the noise. While you can do that in lua it makes sense to continue to offer that in the environment for consistency, imo
register_on_shutdown() is missing... which I discovered while trying to convert mapgen_rivers |
If you are interested, I made my own version of Mapgen Rivers (independently from MisterE) that allows to switch between standard and multithreaded modes: https://gitlab.com/gaelysam/mapgen_rivers/-/tree/mapgen_thread (set Concerning As well, the docs should explain that Anyway I would really like to see this merged, as this feature has been long-awaited and this seems to work well. Congratulations. |
I was thinking it discourages people from just copying code from the normal environment and expecting it to work.
I guess they could but I don't think it's any different to the old callback, is it? |
For the most part, I had a lot of success just copying (mapgen) code and getting it to work, although I did have to change it for the differences in the api. Its more valuable to have a consistent api than the "stop and think" effect obtained with a slightly different arguement order... |
IIRC, you have to call write_to_map manually in regular/synchronous on_generated callbacks. https://github.com/minetest/minetest/pull/13092/files#r1278370082 It would of course be nice to get rid of this inconsistency between on_generated on the main thread and on_generated on mapgen threads. |
You're right. Updated the docs to be clearer about this. |
Co-authored-by: SmallJoker <[email protected]>
…inux, is in fact, GNU/Linux, or as I've recently taken to calling it, GNU plus Linux. Linux is not an operating system unto itself, but rather another free component of a fully functioning GNU system made useful by the GNU corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX. Many computer users run a modified version of the GNU system every day, without realizing it. Through a peculiar turn of events, the version of GNU which is widely used today is often called Linux, and many of its users are not aware that it is basically the GNU system, developed by the GNU Project. There really is a Linux, and these people are using it, but it is just a part of the system they use. Linux is the kernel: the program in the system that allocates the machine's resources to the other programs that you run. The kernel is an essential part of an operating system, but useless by itself; it can only function in the context of a complete operating system. Linux is normally used in combination with the GNU operating system: the whole system is basically GNU with Linux added, or GNU/Linux. All the so-called Linux distributions are really distributions of GNU/Linux!
... is this ready? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
☑️ Gen notify positions are saved and retrieved correctly
☑️ Both, VManip and core.set_node
do work in the main thread (add onto the terrain generated by the mapgen script)
☑️ The functions provided in the example work. That's already a large part what's needed for Lua mapgen development.
What I don't like:
- Code duplication. To be addressed later. This could be worked around by using helper functions that are used by the VManip and regular API using (less efficient) lambdas/callbacks.
- The Lua callback execution order is yet not documented. What if other mods register mapgen scripts? Will all mapgen scripts be executed in order of registration, then the main thread in order of registration? --> see comment
I did some more editing on the docs to make them hopefully clearer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the improvements. There's also an attempt to make the documentation easier to comprehend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the changes. Looks good. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a little nitpicking on the documentation... I don't think these comments are particularly important, I just want the documentation to be as good as (easily) possible.
* Saves data for retrieval using the gennotify mechanism (see [Mapgen objects]). | ||
* Data is bound to the chunk that is currently being processed, so this function | ||
only makes sense inside the `on_generated` callback. | ||
* `id`: user-defined ID (a string) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
newline not rendered
"user-defined ID (a string) By convention these ..."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't remember how to fix that, so I'll leave it 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
two trailing spaces result in a <br>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I'm too late.
(Just skimmed the PR.)
|
||
function core.get_node_or_nil(pos) | ||
local node = core.vmanip:get_node_at(pos) | ||
return node.name ~= "ignore" and node |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return node.name ~= "ignore" and node | |
return node.name ~= "ignore" and node or nil |
CHECK_SECURE_PATH(L, path.c_str(), false); | ||
|
||
// Find currently running mod name (only at init time) | ||
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mod name is used for check for insecure environment, if I understand correctly.
But this means that if a trusted mod A calls a function from another mod B, B can in this function register their own script under the name of A, and can hence request insec env.
Fixes #3182
this adds a separated lua environment on each emerge thread, for obvious reasons mods will have to be adjusted to take advantage of this
Merging
squash everything, don't keep the commit messages
To do
This PR is Ready For Review.
access to node meta ← feasible?postponedcore.registered_*
into mapgen envHow to test
The easiest (but not intended) way is to edit
builtin/emerge/init.lua
and add code there.This will place a mese node in the middle of each generated map chunk all without blocking the main thread (wow!).
You can find a complete example that showcases the intended way here →→ https://gist.github.com/sfan5/1a124eb496a39734f53fb4daffc47bee
Another fun thing you can do is this:
For some reason it confuses our mapgens to a great deal and they never stop generating surface.