背景

我与Watusimoto合作开发了Bitfighter游戏。我们使用LuaWrapper的变体将c++对象与游戏中的Lua对象连接起来。我们还使用Lua的一种变体lua-vec来加快 vector 运算的速度。

我们一直在努力解决一个我们难以捉摸的错误。将会发生随机崩溃,提示损坏的元表。有关此问题的Watusimoto的帖子,请参见here。我不确定这是因为损坏了的元表,并且看到了一些我想在此询问的非常奇怪的行为。

问题表现

例如,我们创建一个对象并将其添加到这样的级别:

t = TextItem.new()
t:setText("hello")
levelgen:addItem(t)

但是,游戏有时(并非总是)崩溃。出现错误:
attempt to call missing or unknown method 'addItem' (a nil value)

使用对上述Watusimoto帖子的回答给出的建议,我将最后一行更改为以下内容:
local ok, res = pcall(function() levelgen:addItem(t) end)

if not ok then
    local s = "Invalid levelgen value: "..tostring(levelgen).." "..type(levelgen).."\n"

    for k, v in pairs(getmetatable(levelgen)) do
        s = s.."meta "..tostring(k).." "..tostring(v).."\n"
    end

    error(res..s)
end

如果错误地从levelgen调用方法,这会打印出addItem的元表。

但是,这很疯狂,当它失败并打印出该元表时,该元表就是它应该的样子(使用正确的levelgen调用以及所有内容)。如果我在脚本加载时打印pcall的元表,并且使用上面的levelgen失败时,它们是相同的,则指向userdata的每个调用和指针都是相同的,也应该相同。

好像levelgen的元表是自发地随机消失的。

有人知道发生了什么吗?

谢谢

注意:TestItem对象不会发生这种情况。例如,它也发生在上面提到的levelgen:addItem(t)对象上。实际上,该代码在我的计算机上的t:setText("hello")行崩溃,但在另一开发人员的计算机上的missing or unknown method 'setText' (a nil value)行崩溃,并带有相同的错误消息ojit_code

最佳答案

与任何谜一样,您需要将其逐层剥离。我建议执行与Lua相同的步骤,并尝试检测所走的路径与您的期望有何不同:
getmetatable(levelgen).__index返回什么?如果是表,请检查其内容是否为addItem。如果它是一个函数,请尝试使用(table, "addItem")调用它并查看它返回什么。

检查getmetatable在调用之前或之后(或失败时)是否返回对同一对象的引用。

调用正在经历多个级别的元表间接访问吗?如果是这样,请尝试通过显式调用遵循相同的路径,并查看差异在哪里。

您是否正在使用weak键,如果没有其他引用,这些键可能会导致值消失?

当您检测到失败时是否可以提供一个“默认”值,并在以后继续查看它是否再次“找到”该方法?还是当它断开时,此后的每个调用都断开了?

如果您为addItem保存适当的值并在检测到损坏的情况下“修复”该怎么办?

如果您只是简单地处理错误并执行10次该怎么办?它会至少显示一次有效的结果(失败后)吗? 100倍?如果您在工作时仍调用相同的方法,它将失败吗?这可以帮助您提出更可重现的错误。

我不熟悉LuaWrapper来提供更具体的问题,但是如果我是您,这些就是我要采取的步骤。

10-08 07:41