Lua接口/函数不存在:修订间差异

来自天龙知识库
跳到导航跳到搜索
雪舞​(留言 | 贡献)
维护服务端 Lua 接口:核对参数、返回值、边界条件与调用示例
 
Waylee​(留言 | 贡献)
维护服务端 Lua 接口:核对参数、返回值、边界条件与调用示例
 
第1行: 第1行:
__NOTOC__
__NOTOC__
<div class="lua-reference" style="max-width:1200px;margin:0 auto;line-height:1.8;color:#29343a;font-family:Arial,'Microsoft YaHei',sans-serif;letter-spacing:0;overflow-wrap:anywhere;">
<div class="lua-reference">
[[首页|首页]] · [[Lua接口/服务端函数索引|服务端接口]] · [[Lua接口/服务端调用约定|调用约定]]
[[首页|首页]] · [[Lua接口/服务端函数索引|服务端接口]] · [[Lua接口/服务端调用约定|调用约定]]


第6行: 第6行:


== 先区分三种情况 ==
== 先区分三种情况 ==
{| class="wikitable" style="width:100%;table-layout:fixed;border-collapse:collapse;font-size:13px;"
{| class="wikitable"
! scope="col" style="text-align:left;background:#edf3f2;padding:8px;" | 现象
! scope="col" | 现象
! scope="col" style="text-align:left;background:#edf3f2;padding:8px;" | 含义与排查方向
! scope="col" | 含义与排查方向
|-
|-
| style="padding:8px;vertical-align:top;overflow-wrap:anywhere;" | <code style="white-space:normal;overflow-wrap:anywhere;">attempt to call ... (a nil value)</code>
| <code>attempt to call ... (a nil value)</code>
| style="padding:8px;vertical-align:top;overflow-wrap:anywhere;" | 执行到调用位置时,该名称的值是 nil;检查拼写、运行环境、脚本加载和同名变量。参数顺序错误通常不是这条报错的直接原因。
| 执行到调用位置时,该名称的值是 nil;检查拼写、运行环境、脚本加载和同名变量。参数顺序错误通常不是这条报错的直接原因。
|-
|-
| style="padding:8px;vertical-align:top;overflow-wrap:anywhere;" | <code style="white-space:normal;overflow-wrap:anywhere;">attempt to index ... (a nil value)</code>
| <code>attempt to index ... (a nil value)</code>
| style="padding:8px;vertical-align:top;overflow-wrap:anywhere;" | 点号或下标前的对象是 nil;先检查访问的 table 或上一步返回值。把 table 不存在误判为原生函数未注册,会查错方向。
| 点号或下标前的对象是 nil;先检查访问的 table 或上一步返回值。把 table 不存在误判为原生函数未注册,会查错方向。
|-
|-
| style="padding:8px;vertical-align:top;overflow-wrap:anywhere;" | 调用完成,接收变量为 <code style="white-space:normal;overflow-wrap:anywhere;">nil</code>
| 调用完成,接收变量为 <code>nil</code>
| style="padding:8px;vertical-align:top;overflow-wrap:anywhere;" | 可能是接口无返回值、失败分支少返回几项,或者脚本封装漏写 return;此时函数本身可以存在。
| 可能是接口无返回值、失败分支少返回几项,或者脚本封装漏写 return;此时函数本身可以存在。
|}
|}
错误文本可能随 Lua 运行环境不同而变化,以实际错误行和被指出的变量为准。
错误文本可能随 Lua 运行环境不同而变化,以实际错误行和被指出的变量为准。


== 检查调用名称是否是函数 ==
== 检查调用名称是否是函数 ==
<pre style="white-space:pre-wrap;overflow-wrap:anywhere;font-size:13px;line-height:1.7;padding:12px;background:#f5f7f8;border:1px solid #dbe3e6;">local entryType = type(GetLevel)
<pre>local entryType = type(GetLevel)
if entryType ~= "function" then
if entryType ~= "function" then
     -- 查看 entryType,并检查当前作用域和运行环境
     -- 查看 entryType,并检查当前作用域和运行环境
第42行: 第42行:


