Jump to content

Trouble with tables


Recommended Posts

Hello everyone! I'm trying to make a character eat a random stat damaging food in their inventory, so far I've come up with this.

local function AutoEat(inst)
    if inst.autoeat_test then
        inst.autoeat_test:Cancel()
        inst.autoeat_test = nil
    end
	
    local badfoods = {}
	
     for k, v in pairs(inst.components.inventory:ReferenceAllItems()) do
        if v and v.components.edible then 
            if v.components.edible.healthvalue < 0 
            or v.components.edible.sanityvalue < 0 
            or v.components.edible.hungervalue < 0 then
                table.insert(badfoods, v.prefab)
                print("Added "..v.prefab.." to table")
            end
        end
    end
	
    if badfoods ~= nil then
        print("we have "..#badfoods.." badfoods")
        print("... Now what?")
    end
  
    inst.autoeat_test = inst:DoTaskInTime(10, function() AutoEat(inst) end)
end

They have no issue logging the foods into the table, but I'm a bit stumped on how to actually get them to eat one of the foods.

Edited by GalaxySugar
Formatting
Link to comment
Share on other sites

I thnk you can try to use the component Eater.

It has a function Eat, which is used when a character eats something.

If you want to make the character eat a random food from badfoods, you can run a function like this:

local food = badfoods[math.random(#badfoods)]
inst.components.eater:Eat(food)

Also pay attention that badfoods will never be nil, as you set it to an empty table and empty tables are not nil. To check if a table is empty, you need to run

if next(badfoods) ~= nil then

 

  • Like 1
Link to comment
Share on other sites

Tried the eater component and it crashed.

Quote

[00:01:05]: [string "scripts/components/eater.lua"]:249: attempt to index field 'components' (a nil value)
LUA ERROR stack traceback:
    scripts/components/eater.lua:249 in () ? (Lua) <248-262>
    =(tail call):-1 in ()  (tail) <-1--1>
    scripts/components/eater.lua:187 in (method) Eat (Lua) <182-246>
    ../mods/Character-Test/scripts/prefabs/watcoon.lua:49 in (upvalue) AutoEat (Lua) <27-53>
    ../mods/Character-Test/scripts/prefabs/watcoon.lua:86 in (field) fn (Lua) <86-86>
    scripts/scheduler.lua:177 in (method) OnTick (Lua) <155-207>
    scripts/scheduler.lua:371 in (global) RunScheduler (Lua) <369-377>
    scripts/update.lua:185 in () ? (Lua) <164-243>

 

Link to comment
Share on other sites

The problem is that you only insert the prefab into the table and not the entity of the food. That's why it crashes, as the string has no components. You need to change

table.insert(badfoods, v.prefab)

to

table.insert(badfoods, v)

This way, you save the entity of the food in the table and then you can also eat it.

  • Like 1
Link to comment
Share on other sites

Try this:

inst.sg:GoToState(food.components.edible.foodtype == FOODTYPE.MEAT and "eat" or "quickeat",{ feed = food, feeder = inst })

Add this after inst.components.eater:Eat. 

This is taken from actions.lua from the action feedplayer, where the state is triggered when feeding a player.

  • Like 1
Link to comment
Share on other sites

Strange...

Then try 

inst.sg:GoToState(food.components.edible.foodtype == FOODTYPE.MEAT and "eat" or "quickeat")
inst.components.eater:Eat(food)

I removed the data for the stategraph, I'm not sure if he will try to do the animation, but I think he should. Then the food gets eaten normally like before.

  • Like 1
Link to comment
Share on other sites

Ah this is always the problems with clients and movement prediction. As the client doesn't know yet what is happening, it thinks that you are still running, which causes the rubberbanding when it knows that the character stopped to eat. A quick fix is probably to just disable movement prediction, otherwise I'm not sure, perhaps try to add before inst.sg:GoToState this

		inst.components.locomotor:Clear()
                inst:ClearBufferedAction()
                inst.sg:AddStateTag("pausepredict")
                if inst.components.playercontroller ~= nil then
                    inst.components.playercontroller:RemotePausePrediction()
                end

This is copied from SGWilson from the state eat if the food is not nil. Seems like it stops the prediction, try if this works.

Edited by Monti18
  • Like 1
Link to comment
Share on other sites

Got a new problem thats also table related and I haven't messed around with saving or loading data that much so, how can I get my character to save and load a table so that it can be used if they leave and rejoin or if the server restarts?

 

 

 

Link to comment
Share on other sites

It's the same way as you would save other data:

local function OnSave(inst,data)
  	data.table = inst.table
end

local function OnLoad(inst,data)
	if data ~= nil then
    	if data.table ~= nil then
      		inst.table = data.table
      	end
    end
end

--master postinit

inst.OnLoad = OnLoad
inst.OnSave = OnSave

 

  • Like 1
Link to comment
Share on other sites

I've actually tried that already, it just crashes when it saves.

Spoiler

[00:02:25]: [string "scripts/dumper.lua"]:112: Cannot dump userdata (Transform (2EAE0608) - unknown)
LUA ERROR stack traceback:
    =[C]:-1 in (global) error (C) <-1--1>
    scripts/dumper.lua:112 in () ? (Lua) <98-113>
    =(tail call):-1 in ()  (tail) <-1--1>
    scripts/dumper.lua:151 in () ? (Lua) <141-159>
    =(tail call):-1 in ()  (tail) <-1--1>
    scripts/dumper.lua:151 in () ? (Lua) <141-159>
    =(tail call):-1 in ()  (tail) <-1--1>
    scripts/dumper.lua:151 in () ? (Lua) <141-159>
    =(tail call):-1 in ()  (tail) <-1--1>
    scripts/dumper.lua:151 in () ? (Lua) <141-159>
    =(tail call):-1 in ()  (tail) <-1--1>
    scripts/dumper.lua:225 in (global) DataDumper (Lua) <77-245>
    scripts/networking.lua:282 in (global) SerializeUserSession (Lua) <278-295>
    scripts/mainfunctions.lua:906 in (global) SaveGame (Lua) <812-975>
    scripts/shardindex.lua:314 in (method) SaveCurrent (Lua) <302-315>
    scripts/components/autosaver.lua:85 in (field) fn (Lua) <59-87>
    scripts/scheduler.lua:177 in (method) OnTick (Lua) <155-207>
    scripts/scheduler.lua:371 in (global) RunScheduler (Lua) <369-377>
    scripts/update.lua:185 in () ? (Lua) <164-243>

 

I should probably clarify that this table is used to store deleted items for later use.

Link to comment
Share on other sites

Ah this is what you are trying to accomplish! As you saw, you cannot save the entity. Could you post the function that saves the items in the table? So you save an item in the table and then delete it if I understand it correctly?

  • Like 1
Link to comment
Share on other sites

AddAction("FAKE_EAT", "Eat", function(act)
    if act.invobject.components.stackable ~= nil then
        local item = act.invobject.components.stackable:Get(1)
        table.insert(act.doer.stored_items, item)
        item:Remove()
        return true
    else
        local item = act.invobject
        table.insert(act.doer.stored_items, item)
        item:Remove()
        return true
    end
end)

I've been using a action to just insert them into the table when done.

Edited by GalaxySugar
formatting again lol
Link to comment
Share on other sites

I think the problem there is that you save the item in the table, but still remove it from the game, so it won't be really saved in the table.

To get around this, you can use the function GetSaveRecord() and SpawnSaveRecord()

AddAction("FAKE_EAT", "Eat", function(act)
    if act.invobject.components.stackable ~= nil then
		local item = act.invobject.components.stackable:Get(1)
        local item_saved = item:GetSaveRecord()
        table.insert(act.doer.stored_items, item_saved)
		item.components.inventoryitem:RemoveFromOwner()
        return true
	else
		local item = act.invobject
        local item_saved = item:GetSaveRecord()
        table.insert(act.doer.stored_items, item_saved)
		item:Remove()
        return true
	end
end)

Try if this works, as you now have saved the item as something that be saved and loaded by the game. If you want to use the item at a later time, use item:SpawnSaveRecord() to spawn it again into the world.

  • Like 1
Link to comment
Share on other sites

ah, it works to save and load but now it crashes with the function the character uses to spawn the items in a bundle

The log:

LUA ERROR stack traceback:
    scripts/components/unwrappable.lua:38 in (method) WrapItems (Lua) <33-45>
    ../mods/Whiskers-The-catoon/scripts/prefabs/watcoon.lua:91 in (upvalue) SpawnBundle (Lua) <74-96>
    ../mods/Whiskers-The-catoon/scripts/prefabs/watcoon.lua:162 in (local) fn (Lua) <138-166>
    scripts/entityscript.lua:1047 in (method) PushEvent (Lua) <1034-1061>
    scripts/components/eater.lua:221 in () ? (Lua) <182-246>
    =(tail call):-1 in ()  (tail) <-1--1>
    scripts/bufferedaction.lua:25 in (method) Do (Lua) <21-35>
    scripts/entityscript.lua:1325 in (method) PerformBufferedAction (Lua) <1312-1335>
    scripts/stategraphs/SGwilson.lua:4230 in (field) fn (Lua) <4228-4236>
    scripts/stategraph.lua:572 in (method) UpdateState (Lua) <540-584>
    scripts/stategraph.lua:611 in (method) Update (Lua) <603-631>
    scripts/stategraph.lua:128 in (method) Update (Lua) <109-153>
    scripts/update.lua:233 in () ? (Lua) <164-243>

The character function:

local function SpawnBundle(inst)
    local items = {}
    for i, v in ipairs(inst.stored_items) do
        table.insert(items, v)
    end
    for i, v in ipairs(items) do
        if type(v) == "string" then
            items[i] = SpawnPrefab(v)
        end
    end

    local bundle = SpawnPrefab("bundle")
    bundle.components.unwrappable:WrapItems(items)
    inst.components.inventory:GiveItem(bundle)
end

 

Link to comment
Share on other sites

As I told you, the item is now saved in another way, you will need to respawn it by calling SpawnSaveRecord.

local function SpawnBundle(inst)
    local items = {}
    for i, v in ipairs(inst.stored_items) do
    	local spawned_item =  SpawnSaveRecord(v)
        table.insert(items, spawned_item)
    end

    local bundle = SpawnPrefab("bundle")
    bundle.components.unwrappable:WrapItems(items)
    inst.components.inventory:GiveItem(bundle)
end

I think this should do it, you don't need to iterate twice through the table to make it spawnable.

  • Like 1
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...