Jump to content

Recommended Posts

I'm trying to get a list of possible light items in the players inventory. I have this part working, however the way I have it now, it can equip a lantern that is at 0%. I'm trying to check if the lantern is empty before adding it to a list of possible lights. 

local possibleLights = CustomFindItem(inst,
            (inst.components and inst.components.playercontroller and inst.components.inventory) or
                (inst.replica and inst.replica.inventory), function(item)
                for _, v in ipairs(lights) do
                    if tostring(item):find(v) then
                        if tostring(item):find("lantern") --and lanternpercent ~= 0 
                        then
                        return true
                    end
                end
            end)

I saw in "mininglantern.lua" it showed a fueled component. and the fueled component had a function IsFueled() and GetPercent(). I tried calling the function item.fueled:IsFueled() and item.fueled:GetPercent() but I could not get either to work. 

How do I call these functions for a lantern item in the inventory?

15 hours ago, Friendly Grass said:

 


not item.components.fueled:IsEmpty()

 

I tried this and I get an error saying "attempt to index field 'fueled' (a nil value)"

So what I am assuming is that my "item" variable isn't the value I'm looking for. It returns the correct item prefab though.

for reference here my CustomFindItem function:

Spoiler
local function CustomFindItem(inst, inv, check)
    local items = inv and inv.GetItems and inv:GetItems() or inv.itemslots or nil
    if not inst or not inv or not check or not items then
        if letsDoDebug then
            print("Something went wrong with the inventory...")
        end
        return nil
    end
 
    local Item = nil
    for k, v in pairs(items) do
        if check(v) then
            Item = v
        end
    end
    if inv.GetOverflowContainer and inv:GetOverflowContainer() ~= nil then
        items = inv:GetOverflowContainer() and inv:GetOverflowContainer().GetItems and
                    inv:GetOverflowContainer():GetItems() or inv:GetOverflowContainer().slots or nil
        if items then
            for k, v in pairs(items) do
                if check(v) then
                    Item = v
                end
            end
        end
    end
 
    if (inst.replica and inst.replica.inventory and inst.replica.inventory.GetEquippedItem and
        inst.replica.inventory:GetEquippedItem(EQUIPSLOTS.HANDS) and
        check(inst.replica.inventory:GetEquippedItem(EQUIPSLOTS.HANDS))) then
        Item = inst.replica.inventory:GetEquippedItem(EQUIPSLOTS.HANDS)
    end
    return Item
end

 

Edited by spm1999316

Is CustomFindItem supposed to return a list of light sources? Because the way it's set up now, it looks like it scans your entire inventory, recording each time it finds a new item to the local "Item" variable, but then continues iterating and continues overwriting Item until it gets to the end, which would only end up returning the last result it finds.

If you want to compile a list of all of the different light sources in all open inventories, instead of just caching the single item every time it finds one, make "Item" an empty table instead and use table.insert to append it for every time it finds a valid lantern (maybe rename it to "Items" for clarity).

And as far as your check function goes, afaik it should still be able to reference the item's components table even from the client side if retrieved via the GetItems method in the replica. The check method should look something like this:

function(item)
    if item ~= nil and item.prefab == "lantern" then         
        local fueled = item.components.fueled
        if fueled and not fueled:IsEmpty() then
            return true
        end
    end
end

 

2 hours ago, w00tyd00d said:

afaik it should still be able to reference the item's components table even from the client side if retrieved via the GetItems method in the replica. 

So I updated my CustomFindItem function to return the first light source that matches a value in a list of item prefabs. That works, however when the item is a "lantern" and I check the fueled:IsEmpty() it still says item.components.fueled is nil. I then tried to see if I could get a list of components in item.components and the only thing listed is "floater". So I'm assuming the issue is that item.components.fueled is not accessible client side or I messed something up somewhere.

updated function:

