mt-mods / plantlife_modpack

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Server Crash

S-S-X opened this issue · comments

commented
ServerError: AsyncErr: Lua: Runtime error from mod '??' in callback environment_Step(): ...test/bin/../mods/plantlife_modpack/trunks/generating.lua:111: attempt to index a nil value
stack traceback:
...test/bin/../mods/plantlife_modpack/trunks/generating.lua:111: in function 'nodes_or_function_or_model'
/home/user/github/minetest/bin/../mods/biome_lib/api.lua:368: in function 'populate_surfaces'
/home/user/github/minetest/bin/../mods/biome_lib/api.lua:480: in function 'generate_block'
...ub/minetest/bin/../mods/biome_lib/block_queue_checks.lua:9: in function 'func'

Juri O debagos · 1 month ago Author
It happened again just a few moments ago. Any idea what's wrong?

-- Juri O debagos · 1 month ago Author

Relevant lines of code:

110		if not (minetest.registered_nodes[minetest.get_node({x=pos.x,y=pos.y,z=pos.z+1}).name].buildable_to
111			or minetest.registered_nodes[minetest.get_node({x=pos.x+1,y=pos.y,z=pos.z+1}).name].buildable_to) then

Do you have unknown nodes in your world? Because pos can't be nil, or it'd have errored on line 110. So it has to be the .buildable_to failing, because minetest.registered_nodes[minetest.get_node( ... )] returned nil. Most likely a removed mod left behind some nodes.

