Jump to content

Recommended Posts

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?

Edited by Cthonicus
Link to comment
https://forums.kleientertainment.com/forums/topic/114787-mod-crashes-with-caves/
Share on other sites

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.

Edited by Ultroman
Corrected _G to GLOBAL
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

Edited by Cthonicus
I attached the modmain.lua AFTER the newly added line.

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

 

Edited by Ultroman
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

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.

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...