4

这已经让我发疯了一个多星期。下面是来自游戏Bitfighter中机器人玩家的两个 Lua 代码片段(用 C++ 编写,使用 LuaWrapper 的变体进行绑定)。

当我第一次启动 Lua 脚本时,两者都按预期工作。但是经过几分钟的强烈对象创建和破坏,变体 2 停止工作,并给我以下错误:

robot.lua:253: attempt to call missing or unknown method 'getEnergy' (a nil value)

在我看来,这些功能应该相同。谁能解释一下区别?

注意:目标是表示 C++ 对象的(重)用户数据。getEnergy 和 getHealth 是正确注册的 C++ 函数。我可以轻松地重现这种不同的行为。这是 Lua 5.1,使用 luavec mod。

变体 1 - 始终有效

local mt = getmetatable(target)
local pow = mt.getEnergy(target) + mt.getHealth(target)

变体 2 - 在脚本运行任意时间后开始失败

 local pow = target:getEnergy() + target:getHealth()
4

3 回答 3

5

要跟踪它停止工作时会发生什么,您可以将调用包装起来pcall并探索值发生了什么target

local ok, res = pcall(function() return target:getEnergy() + target:getHealth() end)
if not ok then
  local s = "Invalid target value: "..tostring(target).." "..type(target).."\n"
  for k, v in pairs(target) do s = s.."target "..tostring(k).." "..tostring(v).."\n" end
  for k, v in pairs(getmetatable(target)) do s = s.."meta "..tostring(k).." "..tostring(v).."\n" end
  -- add anything else that helps you figure out what happened to target
  error(res..s)
end
local pow = res
于 2013-02-01T23:26:26.733 回答
1

我强烈怀疑问题是你有一个类似于这个的类或结构:

struct Foo
{
    Bar bar;
    // Other fields follow
}

你已经通过 LuaWrapper 将 Foo 和 Bar 暴露给 Lua。这里重要的一点是,它是结构bar上的第一个字段Foo。或者,您可能有一些从其他基类继承的类,并且派生类和基类都暴露给 LuaWrapper。

LuaWrapper 使用一个名为 Identifier 的函数来唯一地跟踪每个对象(例如给定对象是否已经添加到 Lua 状态)。默认情况下,它使用对象地址作为键。在上述情况下,Foo 和 Bar 可能在内存中具有相同的地址,因此 LuaWrapper 可能会感到困惑。

这可能会导致在尝试查找方法时抓取错误对象的元表。显然,由于它正在查看错误的元表,它不会找到您想要的方法,因此看起来好像您的元表神秘地丢失了条目。

我检查了一项更改,该更改跟踪每个对象的每种类型的数据,而不是一大堆。如果您将您的 LuaWrapper 副本更新到存储库中的最新版本,我相当肯定您的问题将得到解决。

于 2013-02-23T03:48:07.637 回答
0

当你说它在某个阶段停止工作,但之前工作正常......难道你在运行时的任何地方覆盖了 .getEnergy 函数?也许您正在运行 afoo.getEnergy = nil而不是foo.getEnergy == nil某个地方?听起来可能是后期初始化出错了:)

于 2013-02-02T19:03:17.903 回答