Uberi / Minetest-WorldEdit

The ultimate in-game world editing tool for Minetest! Tons of functionality to help with building, fixing, and more.
https://forum.minetest.net/viewtopic.php?f=11&t=572
GNU Affero General Public License v3.0
160 stars 81 forks source link

crash when loading a save with unregistered nodes #210

Closed fluxionary closed 5 months ago

fluxionary commented 2 years ago
  1. create a //save on one server
  2. use another server which is missing at least one of the nodes that was saved, and try to //load

result:

AsyncErr: Lua: Runtime error from mod 'default' in callback on_chat_message(): "default:micro_goldblock_1" is not a registered node!
stack traceback:
    [C]: in function 'add_node'
    ...lux/.minetest/mods/worldedit/worldedit/serialization.lua:251: in function 'deserialize'
    ...lux/.minetest/mods/worldedit/worldedit_commands/init.lua:1505: in function 'func'
    ...lux/.minetest/mods/worldedit/worldedit_commands/init.lua:55: in function 'func'
    /usr/share/minetest/builtin/profiler/instrumentation.lua:107: in function 'func'
    /usr/share/minetest/builtin/game/chat.lua:79: in function </usr/share/minetest/builtin/game/chat.lua:52>
    /usr/share/minetest/builtin/game/register.lua:429: in function </usr/share/minetest/builtin/game/register.lua:415>

a possible fix would be to do a check to make sure all the nodes are registered before modifying the world, though that would slow down an already slow process.

loosewheel commented 2 years ago

I edited the the worldedit.deserialize function in worldedit/serialization.lua and it seemed to work. It maintains a table of already checked nodes and only tests minetest.registered_nodes if not in the shorter table. I don't know how much more expedient this is in real terms.

function worldedit.deserialize(origin_pos, value)
    local nodes = load_schematic(value)
    if not nodes then return nil end
    if #nodes == 0 then return #nodes end

    local pos1, pos2 = worldedit.allocate_with_nodes(origin_pos, nodes)
    worldedit.keep_loaded(pos1, pos2)

    local origin_x, origin_y, origin_z = origin_pos.x, origin_pos.y, origin_pos.z
    local count = 0
    local add_node, get_meta = minetest.add_node, minetest.get_meta
    local node_check = { }
    for i, entry in ipairs(nodes) do
        entry.x, entry.y, entry.z = origin_x + entry.x, origin_y + entry.y, origin_z + entry.z
        local checked = node_check[entry.name]

        if not checked then
            if minetest.registered_nodes[entry.name] then
                node_check[entry.name] = true
                checked = true
            end
        end

        if checked then
            -- Entry acts as both position and node
            add_node(entry, entry)
            if entry.meta then
                get_meta(entry):from_table(entry.meta)
            end
        else
            print (string.format ("WorldEdit unknown node \"%s\"", entry.name or ""))
        end
    end
    return #nodes
end