Jump to content

Animation is invisible unless I am the host


Recommended Posts

Dear fellow modders,

I have been working on porting snakes from Shipwrecked to DST. This all seemed to work perfectly when I was testing the game locally, i.e., when I was the host. However, when running the same version (I checked this multiple times) on a dedicated server, the snake suddenly becomes invisible for clients. I know the snake is there, because it keeps hitting me, but I can't hit it back.

I have no idea why this problem occurs, since I have worked on several prefabs (items, mobs, etc.). All of them worked both as host and as client, with the exception of the snake which only works as a host but not as a client (at least when it comes to showing the animation).

I have even made sure to insert the SetPristine code at the right location. Here is a snippet to show you this:

 

...

anim:SetBank("snake")
    anim:SetBuild("snake_build")
    anim:PlayAnimation("idle")
    inst.AnimState:SetRayTestOnBB(true)

    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end

    inst:AddComponent("knownlocations")

    inst:AddComponent("locomotor") -- locomotor must be constructed before the stategraph
    inst.components.locomotor.runspeed = 3
    inst:SetStateGraph("SGsnake")

....

The only thing that makes the snake stand out in my mod is that it has a custom stategraph. I have, however, compared this to other stategraphs of DST, but I can't find anything special about this stategraph that would explain this. I have read somewhere that this might have to do with movement prediction and that it may help to add "nopredict" to the tag tables, but no luck there.

This is what the stategraph looks like:

 

require("stategraphs/commonstates")

local actionhandlers =
{
    ActionHandler(ACTIONS.EAT, "eat"),
    ActionHandler(ACTIONS.LAVASPIT, "spit"),
    ActionHandler(ACTIONS.GOHOME, "gohome"),
}

local events=
{
    EventHandler("attacked", function(inst) if not inst.components.health:IsDead() and not inst.sg:HasStateTag("attack") then inst.sg:GoToState("hit") end end),
    EventHandler("death", function(inst) inst.sg:GoToState("death") end),
    EventHandler("doattack", function(inst, data) if not inst.components.health:IsDead() and (inst.sg:HasStateTag("hit") or not inst.sg:HasStateTag("busy")) then inst.sg:GoToState("attack", data.target) end end),
    CommonHandlers.OnSleep(),
    CommonHandlers.OnLocomote(true,false),
    CommonHandlers.OnFreeze(),
}

