minetest_modding_book/_it/quality/common_mistakes.md

4.5 KiB

title layout root idx redirect_from
Errori comuni default ../.. 8.1 /it/chapters/common_mistakes.html

Introduzione

Questo capitolo illustra gli errori più comuni e come evitarli.

Non salvare mai ObjectRef (giocatori ed entità)

Se l'oggetto rappresentato da un ObjectRef viene rimosso - per esempio quando il giocatore si disconnette o un'entità viene rimossa dalla memoria - chiamare metodi su quell'oggetto causerà la chiusura improvvisa del server (crash).

Sbagliato:

minetest.register_on_joinplayer(function(player)
    local function func()
        local pos = player:get_pos() -- MALE!
        -- `player` viene salvato per essere utilizzato dopo.
        -- Se il giocatore si disconnette, il server crasha
    end

    minetest.after(1, func)

    foobar[player:get_player_name()] = player
    -- RISCHIOSO
    -- Non è consigliato fare così.
    -- Usa invece minetest.get_connected_players() e minetest.get_player_by_name().
end)

Giusto:

minetest.register_on_joinplayer(function(player)
    local function func(name)
        -- Tenta di ottenere il riferimento
        local player = minetest.get_player_by_name(name)

        -- Controlla che il giocatore sia online
        if player then
            -- è online, procedo
            local pos = player:get_pos()
        end
    end

    -- Passa il nome nella funzione
    minetest.after(1, func, player:get_player_name())
end)

Non fidarti dei campi dei formspec

Client malevoli possono compilare i campi nei formspec quando vogliono, con qualsiasi contenuto vogliono.

Per esempio, il seguente codice presenta una vulnerabilità che permette ai giocatori di assegnarsi da soli il privilegio di moderatore:

local function show_formspec(name)
    if not minetest.check_player_privs(name, { privs = true }) then
        return false
    end

    minetest.show_formspec(name, "modman:modman", [[
        size[3,2]
        field[0,0;3,1;target;Nome;]
        button_exit[0,1;3,1;sub;Promuovi]
    ]])
    return true
})

minetest.register_on_player_receive_fields(function(player,
        formname, fields)
    -- MALE! Manca il controllo dei privilegi!

    local privs = minetest.get_player_privs(fields.target)
    privs.kick  = true
    privs.ban   = true
    minetest.set_player_privs(fields.target, privs)
    return true
end)

Aggiungi un controllo dei privilegi per ovviare:

minetest.register_on_player_receive_fields(function(player,
        formname, fields)
    if not minetest.check_player_privs(name, { privs = true }) then
        return false
    end

    -- code
end)

Imposta gli ItemStack dopo averli modificati

Se ci si fa caso, nella documentazione si parla di ItemStack e non ItemStackRef. Questo perché gli ItemStack NON sono un riferimento, bensì una copia. Questo vuol dire che modificando la copia, non si modificherà in automatico anche l'originale.

Sbagliato:

local inv = player:get_inventory()
local pila = inv:get_stack("main", 1)  -- lo copio
pila:get_meta():set_string("description", "Un po' smangiucchiato")
-- MALE! Le modifiche saranno perse

Giusto:

local inv = player:get_inventory()
local pila = inv:get_stack("main", 1)  -- lo copio
pila:get_meta():set_string("description", "Un po' smangiucchiato")
inv:set_stack("main", 1, pila)
-- Corretto! L'ItemStack è stato cambiato con la copia

Il comportamento dei callback è leggermente più complicato.

minetest.register_on_item_eat(function(hp_change, replace_with_item,
        itemstack, user, pointed_thing)
    itemstack:get_meta():set_string("description", "Un po' smangiucchiato")
    -- Quasi corretto! I dati saranno persi se un altro callback annulla questa chiamata
end)

Se nessun callback cancella l'operazione, la pila sarà impostata e la descrizione aggiornata; ma se un callback effettivamente cancella l'operazione, l'aggiornamento potrebbe andar perduto.

È meglio quindi fare così:

minetest.register_on_item_eat(function(hp_change, replace_with_item,
        itemstack, user, pointed_thing)
    itemstack:get_meta():set_string("description", "Un po' smangiucchiato")
    user:get_inventory():set_stack("main", user:get_wield_index(),
            itemstack)
    -- Corretto! La descrizione verrà sempre aggiornata
end)