Spoiler
local lightToEquip = CustomFindItem(inst,
            (inst.components and inst.components.playercontroller and inst.components.inventory) or
                (inst.replica and inst.replica.inventory),
                    function(item)
                        if item ~= nil and lights[item.prefab] then
                            local fueled = item.components.fueled
                            if item.prefab == "lantern" and fueled and fueled:IsEmpty() then
                                print("LANTERN IS EMPTY")
                                return
                            end
                            return true
                        end
                    end)

Also attaching the whole modmain.lua incase that helps someone figure out the issue. NOTE this code can use a lot of work, I am just starting to learn how to mod this game. 

Spoiler
local require = GLOBAL.require
local pcall = GLOBAL.pcall
local EQUIPSLOTS = GLOBAL.EQUIPSLOTS
 
local FindEntity = GLOBAL.FindEntity
 
local TheInput = GLOBAL.TheInput
local AllRecipes = GLOBAL.AllRecipes
 
local GetTime = GLOBAL.GetTime
 
local lights = {["lantern"]=true, ["torch"]=true}
local zzz = 1
 
local ae_enablemod = GetModConfigData("ae_enablemod") == 1 or false
local ae_givelight = GetModConfigData("ae_lightindark") or 2
 
local letsDoDebug = true
local ToggleModEnabled
 
local function CustomFindItem(inst, inv, check)
    local items = inv and inv.GetItems and inv:GetItems() or inv.itemslots or nil
    if not inst or not inv or not check or not items then
        if letsDoDebug then
            print("Something went wrong with the inventory...")
        end
        return nil
    end
 
    local Item = nil
    for k, v in pairs(items) do
        if check(v) then
            return v
        end
    end
    if inv.GetOverflowContainer and inv:GetOverflowContainer() ~= nil then
        items = inv:GetOverflowContainer() and inv:GetOverflowContainer().GetItems and
                    inv:GetOverflowContainer():GetItems() or inv:GetOverflowContainer().slots or nil
        if items then
            for k, v in pairs(items) do
                if check(v) then
                    return v
                end
            end
        end
    end
 
    if (inst.replica and inst.replica.inventory and inst.replica.inventory.GetEquippedItem and
        inst.replica.inventory:GetEquippedItem(EQUIPSLOTS.HANDS) and
        check(inst.replica.inventory:GetEquippedItem(EQUIPSLOTS.HANDS))) then
        Item = inst.replica.inventory:GetEquippedItem(EQUIPSLOTS.HANDS)
    end
    return Item
end
 
local tookLightOut = nil
local firstCheckedForDarkness = nil
local function CheckIfInDarkness(inst)
    if (not firstCheckedForDarkness) then
        if letsDoDebug then
            print("Oh, it's dark...")
        end
        firstCheckedForDarkness = GetTime()
    elseif (firstCheckedForDarkness and GetTime() > (firstCheckedForDarkness + 2)) then
        if letsDoDebug then
            print("That's it, I'm equipping light!")
        end
        firstCheckedForDarkness = nil
        local lightToEquip = CustomFindItem(inst,
            (inst.components and inst.components.playercontroller and inst.components.inventory) or
                (inst.replica and inst.replica.inventory),
                    function(item)
                        if item ~= nil and lights[item.prefab] then
                            local fueled = item.components.fueled
                            if item.prefab == "lantern" and fueled and fueled:IsEmpty() then
                                print("LANTERN IS EMPTY")
                                return
                            end
                            return true
                        end
                    end)
                            --[[ print("Fueled: ", fueled)
                            if zzz ~= nil then
                                print("Debug Data: ")
                                for k, v in pairs(item.components) do
                                    print("Comp: ", k)
                                end
                                zzz = nil
                            end ]]
        if (lightToEquip) then
            if lightToEquip then
                if letsDoDebug then
                    print("Equipping a light-source!")
                    print(lightToEquip)
                end
                if (inst == nil or inst.components == nil or inst.components.playercontroller == nil or lightToEquip ==
                    nil) then
                    return
                end
 
                local plcotrl = inst.components.playercontroller
                if (plcotrl and plcotrl.inst and plcotrl.inst.replica and plcotrl.inst.replica.inventory) then
                    if letsDoDebug then
                        print("- Equipping tool/weapon:", lightToEquip)
                    end
                    inst.replica.inventory:UseItemFromInvTile(lightToEquip)
                else
                    if letsDoDebug then
                        print("Tried to equip, but failed.")
                    end
                end
            else
                if letsDoDebug then
                    print("No lights found! Something went wrong...")
                end
            end
        else
            if (ae_givelight > 1) then
                if letsDoDebug then
                    print("No lights found, but attempting to craft a light.")
                end
                if (inst.replica and inst.replica.builder and inst.replica.builder.CanBuild and
                    inst.replica.builder.MakeRecipeFromMenu and inst.replica.builder:CanBuild("torch")) then
                    inst.replica.builder:MakeRecipeFromMenu(AllRecipes["torch"])
                end
            else
                if letsDoDebug then
                    print("No lights found.")
                end
            end
        end
    end