local states=
{

    State{
        name = "gohome",
        tags = {"busy", "nopredict"},
        onenter = function(inst, playanim)
            if inst.components.homeseeker and 
               inst.components.homeseeker.home and 
               inst.components.homeseeker.home:IsValid() then

                --inst.components.homeseeker.home.AnimState:PlayAnimation("chop", false)
            end
            inst:PerformBufferedAction()
        end,
    },

    State{
        name = "idle",
        tags = {"idle", "canrotate", "nopredict"},
        onenter = function(inst, playanim)
            --inst.SoundEmitter:PlaySound("dontstarve/creatures/spider/idle")
            inst.Physics:Stop()
            if playanim then
                inst.AnimState:PlayAnimation(playanim)
                inst.AnimState:PushAnimation("idle", true)
            else
                inst.AnimState:PlayAnimation("idle", true)
            end
            inst.sg:SetTimeout(2*math.random()+.5)
        end,

    },

    
    State{
        name = "attack",
        tags = {"attack", "busy", "nopredict"},

        onenter = function(inst, target)
            inst.sg.statemem.target = target
            inst.Physics:Stop()
            inst.components.combat:StartAttack()
            --inst.SoundEmitter:PlaySound("dontstarve/creatures/spider/pre-attack")
            inst.AnimState:PlayAnimation("atk_pre")
            inst.AnimState:PushAnimation("atk", false)
            inst.AnimState:PushAnimation("atk_pst", false)
        end,

        timeline=
        {
            TimeEvent(8*FRAMES, function(inst) 
                if inst.components.combat.target then 
                    inst:ForceFacePoint(inst.components.combat.target:GetPosition()) 
                end 
            end),

            TimeEvent(14*FRAMES, function(inst) 
                if inst.components.combat.target then 
                    inst:ForceFacePoint(inst.components.combat.target:GetPosition()) 
                end 
                inst.SoundEmitter:PlaySound("dontstarve/creatures/spider/attack") 
            end),

            TimeEvent(20*FRAMES, function(inst) 
                if inst.components.combat.target then 
                    inst:ForceFacePoint(inst.components.combat.target:GetPosition()) 
                end 
            end),

            TimeEvent(27*FRAMES, function(inst) 
                inst.components.combat:DoAttack(inst.sg.statemem.target) 
                if inst.components.combat.target then 
                    inst:ForceFacePoint(inst.components.combat.target:GetPosition())
                end 
            end),
        },

        events=
        {
            EventHandler("animqueueover", function(inst) inst.sg:GoToState("idle") end),
        },
    },

    State{
        name = "eat",
        tags = {"busy", "nopredict"},

        onenter = function(inst, cb)
            inst.Physics:Stop()
            inst.components.combat:StartAttack()
            inst.AnimState:PlayAnimation("atk_pre")
            inst.AnimState:PushAnimation("atk", false)
            inst.AnimState:PushAnimation("atk_pst", false)
        end,

        timeline=
        {
            TimeEvent(14*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spider/attack") end),
            TimeEvent(24*FRAMES, function(inst) if inst:PerformBufferedAction() then inst.components.combat:SetTarget(nil) end end),
        },

        events=
        {
            EventHandler("animqueueover", function(inst)  inst.sg:GoToState("taunt")  end),
        },
    },

    State{
        name = "spit",
        tags = {"busy", "nopredict"},
        
        onenter = function(inst)
            -- print("snake spit")
            if ((inst.target ~= inst and not inst.target:HasTag("fire")) or inst.target == inst) and not (inst.recently_frozen) then
                if inst.components.locomotor then
                    inst.components.locomotor:StopMoving()
                end
                inst.AnimState:PlayAnimation("atk_pre")
                inst.AnimState:PushAnimation("atk", false)
                inst.AnimState:PushAnimation("atk_pst", false)

                inst.components.propagator:StartSpreading()

                --print("vomitfire_fx spawned")
                -- inst.vomitfx = SpawnPrefab("vomitfire_fx")
                -- inst.vomitfx.Transform:SetPosition(inst.Transform:GetWorldPosition())
                -- inst.vomitfx.Transform:SetRotation(inst.Transform:GetRotation())
                --inst.SoundEmitter:PlaySound("dontstarve_DLC001/creatures/dragonfly/vomitrumble", "vomitrumble")
            else
                -- print("no spit")
                inst:ClearBufferedAction()
                inst.sg:GoToState("idle")
            end
        end,

        onexit = function(inst)
            -- print("spit onexit")
            if inst.last_target and inst.last_target ~= inst then
                inst.num_targets_vomited = inst.last_target.components.stackable and inst.num_targets_vomited + inst.last_target.components.stackable:StackSize() or inst.num_targets_vomited + 1
                inst.last_target_spit_time = GetTime()
            end
            --inst.Transform:SetFourFaced()
            -- if inst.vomitfx then 
                -- inst.vomitfx:Remove() 
            -- end
            -- inst.vomitfx = nil
            -- inst.SoundEmitter:KillSound("vomitrumble")

            inst.components.propagator:StopSpreading()
        end,
        
        events=
        {
            EventHandler("animqueueover", function(inst) 
                -- print("spit animqueueover")
                inst.sg:GoToState("idle")
            end),
        },

        timeline=
        {
            TimeEvent(2*FRAMES, function(inst) 
                -- print("spit timeline")
                inst:PerformBufferedAction()
                inst.last_target = inst.target
                inst.target = nil
                inst.spit_interval = math.random(20,30)
                inst.last_spit_time = GetTime()
            end),
        },
    },
    
    State{
        name = "hit",
        tags = {"busy", "hit", "nopredict"},

        onenter = function(inst, cb)
            inst.Physics:Stop()
            inst.AnimState:PlayAnimation("hit")
            inst.SoundEmitter:PlaySound("dontstarve/creatures/spider/hurt")
        end,

        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end),
        },
    },

    State{
        name = "taunt",
        tags = {"busy", "nopredict"},

        onenter = function(inst, cb)
            inst.Physics:Stop()
            inst.AnimState:PlayAnimation("taunt")
            -- inst.SoundEmitter:PlaySound("dontstarve_DLC002/creatures/snake/taunt")
        end,

        timeline=
        {
            TimeEvent(10*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spider/scream") end),
            --TimeEvent(24*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC002/creatures/snake/taunt") end),
        },

        events=
        {
            EventHandler("animover", function(inst) inst.sg:GoToState("idle") end ),
        },
    },

    State{
        name = "death",
        tags = {"busy"},

        onenter = function(inst)
            inst.SoundEmitter:PlaySound("dontstarve/creatures/spider/death")
            inst.AnimState:PlayAnimation("death")
            inst.Physics:Stop()
            RemovePhysicsColliders(inst)            
            inst.components.lootdropper:DropLoot(Vector3(inst.Transform:GetWorldPosition()))            
        end,

    },
}

CommonStates.AddSleepStates(states,
{
    sleeptimeline = {
        TimeEvent(30*FRAMES, function(inst) inst.SoundEmitter:PlaySound("dontstarve/creatures/spider/sleep") end),
    },
})


CommonStates.AddRunStates(states,
{
    runtimeline = {
        --TimeEvent(0, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC002/creatures/snake/move") end),
        --TimeEvent(4, function(inst) inst.SoundEmitter:PlaySound("dontstarve_DLC002/creatures/snake/move") end),
    },
})
CommonStates.AddFrozenStates(states)


return StateGraph("snake", states, events, "taunt", actionhandlers)

If anyone can help me out, that would be great. Thanks in advance.

Edited by Joachim
Link to comment
Share on other sites

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
 Share

×
  • Create New...