Jump to content
Toggle menu
  • 3 articles
  • 22 files
  • 3 users
  • 2.5K edits
Shroudforge
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.
This page is a translated version of the page Modding and the translation is 100% complete.


Modding



通过 Lua 运行时读取主菜单状态和当前选中的本地角色名称。这两个查询使用与 Modloader 相同的原生数据,无需访问世界。

前置条件

启用模组,并在 mod.json 中声明 runtime 能力:

{
  "capabilities": ["runtime"]
}

对于这些客户端查询,请在 extended.mod.json 中将 targets 设为 ["client"]。从活动的运行时回调(例如 on_load 和 on_update)调用这些函数。runtime.phase == "ingame" 表示模组运行时已启动,但不能确认已进入世界。这两个查询都不需要执行配置文件。其他世界操作仍有各自的要求。

检测主菜单

local in_menu, reason = runtime.is_main_menu()
返回值 含义
true, nil 已确认处于主菜单,包括角色、世界和服务器选择界面。
false, nil 已验证为游戏的其他原始状态。
nil, reason 状态未知、正在变化,或查询不可用。

请明确检查 in_menu == true 或 in_menu == false。nil 不代表已确认的状态。单独的 false 也不能确认世界可读取。请另外检查所需操作,例如 runtime.has("runtime.ecs.read")。

读取角色名称

local name, reason = runtime.player.name()
local display_name = name or "Flameborn"

name, nil 会以 UTF-8 字符串形式返回在本地客户端主菜单中选中的角色名称。Ikiju 育樹 这样的 Unicode 字符会保留。nil, reason 表示名称尚不可用,或当前无法访问或不允许访问。

模组自行选择备用名称。API 不会插入默认名称,也不会使用 Modloader 的手动名称选择。此值不代表远程玩家,也不是 SteamID 或 Steam 显示名称。专用服务器没有本地客户端角色名称。

共享缓存

Lua 和 Modloader 读取同一个原生缓存。现有运行时 tick 会刷新菜单状态。现有菜单集成会在首次选择可用时获取名称,并在选择或名称元数据变化时再次获取。Lua 查询不会启动单独的发现过程,也不会读取日志。

进入世界后,最近一次成功获取的名称仍会保留在缓存中。因此,缓存中存在名称并不能确认菜单仍处于打开状态。runtime.has("runtime.is_main_menu") 和 runtime.has("runtime.player.name") 会报告各自查询是否可用。runtime.status(...) 也会提供原因。

src/mod.lua 示例

此示例会在加载时读取缓存,之后每 500 毫秒读取一次。它会选择备用名称,并且只记录变化:

runtime.require("runtime.lifecycle")

local previous_message = nil

local function refresh()
    local in_menu = runtime.is_main_menu()
    local name = runtime.player.name()
    local state = "unknown"
    if in_menu == true then
        state = "menu"
    elseif in_menu == false then
        state = "other"
    end

    local message = state .. ": " .. (name or "Flameborn")
    if message ~= previous_message then
        previous_message = message
        shroudforge.log.info(message)
    end
end

return {
    on_load = refresh,
    on_update = function()
        refresh()
    end,
    update_interval_ms = 500,
}