为什么一个能工作而另一个却崩溃?
这件事让我感到疯狂,已经持续了一个星期。以下是来自游戏Bitfighter的机器人玩家中的两个 Lua 代码片段(使用 LuaWrapper 变体进行绑定,使用 C++ 编写)。
当我开始运行 Lua 脚本时,两者都像预期一样正常工作。但是,在经过一段时间的强烈的对象创建和销毁后,变体 2 停止工作,并给出以下错误:
robot.lua:253: attempt to call missing or unknown method 'getEnergy' (a nil value)
在我看来,这些应该有相同的功能。谁能解释其中的区别呢?
注:target 是代表 C++ 对象的(重型)userdata。 getEnergy 和 getHealth 是已正确注册的 C++ 函数。我可以轻松地重现这种不同的行为。这是 Lua 5.1,使用的是 luavec 模块。
变体 1 - 总是有效的
local mt = getmetatable(target)
local pow = mt.getEnergy(target) + mt.getHealth(target)
变体 2 - 在脚本运行了任意数量的时间后开始失效
local pow = target:getEnergy() + target:getHealth()
当你说它在某个阶段停止工作,但之前正常工作...它可能是因为在运行时你在任何地方覆盖了.getEnergy函数吗?
也许你在某个地方运行了foo.getEnergy = nil而不是foo.getEnergy == nil?听起来可能是一个晚初始化出了问题 :)
我强烈怀疑问题出在你有一个类或者 struct 很像这样子:
struct Foo
{
Bar bar;
// Other fields follow
}
并且你通过 LuaWrapper 把 Foo 和 Bar 都暴露到 Lua 中去了。重要的是,bar 是你的 Foo struct 的第一个字段。 另外,你也可能有一个继承于一些基础类的类,并且这个派生类和基础类都被暴露到了 LuaWrapper 中。
LuaWrapper 使用一个称为 Identifier 的函数来唯一地追踪每个对象(比如说确定该对象是否已经被添加到了 Lua 状态中)。 默认情况下,它使用对象地址作为关键字。在上面提到的情况下,可能 Foo 和 Bar 都有相同的内存地址,因此 LuaWrapper 可能会困惑。
这可能导致当尝试查找方法时,获取错误对象的元表。显然,因为它查找的是错误元表,所以它找不到你希望的方法,因此会出现元表神秘地丢失了条目的情况。
我在更改中添加了一些代码,使其根据类型追踪每个对象的数据,而不是在一个巨大的堆栈中跟踪它们。如果你将 LuaWrapper 更新到存储库中最新的版本,我相信你的问题将会得到解决。
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
为了跟踪当它停止工作时发生了什么,您可以将调用包装在
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