== 有函数但没有返回值 ==
== 有函数但没有返回值 ==
<pre style="white-space:pre-wrap;overflow-wrap:anywhere;font-size:13px;line-height:1.7;padding:12px;background:#f5f7f8;border:1px solid #dbe3e6;">local result = EndEvent()
<pre>local result = EndEvent()
-- EndEvent 已注册,但无返回值,因此 result 为 nil
-- EndEvent 已注册,但无返回值,因此 result 为 nil
if result == nil then
if result == nil then
第60行: 第60行:
[[Lua接口/服务端调用约定|服务端调用约定]] · [[Lua接口/服务端调用示例|服务端调用示例]]
[[Lua接口/服务端调用约定|服务端调用约定]] · [[Lua接口/服务端调用示例|服务端调用示例]]


<div style="margin-top:20px;padding-top:10px;border-top:1px solid #dbe3e6;color:#657078;font-size:12px;">示例依据当前服务端注册名称和参数读取顺序核对;sceneId、selfId 等上下文及业务编号由实际回调提供。Lua 语法检查不能代替游戏内实测。</div>
<div class="lua-note">示例依据当前服务端注册名称和参数读取顺序核对;sceneId、selfId 等上下文及业务编号由实际回调提供。Lua 语法检查不能代替游戏内实测。</div>


</div>
</div>

2026年9月19日 (六) 16:59的最新版本

首页 · 服务端接口 · 调用约定

函数调用报 nil 时,先判断报错的是函数名称,还是函数执行后得到的结果。下面的服务端示例使用当前回调提供的 sceneId、selfId。

先区分三种情况

现象 含义与排查方向
attempt to call ... (a nil value) 执行到调用位置时,该名称的值是 nil;检查拼写、运行环境、脚本加载和同名变量。参数顺序错误通常不是这条报错的直接原因。
attempt to index ... (a nil value) 点号或下标前的对象是 nil;先检查访问的 table 或上一步返回值。把 table 不存在误判为原生函数未注册,会查错方向。
调用完成,接收变量为 nil 可能是接口无返回值、失败分支少返回几项,或者脚本封装漏写 return;此时函数本身可以存在。

错误文本可能随 Lua 运行环境不同而变化,以实际错误行和被指出的变量为准。

检查调用名称是否是函数

local entryType = type(GetLevel)
if entryType ~= "function" then
    -- 查看 entryType,并检查当前作用域和运行环境
    return
end
local level = GetLevel(sceneId, selfId)
if type(level) == "number" and level >= 0 then
    -- 已取得等级
end

这里只检查名称能否调用,不保证玩家对象、场景或业务条件有效。type 是 Lua 基础函数,不属于服务端注册接口。

按顺序排查

  1. 在 服务端函数索引 中查完整名称,核对大小写和 LuaFn 前缀。GetLevel 与 LuaFnGetLevel 都有注册,但不能把这个规则套给其他函数。
  2. 核对实际运行的是服务端脚本还是客户端界面脚本。复制 .lua 文件不会把另一端的 C++ 注册函数一并复制过去,见 调用范围。
  3. 检查同名变量。例如声明 local GetLevel 后,该局部变量会遮住全局函数;给 GetLevel 赋数值、字符串或 nil 也会改变之后的调用行为。业务变量宜命名为 level、playerLevel。
  4. 若调整过脚本环境表,检查该环境是否能访问注册函数。普通全局环境下可比较 type(GetLevel) 与 type(_G.GetLevel),不要直接修改 _G 来掩盖加载问题。
  5. 区分 C++ 注册接口和脚本自定义入口。前者由运行程序注册,后者需要对应脚本加载成功;检查脚本编号、入口名称和之前的语法错误。CallScriptFunction 的参数另有约定,不能代替两端之间的通信。
  6. 若当前源码有注册而运行时仍为 nil,核对实际启动的程序和脚本部署是否与源码一致;热加载能力、加载时机和具体重载流程需要实测。

有函数但没有返回值

local result = EndEvent()
-- EndEvent 已注册,但无返回值,因此 result 为 nil
if result == nil then
    -- 这不能证明 EndEvent 不存在或执行失败
end

EndEvent 不会自动把对话显示给玩家。AddText 和 AddItemListToHuman 也不能通过接收结果判断业务成功。返回数量与返回数字的区别见 返回值判断。

记录问题时保留什么

保留函数完整名称、错误文本和行号、报错前后的短代码、运行端、回调名称,以及每个实参的值和 type 结果。优先检查最早出现的加载错误,后续 nil 可能只是连带结果。

相关问题

服务端调用约定 · 服务端调用示例

示例依据当前服务端注册名称和参数读取顺序核对;sceneId、selfId 等上下文及业务编号由实际回调提供。Lua 语法检查不能代替游戏内实测。