Stiamo usando il motore di gioco Love2d Lua che espone una grafica a Lua. Stiamo cercando di serializzare una tabella hash gigante che contiene tutti i dati di salvataggio del gioco per il mondo di gioco. Questo hash include alcune funzioni e alcune di queste funzioni chiamano le funzioni di Love2d C.È possibile chiamare loadstring su una stringa di bytecode lua che contiene un riferimento a una funzione C?
Per serializzare le funzioni nell'hash, si utilizza string.dump e si caricano di nuovo con loadstring. Funziona bene per le funzioni Lua pure, ma quando proviamo a serializzare e quindi a caricare di nuovo una funzione che chiama una funzione C avvolta come quella nell'Api di Love2d, loadstring restituisce nil.
Si consideri il seguente programma semplice che disegna "ciao, mondo" alla schermata di via motore grafico di Love2d:
function love.load()
draw = function()
love.graphics.print('hello, world', 10, 10)
end
end
function love.draw()
draw()
end
Vorremmo essere in grado di fare questo:
function love.load()
draw_before_serialize = function()
love.graphics.print('hello, world', 10, 10)
end
out = io.open("serialized.lua", "wb")
out:write('draw = load([[' .. string.dump(draw_before_serialize) .. ']])')
out:close()
require "serialized"
end
function love.draw()
draw()
end
Facendo questo scrive su un file Lua su disco che contiene un mix di codice bytec Lua e Lua non compilato, che assomiglia a questo:
draw = load([[^[LJ^A^@
@main.lua2^@^@^B^@^B^@^D^E^B^B4^@^@^@%^A^A^@>^@^B^AG^@^A^@^Qhello, world
print^A^A^A^B^@^@]])
Questo metodo funziona perfettamente con le funzioni Lua che non chiamano i moduli C. Noi pensiamo che questo è il problema, perché questo esempio funziona:
function love.load()
draw_before_serialize = function()
print('hello, world')
end
out = io.open("serialized.lua", "wb")
out:write('draw = load([[' .. string.dump(draw_before_serialize) .. ']])')
out:close()
require "serialized"
end
function love.draw()
draw()
end
Invece di chiamare il metodo grafico Love2d, lo fa una stampa alla console.
Dopo ulteriori test, siamo stati confusi per scoprire che questo esempio funziona:
function love.load()
draw_before_serialize = function()
love.graphics.print('hello, world', 10, 10)
end
draw = load(string.dump(draw_before_serialize))
end
function love.draw()
draw()
end
Qui in realtà non scriviamo la funzione sul disco, e invece solo discarica e poi subito a caricare di nuovo . Abbiamo pensato che forse il colpevole non stava scrivendo i dati con il set di flag in modalità scrittura binaria ("wb"
), ma dato che siamo su Linux questo flag non ha alcun effetto.
Qualche idea?
"fa una stampa alla console" cosa stampa? Inoltre, sei sicuro che l'ambiente globale utilizzato dal codice precedente sia lo stesso dell'ambiente globale utilizzato da 'require'? [dato che dipendi dal fatto che 'draw' sia definito nell'ambiente globale] – snogglethorpe
Dovresti essere avvisato che:' [['.. string.dump (draw_before_serialize) ..']] 'non funzionerà necessariamente. Il dump che ottieni potrebbe contenere * qualsiasi cosa *, inclusi i caratteri ']]'. Ciò finirebbe presto la stringa, rompendo così le cose. –
@NicolBolas Una volta ho visto una soluzione semplice ma intelligente per quello che ha appena controllato la stringa per '] (= *)]' e poi ho incorniciato il dump con uno '=' più del numero massimo di '=' 'trovato con la partita. – jpjacobs