(EDIT: Scratch that, this code is running on newly-generated blocks so that doesn't make sense.)

This code can be made safer too, though. Will raise a PR to stop this crashing.

Another possibility is the log is being generated on a node-block that's next to a non-existent node-block, so x=pos.x+1 tried to fetch a node that doesn't exist? Could that happen?

commented

Do you have unknown nodes in your world?

Those were only comments on GitLab side... I guess would need to find OP for any additional information.
If it seems like there's no clear obvious reason for crash then I guess we could just close this issue and if someone manages to reproduce it they'll post it again...

commented

Another possibility is the log is being generated on a node-block that's next to a non-existent node-block, so x=pos.x+1 tried to fetch a node that doesn't exist? Could that happen?

minetest.get_node always returns node no matter what. For example

minetest.registered_nodes[minetest.get_node({x=9999999999,y=9999999999,z=9999999999}).name].whatever

is completely valid and should not crash (but it will return nil because ignore node does not have whatever key defined)
edit. if that causes error then it might be older engine that is still marked as compatible but might return nil.
or it has to be unknown node but like you said... that does not make sense?

I see. Well, this PR is probably overkill:
#9

I can only guess a different mod is creating nodes of an unknown type, but I'm not sure that's even allowed by minetest.

commented

If location pos.z+1 (or x+1 or z+1 x+1) can be in already existing previously generated block then there can be unknown node and name is not in minetest.registered_nodes. Should it be guaranteed that those positions are always on same mapblock? If not then your PR does make sense (unless it should only check same block)

Should it be guaranteed that those positions are always on same mapblock?

I've not looked at this code before, but I don't see why it should. It's just checking the area around the object being generated.

I think this could be an outdated crash, because there is a commit that seems to fix it: 9ed4771

That fix doesn't cover the line that the crash was reported on, so it seems this issue happened before and the fix wasn't complete.

commented

Should it be guaranteed that those positions are always on same mapblock?

I've not looked at this code before, but I don't see why it should. It's just checking the area around the object being generated.

If object you're talking about is generated on mapblock edge then:

  • there should either be additional check to skip this part
  • or if it should never operate on mapblock edges then there might be bug elsewhere
  • or your pr is correct way to solve this (and unknown nodes is not considered buildable_to)

There's multiple things to consider depending on what this code is actually doing and why it is doing it:

  • If it is changing things on already generated blocks then this should be avoided unless it is absolutely necessary.
  • If is is just checking neighbor mapblock when generating things on mapblock edges then unknown node check is correct.
  • If it should never work near mapblock edges then possible bug in code that is calling trunks/generating.lua stuff.

Also min/max coordinates for generator itself might need to be considered but again it depends... (last block for biome, absolute no-go areas for generator and similar stuff)

That fix doesn't cover the line that the crash was reported on, so it seems this issue happened before and the fix wasn't complete.

I think you're right, those variables should have been used on those lines too.

That fix doesn't cover the line that the crash was reported on, so it seems this issue happened before and the fix wasn't complete.

I think you're right, those variables should have been used on those lines too.

Those variables are for y+1, which is why we can't use those variables.

  • If it is changing things on already generated blocks then this should be avoided unless it is absolutely necessary.

Sorry not following, why is this?

commented
  • If it is changing things on already generated blocks then this should be avoided unless it is absolutely necessary.

Sorry not following, why is this?

Because changing existing things is source of many other problems, that's why it should be avoided unless it is necessary for desired outcome.
I'm not saying that it is wrong or bad to do that, just that it should be avoided if it is possible to avoid it without affecting actual outcome and it would be best to have additional check / some extra code to avoid it instead of saving LoC because it seems unnecessary / "works for me".

But, why is it different to generate part of the object on a previously generated node-block, than on the just-generated node-block? In both cases you're "changing existing things", unless I'm missing something.

commented

But, why is it different to generate part of the object on a previously generated node-block, than on the just-generated node-block? In both cases you're "changing existing things", unless I'm missing something.

When talking about mapgen you are generating new areas instead of changing existing areas, if your intention is to change existinng world instead of simply generating new areas that does not yet exist then it is all fine.

this code is running on newly-generated blocks so that doesn't make sense

Running in separate threads is one thing, changing existing surrounding areas when block is cleared is another thing, working with other mods that are supposed to change existing areas also affects actual outcome.
However basically in almost every possible imaginable situation no matter what you do it is always safest and simplest for compatibility to do minimal changes: only do what is necessary for desired outcome and nothing else.

Should anyway continue this discussion in some chat / mt forums / irc / discord because here it will just be derailing discussion about actual issue and might be completely irrelevant depending on what this generator actually handles and why.
It is simply thing to consider when deciding what to do and might be completely irrelevant here, not thing that absolutely should not or cannot be done.

Thing is I've no idea what is "desired outcome" here so I cannot really say if this is relevant or not, that's basically why this note had conditions. "unless it is absolutely necessary" means that if desired outcome can only be achieved through modifying existing mapblock when generating new mablocks then doing that is absolutely necessary, if there's way to achieve exact same results without modifying existing mapblocks then it is not necessary.

Ok I see. In this case, the desired outcome is to randomly generate twigs, branches and logs onto the terrain.

The objects it creates are multiple nodes in size horizontally, so it might place part of the object on the next node-block if the randomly chosen position is close enough to the edge. It only creates the object if the affected nodes the object will replace have the buildable_to flag.

It wouldn't be impossible to cancel the object creation if it passes over a node-block, it would simply reduce the number of objects it generates a bit.

Actually something about how biome_lib works might be important here.

Biome_lib doesn't actually do its changes during the register_on_generated callback, instead during the callback it adds the newly-generated mapblock to a queue.

There is a global step which processes this queue, and generates stuff on the mapblocks at this point. This means when you fly quickly to a new area, you'll see the terrain generate, followed by the stuff added by biome_lib.

I'm not sure why it was done this way, probably to avoid freezing the client by making it wait for the register_on_generated callback to finish.

EDIT: I think it's so generating objects in a block can be deferred if its neighbouring blocks don't appear to be loaded yet. Presumably specifically so it can more easily generate objects that cross block borders. For example with the mod moretrees which generates rather huge trees.

commented

I'm not sure why it was done this way, probably to avoid freezing the client by making it wait for the register_on_generated callback to finish.

register_on_generated executes under emerge thread and therefore should not be able to directly freeze client or server even if you'd stall it unless register_on_generated does things that add thread locks also used by main server thread.
Yeah, you heard that modding is single threaded but that's not completely true. It is multi threaded but manages locks for threads under the hood.

It would actually be good to track down underlying reason why it was done with globalstep queue (which can freeze main server thread) instead of in register_on_generated which runs under emerge thread. Possibly because doing stuff on already generated areas and locking main thread anyway through actual operations.

I edited my post literally seconds before you posted :) I figured it out.

Anyway, the linked PR will stop this crash although there's other places in the code that look like they need fixing too, I'll fix them and update the PR.