我们正在使用向 Lua 公开图形 API 的 Love2d Lua 游戏引擎。我们正在尝试序列化一个包含游戏世界所有保存游戏数据的巨型哈希表。这个散列包括一些函数,其中一些函数调用 Love2d C 函数。
为了序列化散列中的函数,我们使用 string.dump,并使用 loadstring 将它们重新加载。这适用于纯 Lua 函数,但是当我们尝试序列化然后加载回调用包装 C 函数的函数(例如 Love2d api 中的函数)时,loadstring 返回 nil。
考虑以下通过 Love2d 的图形引擎在屏幕上绘制“hello, world”的简单程序:
function love.load()
draw = function()
love.graphics.print('hello, world', 10, 10)
end
end
function love.draw()
draw()
end
我们希望能够做到这一点:
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
这样做会写入磁盘上的 Lua 文件,该文件包含未编译的 Lua 和 Lua 字节码的混合,如下所示:
draw = load([[^[LJ^A^@
@main.lua2^@^@^B^@^B^@^D^E^B^B4^@^@^@%^A^A^@>^@^B^AG^@^A^@^Qhello, world
print^A^A^A^B^@^@]])
此方法适用于不调用 C 模块的 Lua 函数。我们认为这是问题所在,因为此示例确实有效:
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
它不调用 Love2d 图形方法,而是打印到控制台。
经过更多的测试,我们困惑地发现这个例子确实有效:
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
在这里,我们实际上并没有将函数写到磁盘上,而是直接转储它,然后立即将其加载回来。"wb"
我们认为罪魁祸首可能是没有设置二进制写入模式标志(
有任何想法吗?