Archived

This topic is now archived and is closed to further replies.

Please be aware that the content of this thread may be outdated and no longer applicable.

Recommended Posts

Cthonicus    11

Hello there!

 

I recently have composed a character mod that consists of a character and a custom item this character uses. All seemed to work just fine, even to where I uploaded it to the workshop. However, I soon discovered that the mod absolutely does not work with caves and I cannot figure out why. The mod works perfectly fine with no caves, but once they're added, the server immediately disconnects and loses connection right after spawning in.

 

If this matters, my character's perks are:

-sanity gain near certain mobs

-spawns with a custom weapon

-loses additional sanity at night

 

I have attached my character, modinfo and modmain .lua files in case anyone wants to view them.

Thank you for your time!

modinfo.lua

modmain.lua

wolyo.lua

 

(EDIT): I singled out the issue and found the specific lines that are causing the crash. It is these lines of code in my modmain.lua that cause the server to disconnect upon launch -

AddPrefabPostInit("butterfly", function(inst)
        if GetPlayer().prefab == "wolyo" then
            inst:AddComponent("sanityaura")
            inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
        end
end)

AddPrefabPostInit("bee", function(inst)
        if GetPlayer().prefab == "wolyo" then
            inst:AddComponent("sanityaura")
            inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
        end
end)

AddPrefabPostInit("chester", function(inst)
        if GetPlayer().prefab == "wolyo" then
            inst:AddComponent("sanityaura")
            inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
        end
end)

AddPrefabPostInit("glommer", function(inst)
        if GetPlayer().prefab == "wolyo" then
            inst:AddComponent("sanityaura")
            inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
        end
end)

AddPrefabPostInit("hutch", function(inst)
        if GetPlayer().prefab == "wolyo" then
            inst:AddComponent("sanityaura")
            inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
        end
end)

If these lines work without caves, what would make them work with caves?

Share this post


Link to post
Share on other sites
Ultroman    659

Your mod doesn't work for clients, so it doesn't work fine without caves either. When you add caves, it splits the game into two server shards, forest and cave. You then become a client on forest and can transition to caves. Without caves, there's only one server shard needed so you become the server instead of a client. It's badly explained, but that's the gist of it. Some code explodes when it runs on the clients, because clients do not have components on their entities like the server does. They only have shells of the entities which are controlled by the server, and they also don't have access to calling functions on the server. So, all your code that messes with components and calls postinit functions and all that, that can't be run on the clients.

Start by wrapping your many AddPrefabPostInit calls like this:

