Jump to content

I encountered player_common.lua:468: attempt to index field 'action' (a nil value), and I found the reason


Whateverr
  • Fixed

Crash log

I found that someone else had already reported the bug, here are some links to the posts.

Causing the server to crash while doing certain action expressions

Character action causes server crash

A typical stack traceback looks like this:

[string "scripts/prefabs/player_common.lua"]:468: attempt to index field 'action' (a nil value)
LUA ERROR stack traceback:
    scripts/prefabs/player_common.lua:468 in (local) fn (Lua) <466-479>
    scripts/entityscript.lua:1178 in (method) PushEvent (Lua) <1165-1192>
    scripts/entityscript.lua:1495 in (method) PerformBufferedAction (Lua) <1476-1500>
    scripts/stategraphs/SGwilson.lua:12081 in () ? (Lua) <12078-12086>
    =(tail call):-1 in ()  (tail) <-1--1>
    scripts/stategraph.lua:453 in (method) HandleEvent (Lua) <451-459>
    scripts/stategraph.lua:467 in (method) HandleEvents (Lua) <461-476>
    scripts/stategraph.lua:154 in (method) UpdateEvents (Lua) <148-157>
    scripts/stategraph.lua:145 in (method) Update (Lua) <109-146>
    scripts/update.lua:288 in () ? (Lua) <224-298>

 

Analysis

According to the stack traceback, inst:PerformBufferedAction() was called from SGwilson.lua:12081, it pushed an actionfailed event, but self.bufferedaction was nil.

So, why was self.bufferedaction nil?

Let's take a look at the implementation of PerformBufferedAction.

function EntityScript:PerformBufferedAction()
    if self.bufferedaction then
        if self.bufferedaction.target and self.bufferedaction.target:IsValid() and self.bufferedaction.target.Transform then
            self:FacePoint(self.bufferedaction.target.Transform:GetWorldPosition())
        end

        self:PushEvent("performaction", { action = self.bufferedaction })

        local action_theme_music = self:HasTag("player") and (self.bufferedaction.action.theme_music or (self.bufferedaction.action.theme_music_fn ~= nil and self.bufferedaction.action.theme_music_fn(self.bufferedaction)))
        if action_theme_music then
            self:PushEvent("play_theme_music", {theme = action_theme_music})
        end

        local success, reason = self.bufferedaction:Do() -- << here called ACTIONS.JUMPIN.fn but the return value was not true
        if success then
            self.bufferedaction = nil
            return true
        end

        self:PushEvent("actionfailed", { action = self.bufferedaction, reason = reason }) -- << !!! PUSHED actionfailed EVENT but data.action was nil

        self.bufferedaction:Fail()
        self.bufferedaction = nil
    end
end

In this method, initially, self.bufferedaction is NOT nil. However, if self.bufferedaction:Do() is called and the return value success is NOT true, then it means that the action execution has failed, and actionfailed event will be pushed.

Obviously, if self.bufferedaction is set to nil when self.bufferedaction:Do() is executed, it will cause a crash.

Possible causes

Since version 579589, inst:ClearBufferedAction() was added to line 2681 of SGwilson.lua, which causes the buffered action to be cleared when calling player.sg:GoToState("idle"). Similar changes have also been made in SGwilsonghost.lua.

image.png.9ae3105b768aeea05e010951c3feef5b.png

 

Let's see the implementation of ClearBufferedAction, it does set self.bufferedaction to nil.

function EntityScript:ClearBufferedAction()
    if self.bufferedaction ~= nil then
        self.bufferedaction:Fail()
        self.bufferedaction = nil -- << THIS LINE
    end
end

However, in some ACTIONS such as JUMPIN (as well as ACTIONS added in some mods that mimic JUMPIN), doer.sg:GoToState("idle") is called when some conditions are not met.

ACTIONS.JUMPIN.fn = function(act)
    if act.doer ~= nil and
        act.doer.sg ~= nil and
        act.doer.sg.currentstate.name == "jumpin_pre" then
        if act.target ~= nil and
            act.target.components.teleporter ~= nil and
            act.target.components.teleporter:IsActive() then
            act.doer.sg:GoToState("jumpin", { teleporter = act.target })
            return true
        end
        act.doer.sg:GoToState("idle") -- << THIS LINE WILL SET self.bufferedaction TO nil !!!
    end
end

In this case, the call to self.bufferedaction:Do() in inst:PerformBufferedAction() returns nil, and self.bufferedaction is also set to nil, hence the aforementioned crash.

There are many mods that mimic what is done in the JUMPIN action, so I'm hoping that this can be fixed with, say, allowing GoToState("idle") to be called in ACTION.fn.


That's all.


Steps to Reproduce

see above




User Feedback


A developer has marked this issue as fixed. This means that the issue has been addressed in the current development build and will likely be in the next update.


Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
  • Create New...