You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UE4SS环境下Lua脚本ToggleVisibility函数重复执行问题求助

问题分析与解决方法

你遇到的attempt to index a nil value错误,核心原因是变量未初始化就被访问,或者全局Hook/定时器逻辑未做足够空值校验,具体分两种场景修复:

一、TimerManager方式失效的原因与修复

UE4SS中TimerManager并非全局可直接调用的对象,需从玩家控制器或游戏实例中获取有效实例。另外原逻辑未判断LightComponent是否初始化就重复调用,导致空指针错误。

修改后的定时器实现:

local IDA, IDB
local LightComponent
local TimerHandle -- 存储定时器句柄,方便后续销毁

function HookNewLight(ContextParam)
    local Context = ContextParam:get()
    LightComponent = Context:GetPropertyValue("PointLight")
    if LightComponent and LightComponent:IsValid() then
        LightComponent:SetHiddenInGame(true, true)
        -- 仅当LightComponent有效时启动定时器
        StartVisibilityCheckTimer()
    end
end

function StartVisibilityCheckTimer()
    -- 获取玩家控制器实例
    local PlayerController = GetPlayerController()
    if not PlayerController then return end
    
    local TimerManager = PlayerController:GetTimerManager()
    if not TimerManager then return end

    -- 使用循环定时器替代递归调用,避免栈溢出
    TimerHandle = TimerManager:SetTimer(function() CheckVisibility() end, 0.1, true)
end

function CheckVisibility()
    if (LightComponent and LightComponent:IsValid()) then
        -- 逻辑调整:如果当前可见则隐藏
        if LightComponent:IsVisible() then
            LightComponent:SetHiddenInGame(true, true)
        end
    else
        -- LightComponent失效时停止定时器
        local PlayerController = GetPlayerController()
        if PlayerController then
            local TimerManager = PlayerController:GetTimerManager()
            if TimerManager and TimerHandle then
                TimerManager:ClearTimer(TimerHandle)
                TimerHandle = nil
            end
        end
    end
end

RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
    if IDA == nil then
        IDA, IDB = RegisterHook("/Game/Core/Characters/Player/AnathemaPlayerCharacter_BP.AnathemaPlayerCharacter_BP_C:ReceiveBeginPlay", HookNewLight)
    end
end)

function ToggleVisibility()
    if(LightComponent and LightComponent:IsValid()) then
        -- 原逻辑写反:SetHiddenInGame参数为是否隐藏,需取反当前可见状态
        local NewState = not LightComponent:IsVisible()
        LightComponent:SetHiddenInGame(NewState, true)
    end
end

RegisterKeyBind(Key.F3, ToggleVisibility)

二、Actor Tick Hook失效的原因与修复

全局Hook/Script/Engine.Actor:Tick会对所有Actor触发回调,原逻辑未处理回调参数、未判断当前Actor是否为玩家角色,导致多数场景下LightComponent为nil。正确做法是仅Hook玩家角色的Tick:

local IDA, IDB, TickHookID
local LightComponent

function HookNewLight(ContextParam)
    local Context = ContextParam:get()
    LightComponent = Context:GetPropertyValue("PointLight")
    if LightComponent and LightComponent:IsValid() then
        LightComponent:SetHiddenInGame(true, true)
        -- Hook当前玩家角色的Tick
        local PlayerCharacter = Context:GetOwner()
        if PlayerCharacter then
            TickHookID = RegisterHook(PlayerCharacter:GetFullName() .. ":Tick", CheckVisibility)
        end
    end
end

function CheckVisibility(ContextParam)
    -- 先校验LightComponent有效性
    if not (LightComponent and LightComponent:IsValid()) then
        -- 失效时取消Tick Hook
        if TickHookID then
            UnregisterHook(TickHookID)
            TickHookID = nil
        end
        return
    end

    if LightComponent:IsVisible() then
        LightComponent:SetHiddenInGame(true, true)
    end
end

RegisterHook("/Script/Engine.PlayerController:ClientRestart", function(Context, NewPawn)
    if IDA == nil then
        IDA, IDB = RegisterHook("/Game/Core/Characters/Player/AnathemaPlayerCharacter_BP.AnathemaPlayerCharacter_BP_C:ReceiveBeginPlay", HookNewLight)
    end
end)

function ToggleVisibility()
    if(LightComponent and LightComponent:IsValid()) then
        local NewState = not LightComponent:IsVisible()
        LightComponent:SetHiddenInGame(NewState, true)
    end
end

RegisterKeyBind(Key.F3, ToggleVisibility)

通用注意事项

  • 所有访问LightComponent的地方必须先做LightComponent and LightComponent:IsValid()校验,避免对象失效引发错误。
  • 避免全局Hook所有Actor的通用函数(如Tick),尽量只Hook目标对象的函数,减少性能开销和错误概率。
  • UE4SS中获取全局对象(如PlayerController)可使用GetPlayerController()或GetGameInstance(),确保获取有效实例后再操作。

内容的提问来源于stack exchange,提问作者Account Kis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 22:20:06