Estamos utilizando el motor de juego Love2d Lua que expone una aplicación gráfica a Lua. Estamos tratando de serializar una tabla hash gigante que contiene todos los datos guardados del juego para el mundo del juego. Este hash incluye algunas funciones, y algunas de estas funciones llaman a Love2d C funciones.¿Es posible llamar a la cadena de carga en la cadena de códigos de bytes lua que contiene una referencia a una función C?
Para serializar las funciones en el hash, usamos string.dump, y lo volvemos a cargar con loadstring. Esto funciona bien para funciones Lua puras, pero cuando tratamos de serializar y luego cargar de nuevo en una función que llama a una función envolvente C como una en la API Love2d, la cadena de carga devuelve nil.
Considere el siguiente programa simple que dibuja "hola, mundo" a la pantalla a través de un motor gráfico de Love2d:
function love.load()
draw = function()
love.graphics.print('hello, world', 10, 10)
end
end
function love.draw()
draw()
end
Nos gustaría ser capaz de hacer esto:
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
Hacer esto escribe en un archivo Lua en el disco que contiene una mezcla de bytecode Lua y Lua no compilados, que se parece a esto:
draw = load([[^[LJ^A^@
@main.lua2^@^@^B^@^B^@^D^E^B^B4^@^@^@%^A^A^@>^@^B^AG^@^A^@^Qhello, world
print^A^A^A^B^@^@]])
Este método funciona bien con las funciones Lua que no llaman a los módulos C. Creemos que este es el problema, ya que este ejemplo funciona:
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
lugar de llamar al método de gráficos Love2d, se hace una impresión en la consola.
Después de más pruebas, que estaban confundidos al ver que este ejemplo funciona:
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
Aquí en realidad no escribimos la función en el disco, y en su lugar sólo lo descarga e inmediatamente después cargamos de nuevo . Pensamos que quizás el culpable no estaba escribiendo los datos con el indicador de modo de escritura binaria establecido ("wb"
), pero como estamos en Linux, esta bandera no tiene ningún efecto.
¿Alguna idea?
"imprime en la consola" ¿qué imprime? Además, ¿está seguro de que el entorno global utilizado por el código anterior es el mismo que el utilizado por 'require'? [ya que depende de que 'draw' se defina en el entorno global] – snogglethorpe
Debe avisar que esto: '[['.. string.dump (draw_before_serialize) ..']]' no necesariamente va a funcionar. El volcado que reciba podría contener * cualquier cosa *, incluidos los caracteres ']]'. Eso terminaría la cadena temprano, rompiendo así las cosas. –
@NicolBolas Una vez vi una solución fácil pero inteligente para eso que acaba de comprobar la cadena para '] (= *)]' y luego enmarcar el volcado con una '=' más que el número máximo de '=' que se encuentra con el partido. – jpjacobs