end
 
local CreateEntity = GLOBAL.CreateEntity
 
local function OnUpdate(playercontroller, dt)
    if not playercontroller:IsEnabled() then
        return
    end
    if ae_givelight and ae_givelight > 0 then
        if GLOBAL.TheWorld.state.isnight and not GLOBAL.TheWorld.state.isfullmoon and playercontroller.inst.LightWatcher and
            not playercontroller.inst.LightWatcher:IsInLight() then
            CheckIfInDarkness(playercontroller.inst)
        elseif (not (GLOBAL.TheWorld.state.isnight and not GLOBAL.TheWorld.state.isfullmoon and
            playercontroller.inst.LightWatcher and not playercontroller.inst.LightWatcher:IsInLight()) and
            firstCheckedForDarkness) then
            firstCheckedForDarkness = nil
        end
    end
end
 
local originalFunctions = {}
local originalFunctionsPicker = {}
 
local shouldToggleEnabled = nil
local function addPlayerController(inst)
    local controller = inst
 
    originalFunctions.OnUpdate = controller.OnUpdate
 
    controller.OnUpdate = function(salf, dt)
        originalFunctions.OnUpdate(salf, dt)
        if (shouldToggleEnabled ~= nil) then
            ToggleModEnabled(salf, shouldToggleEnabled)
            shouldToggleEnabled = nil
            return
        end
        if (ae_enablemod) then
            local successflag, retvalue = pcall(OnUpdate, salf, dt)
            if not successflag then
                if letsDoDebug then
                    print(retvalue)
                end
            end
        end
    end
end
AddClassPostConstruct("components/playercontroller", addPlayerController)

 

Edited by spm1999316
25 minutes ago, spm1999316 said:

So I'm assuming the issue is that item.components.fueled is not accessible client side

Ok try this, the fueled component seems to add/remove a tag to the instance its attached to whenever it's depleted on fuel called "fueldepleted", instead of checking for the fueled component, just try changing the check function to

function(item)
    if item ~= nil and item.prefab == "lantern" and item:HasTag("fueldepleted") then         
        return true
    end
end

since I'm certain clients should still be able to see any tags on the target, plus that should be deterministic enough for you to be accurate

  • Thanks 1
29 minutes ago, w00tyd00d said:

Ok try this, the fueled component seems to add/remove a tag to the instance its attached to whenever it's depleted on fuel called "fueldepleted", instead of checking for the fueled component, just try changing the check function to


function(item)
    if item ~= nil and item.prefab == "lantern" and item:HasTag("fueldepleted") then         
        return true
    end
end

since I'm certain clients should still be able to see any tags on the target, plus that should be deterministic enough for you to be accurate

Perfect! It works as expected, thanks for the help!

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