GalaxySugar Posted July 7, 2021 Share Posted July 7, 2021 (edited) 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 July 7, 2021 by GalaxySugar Formatting Link to comment Share on other sites More sharing options...
Monti18 Posted July 7, 2021 Share Posted July 7, 2021 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 1 Link to comment Share on other sites More sharing options...
GalaxySugar Posted July 7, 2021 Author Share Posted July 7, 2021 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 More sharing options...
Monti18 Posted July 7, 2021 Share Posted July 7, 2021 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. 1 Link to comment Share on other sites More sharing options...
GalaxySugar Posted July 7, 2021 Author Share Posted July 7, 2021 Ah, that explains it. thanks! works exactly how I need it to now! Link to comment Share on other sites More sharing options...
GalaxySugar Posted July 7, 2021 Author Share Posted July 7, 2021 (edited) Oh, so I just noticed that going through the eater component doesn't trigger the eating states. anyway to fix that? Edited July 7, 2021 by GalaxySugar Link to comment Share on other sites More sharing options...
Monti18 Posted July 7, 2021 Share Posted July 7, 2021 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. 1 Link to comment Share on other sites More sharing options...
GalaxySugar Posted July 7, 2021 Author Share Posted July 7, 2021 Works fine for unstacked foods but if theres more than 1 in a stack the character will immediately consume a second before the entire stack vanishes. nothing in the log seems to indicate why. Link to comment Share on other sites More sharing options...
Monti18 Posted July 7, 2021 Share Posted July 7, 2021 Try removing the inst.components.eater:Eat line and see if it works. I just saw that the stategraph also calls Eat so it shouldn't be needed to be written there, perhaps that's the problem. 1 Link to comment Share on other sites More sharing options...
GalaxySugar Posted July 7, 2021 Author Share Posted July 7, 2021 (edited) Doing that fixed eating a second food but the whole stack still vanishes right after. Edited July 7, 2021 by GalaxySugar Link to comment Share on other sites More sharing options...
Monti18 Posted July 7, 2021 Share Posted July 7, 2021 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. 1 Link to comment Share on other sites More sharing options...
GalaxySugar Posted July 7, 2021 Author Share Posted July 7, 2021 Works completely fine unless the player is moving around on a dedicated server. they'll continue to move before rubberbanding back into position. Link to comment Share on other sites More sharing options...
Monti18 Posted July 7, 2021 Share Posted July 7, 2021 (edited) 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 July 7, 2021 by Monti18 1 Link to comment Share on other sites More sharing options...
GalaxySugar Posted July 7, 2021 Author Share Posted July 7, 2021 Finally, everything works lmao. Thanks so much for all your help, I really appreciate it! Link to comment Share on other sites More sharing options...
GalaxySugar Posted July 8, 2021 Author Share Posted July 8, 2021 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 More sharing options...
Monti18 Posted July 8, 2021 Share Posted July 8, 2021 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 1 Link to comment Share on other sites More sharing options...
GalaxySugar Posted July 8, 2021 Author Share Posted July 8, 2021 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 More sharing options...
Monti18 Posted July 8, 2021 Share Posted July 8, 2021 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? 1 Link to comment Share on other sites More sharing options...
GalaxySugar Posted July 8, 2021 Author Share Posted July 8, 2021 (edited) 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 July 8, 2021 by GalaxySugar formatting again lol Link to comment Share on other sites More sharing options...
Monti18 Posted July 8, 2021 Share Posted July 8, 2021 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. 1 Link to comment Share on other sites More sharing options...
GalaxySugar Posted July 8, 2021 Author Share Posted July 8, 2021 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 More sharing options...
Monti18 Posted July 8, 2021 Share Posted July 8, 2021 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. 1 Link to comment Share on other sites More sharing options...
GalaxySugar Posted July 8, 2021 Author Share Posted July 8, 2021 Oh! sorry, I completely blanked on that lmao. spawning a bundle with the items works again but now it also spawns a copy of the items where the action was preformed... which I can't find any indication on why? Link to comment Share on other sites More sharing options...
Monti18 Posted July 8, 2021 Share Posted July 8, 2021 That happens to the best I don't really understand what you mean, do you mean the items are duplicated? 1 Link to comment Share on other sites More sharing options...
GalaxySugar Posted July 8, 2021 Author Share Posted July 8, 2021 Yeah, it spawns a copy of all the items in the bundle on the floor Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now