minetest / minetest

Minetest is an open source voxel game-creation platform with easy modding and game creation

Home Page:https://www.minetest.net/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unknown nodes (sometimes) show with no_texture.png instead of unknown_node.png

sfan5 opened this issue · comments

commented
Minetest version

5.6.0-devs
only happens in multiplayer, not singleplayer

Summary

Unknown nodes in the world no longer show with the texture they're supposed to have but instead have the "no texture" fallback texture

commented

I haven't been able to reliably reproduce this bug but I don't remember seeing it before 5.5.
Someone else noticed it too https://irc.minetest.net/minetest-dev/2022-04-27#i_5966663

commented

It was definitely introduced in 5.5.0, the same version which introduced #11429. Can confirm.

Sadly, I don’t know either what causes this, and it also only happens unpredictably under unknown conditions.

If we can’t figure out what causes this, do the nuclear option by reverting #11429 (and thus losing no_texture.png). :-(

commented

If I would have to make a guess in the blue, it could have somthing to do with the order in which mods loaded, so it might depend on the mod name. This theory was NOT tested.

Can confirm the no_texture.png on servers instead of the unknown node texture.

commented

I think I have it figured out but it needs a bit of explanation:
When loading a block from disk and encountering an unknown node the server allocates a dummy ID with empty ContentFeatures entry (via correctBlockNodeIds):

minetest/src/nodedef.cpp

Lines 1405 to 1411 in e0e8978

content_t NodeDefManager::allocateDummy(const std::string &name)
{
assert(name != ""); // Pre-condition
ContentFeatures f;
f.name = name;
return set(name, f);
}

This is not the issue, these are never sent to the client. The client just works with the IDs it is given.
Like any other ID the client will attempt to look it up in its table and fall back to the definition for CONTENT_IGNORE (which contains unknown_node.png) if it's past the end of the array:

minetest/src/nodedef.h

Lines 540 to 544 in e0e8978

inline const ContentFeatures& get(content_t c) const {
return
c < m_content_features.size() ?
m_content_features[c] : m_content_features[CONTENT_UNKNOWN];
}

But wait, how big is that array? It is initially created with a size of 128:

minetest/src/nodedef.cpp

Lines 1084 to 1088 in e0e8978

u32 initial_length = 0;
initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
m_content_features.resize(initial_length);

So the conditions for no_texture.png to appear are whether the ID of the unknown node is smaller than 126.

Why this does not happen in singleplayer, only sporadically and in game sessions with clearly more than 126 nodes (therefore all earlier IDs should be filled) is still unknown.

commented

Why this does not happen in singleplayer, only sporadically and in game sessions with clearly more than 126 nodes (therefore all earlier IDs should be filled) is still unknown.

I think I know the answer to that. I created a minimalist test game with only one mod (minimod) to register 256 nodes and a command /place_nodes to place these nodes at (0,0,0). If you do that, and then set NODES_COUNT to 0 in the code below, and then load the world again, you consistently get the same number of nodes that use the correct unknown_node.png texture (128+3 out of 256) and the same number of nodes with the wrong no_texture.png texture (128-3 out of 256). What changes is which nodes are affected, it probably has something do to with at which position in the world I spawned.

I also noticed that when you point a no_texture.png node, the F5 debug shows "pointed: " with no nodename. Seems like the empty string. The nodes with the correct unknown_node.png texture correctly show pointed: <unknown node>.

The code also prints the content IDs to the errorlog.

Here is the code of the minimod:

local NODES_COUNT = 256

for i=0,NODES_COUNT-1 do
	minetest.register_node("minimod:badnode"..string.format("%03d", i), {
		tiles = { "default_stone.png" },
		groups = { dig_immediate = 3 },
	})
end

minetest.register_on_mods_loaded(function()
	-- Print list of content IDs
	local nodelist = {}
	for node, _ in pairs(minetest.registered_nodes) do
		table.insert(nodelist, node)
	end
	table.sort(nodelist)
	for i=1, #nodelist do
		local node = nodelist[i]
		local id = minetest.get_content_id(node)
		minetest.log("error", id..": "..node)
	end
end)


minetest.register_chatcommand("place_nodes", {
	privs = {server=true},
	func = function(name, param)
		local pos = vector.zero()
		local row = 0
		for i=0,NODES_COUNT-1 do
			minetest.set_node(pos, {name="minimod:badnode"..string.format("%03d", i)})
			pos.x = pos.x + 2
			row = row + 1
			if row >= 16 then
				row = 0
				pos.x = 0
				pos.z = pos.z + 2
			end
		end
		return true
	end,
})
commented

So the reason why this happens only sporadically is probably because of the way how content IDs are created on the fly, depending on which node is first "seen" by the server. The content IDs can change at every load. So it depends a lot on where players spawned into the world. If the map is loaded in such a way that all the first 125 node types "seen" by the server are known nodes, this issue does not occur.

So this is less likely to happen when there is only 1 unknown node in the entire game with hundreds of nodes but it is 100% likely to happen if there are less than 125 node types in the game. I also repeated the test code above with NODES_COUNT=64 and then every node had no_texture.png. This is consistent with sfan5's analysis.