if GLOBAL.TheNet and GLOBAL.TheNet:GetIsServer() then
    AddPrefabPostInit("butterfly", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("bee", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("chester", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("glommer", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("hutch", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)
end

There are also things in custom items which need networking attention. Components should only be added to the item on the server.

Share this post


Link to post
Share on other sites
Cthonicus    11
1 hour ago, Ultroman said:

Your mod doesn't work for clients, so it doesn't work fine without caves either. When you add caves, it splits the game into two server shards, forest and cave. You then become a client on forest and can transition to caves. Without caves, there's only one server shard needed so you become the server instead of a client. It's badly explained, but that's the gist of it. Some code explodes when it runs on the clients, because clients do not have components on their entities like the server does. They only have shells of the entities which are controlled by the server, and they also don't have access to calling functions on the server. So, all your code that messes with components and calls postinit functions and all that, that can't be run on the clients.

Start by wrapping your many AddPrefabPostInit calls like this:


if _G.TheNet and _G.TheNet:GetIsServer() then
    AddPrefabPostInit("butterfly", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("bee", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("chester", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("glommer", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("hutch", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)
end

There are also things in custom items which need networking attention. Components should only be added to the item on the server.

I tried this and it results in me being unable to start the server. It tells me "There was some sort of trouble starting the server. Please try again."

 

I attached the log below if that helps.

 

Thanks for the reply!

client_log.txt

modmain.lua

Share this post


Link to post
Share on other sites
Ultroman    659

The client log doesn't help much when you use caves, since everything then runs on the server shards. We need the server logs from both the forest and cave server shards, as well as the client log, from just after a crash happened. Please check out the newcomer post. It has information about where to find these files, and how to debug your mod in general.

BUT, in this case, there is one error you should fix before debugging any further. The code I pasted uses _G, which is what I always save my GLOBAL reference as, just to save on characters. Here's an example using your own code.

local _G = GLOBAL
local require = _G.require
local STRINGS = _G.STRINGS
local Ingredient = _G.Ingredient
local RECIPETABS = _G.RECIPETABS
local Recipe = _G.Recipe
local TECH = _G.TECH
local TUNING = _G.TUNING
local GetPlayer = _G.GetPlayer

-- This is for the sanity aura Wolyo gains from "cute" things

if _G.TheNet and _G.TheNet:GetIsServer() then
    AddPrefabPostInit("butterfly", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("bee", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("chester", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("glommer", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("hutch", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)
end

 

Share this post


Link to post
Share on other sites
Cthonicus    11
6 minutes ago, Ultroman said:

The client log doesn't help much when you use caves, since everything then runs on the server. We need the server logs from both the forest and cave server shards, as well as the client log, from just after a crash happened. Please check out the newcomer post. It has information about where to find these files, and how to debug your mod in general.

BUT, in this case, there is one error you should fix before debugging any further. The code I pasted uses _G, which is what I always save my GLOBAL reference as, just to save on characters. Here's an example using your own code.


local _G = GLOBAL
local require = _G.require
local STRINGS = _G.STRINGS
local Ingredient = _G.Ingredient
local RECIPETABS = _G.RECIPETABS
local Recipe = _G.Recipe
local TECH = _G.TECH
local TUNING = _G.TUNING
local GetPlayer = _G.GetPlayer

-- This is for the sanity aura Wolyo gains from "cute" things

if _G.TheNet and _G.TheNet:GetIsServer() then
    AddPrefabPostInit("butterfly", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("bee", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("chester", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("glommer", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)

    AddPrefabPostInit("hutch", function(inst)
            if GetPlayer().prefab == "wolyo" then
                inst:AddComponent("sanityaura")
                inst.components.sanityaura.aura = TUNING.SANITYAURA_MED
            end
    end)
end

 

Tried the code and got the same result :(

 

I attached both log files like you said, hope it helps!

server_log_cave.txt

server_log.txt

client_log.txt

Share this post


Link to post
Share on other sites
Ultroman    659

From the absolute bottom of your first server log:

[string "../mods/wolyo/modmain.lua"]:64: attempt to index a nil value
LUA ERROR stack traceback:
        ../mods/wolyo/modmain.lua(64,1)
        =(tail call) ?
        =[C] in function 'xpcall'
        scripts/mods.lua(161,1) in function 'mod'
        scripts/mainfunctions.lua(267,1)
        =[C] in function 'SpawnPrefab'
        scripts/mainfunctions.lua(306,1) in function 'SpawnPrefab'
        scripts/components/childspawner.lua(445,1) in function 'DoSpawnChild'
        scripts/components/childspawner.lua(472,1) in function 'SpawnChild'
        scripts/components/childspawner.lua(178,1) in function 'OnUpdate'
        scripts/components/childspawner.lua(200,1) in function 'fn'
        scripts/scheduler.lua(177,1) in function 'OnTick'
        scripts/scheduler.lua(371,1) in function 'RunScheduler'
        scripts/update.lua(180,1)	
[00:01:07]: Disabling wolyo (Wolyo) because it had an error.

Since you've edited the code, I don't know what line 64 is now. But I'm guessing it's GetPlayer() which returns nil. This looks like DS code. What it wants to do doesn't make any sense in a multiplayer setting. It says: if the "the player" using a particular character, add an aura to the bees. It makes sense in DS, since there's only one player to be affected by the aura, and we know which character they are playing during worldgeneration and loading, but in DST we do not. I believe GetPlayer() on the client returns the character entity (client-shell version) of the current client, but since the postinits are only called on the server, there IS NO PLAYER TO CHECK.

The code wants to give the player sanity when close to bees by adding a sanity aura to the bees. But the way it is done makes everyone be affected by the sanityaura. Additionally, you don't check if they already have a sanityaura component. Perhaps another mod has already added a sanityaura component, in which case your mod overwrites their sanityaura or their mod overwrites yours (I think).

Always check if there is already an aurafn function, and if there is, extend it to do whatever extra thing you want it to do for certain "observers" (entities, i.e. players, monster, etc. with a sanity component). Otherwise, add a new aurafn which does what you want. I have done this in the topic here.

Share this post


Link to post
Share on other sites