ShinyMoogle Posted October 20, 2019 Share Posted October 20, 2019 I'm throwing in the towel on this one, but I'm sure it's something minor that I'm managing to overlook somehow... I've created a fueled machine which is supposed to accept a custom fuel type. Currently, this can be either a new custom item which provides a large amount of fuel, or plain Honey, which adds a small amount but is more readily accessible. The custom fuel is working perfectly as intended. However, the machine simply will not accept Honey as fuel, despite me adding the fueled component to Honey via AddPrefabPostInit and setting the fuel type accordingly. I've pulled out some of the relevant code snippets below: Fueled machine main prefab function local function fn(Sim) local inst = CreateEntity() local modnameFancy = "Pandora" local modnameActual = KnownModIndex:GetModActualName(modnameFancy) local craftrate if modnameActual == nil then print(string.format("Mod '%s' not found", modnameFancy)) craftrate = GUMMIMAKER_MAKE_RATE else craftrate = GetModConfigData("gummirate", modnameActual) end inst.entity:AddNetwork() inst.entity:AddTransform() inst.entity:AddAnimState() inst.entity:AddSoundEmitter() inst.AnimState:SetBank("gummimaker") inst.AnimState:SetBuild("gummimaker") MakeObstaclePhysics(inst, .4) inst:AddTag("structure") inst:AddTag("fridge") inst.entity:SetPristine() if not TheWorld.ismastersim then inst:DoTaskInTime(0.1, function(inst) inst.replica.container:WidgetSetup("treasurechest") end) return inst end inst:AddComponent("lootdropper") inst:AddComponent("machine") inst.components.machine.turnonfn = TurnOn inst.components.machine.turnofffn = TurnOff inst.components.machine.caninteractfn = CanInteract inst.components.machine.cooldowntime = 0.5 inst:AddComponent("container") inst.components.container:WidgetSetup("treasurechest") inst.components.container.onopenfn = onopen inst.components.container.onclosefn = onclose inst:AddComponent("fueled") inst.components.fueled.fueltype = FUELTYPE.SWEETDREAM inst.components.fueled.maxfuel = GUMMIMAKER_FUEL_MAX inst.components.fueled.accepting = true inst.components.fueled:SetSections(4) inst.components.fueled:SetDepletedFn(OnFuelEmpty) inst.components.fueled:SetTakeFuelFn(ontakefuelfn) inst.components.fueled:InitializeFuelLevel(GUMMIMAKER_FUEL_MAX/2) inst.components.fueled:StartConsuming() inst:AddComponent("inspectable") inst.components.inspectable.getstatus = getstatus inst:AddComponent("workable") inst.components.workable:SetWorkAction(ACTIONS.HAMMER) inst.components.workable:SetWorkLeft(4) inst.components.workable:SetOnFinishCallback(onhammered) inst.components.workable:SetOnWorkCallback(onhit) -- Set the amount of time it takes to create a gummi inst.craftrate = TUNING.TOTAL_DAY_TIME / craftrate inst:ListenForEvent("onbuilt", onbuilt) return inst end Working Custom Fuel local assets = { Asset("ANIM", "anim/dreamfuel.zip"), Asset("ATLAS", "images/inventoryimages/dreamfuel.xml"), Asset("IMAGE", "images/inventoryimages/dreamfuel.tex"), } local prefabs = {} local function takenap(inst, time) if inst:HasTag("player") then inst:PushEvent("yawn", { grogginess = 4, knockoutduration = time + math.random() }) elseif inst.components.sleeper ~= nil then inst.components.sleeper:AddSleepiness(7, time + math.random()) elseif inst.components.grogginess ~= nil then inst.components.grogginess:AddGrogginess(4, time + math.random()) else ins:PushEvent("knockedout") end end local function oneat(inst, eater) eater:DoTaskInTime(0.5, function() takenap(eater, TUNING.MANDRAKE_SLEEP_TIME*2) end) end local function fn() local inst = CreateEntity() inst.entity:AddTransform() inst.entity:AddAnimState() inst.entity:AddNetwork() MakeInventoryPhysics(inst) inst.AnimState:SetBank("dreamfuel") inst.AnimState:SetBuild("dreamfuel") inst.AnimState:PlayAnimation("idle", true) inst.entity:SetPristine() if not TheWorld.ismastersim then return inst end inst:AddComponent("edible") inst.components.edible.healthvalue = 0 inst.components.edible.hungervalue = 0 inst.components.edible.sanityvalue = TUNING.SANITY_SMALL inst.components.edible.foodtype = FOODTYPE.GENERIC inst.components.edible:SetOnEatenFn(oneat) inst:AddComponent("stackable") inst.components.stackable.maxsize = TUNING.STACK_SIZE_SMALLITEM inst:AddComponent("inspectable") inst:AddComponent("fuel") inst.components.fuel.fueltype = FUELTYPE.SWEETDREAM inst.components.fuel.fuelvalue = TUNING.LARGE_FUEL * 2 print("Whipped Dream fuel type: "..FUELTYPE.SWEETDREAM) MakeHauntableLaunch(inst) inst:AddComponent("inventoryitem") inst.components.inventoryitem.atlasname = "images/inventoryimages/dreamfuel.xml" return inst end return Prefab("dreamfuel", fn, assets) AddPrefabPostInit in modmain.lua -- Allow honey to be used as fuel for the Confectionary Station -- Also define new fuel here GLOBAL.FUELTYPE.SWEETDREAM = "SWEETDREAM" AddPrefabPostInit("honey", function(inst) --inst:AddTag(GLOBAL.FUELTYPE.SWEETDREAM.."_fuel") if not GLOBAL.TheWorld.ismastersim then return end --print("Attempting to add fuel component to honey") inst:AddComponent("fuel") inst.components.fuel.fueltype = GLOBAL.FUELTYPE.SWEETDREAM inst.components.fuel.fuelvalue = GLOBAL.TUNING.MED_FUEL --print("Fuel type added: "..inst.components.fuel.fueltype) end) It seems like the component is being added to Honey and the right fuel type is being verified with that last print statement, but it's still not being accepted as valid fuel for the machine. I don't think I'm doing anything differently here from the custom fuel item, so I have no idea where the hangup is! My only other guess was that adding fuel isn't registering as a valid action in componentactions.lua, which seems to check for a matching tag, but adding that in manually didn't work out either. From componentactions.lua for k, v in pairs(FUELTYPE) do if inst:HasTag(v.."_fuel") then if target:HasTag(v.."_fueled") then table.insert(actions, inst:GetIsWet() and ACTIONS.ADDWETFUEL or ACTIONS.ADDFUEL) end return end end So... I'm stumped. Anyone have any insight? I've attached my modmain.lua and relevant prefab files if you need to see the big picture. modmain.lua dreamfuel.lua gummimaker.lua Link to comment Share on other sites More sharing options...
Serpens Posted October 20, 2019 Share Posted October 20, 2019 At first look everything looks right. you can add more prints/print some things ingame to. So check if the fueltype and tags are really there while being ingame. you can use c_select() and hover over the thing with mouse. Or use c_findnext(prefab) to use the things within console. Link to comment Share on other sites More sharing options...
ShinyMoogle Posted October 20, 2019 Author Share Posted October 20, 2019 (edited) Thanks! I never knew those console commands were available, that's helpful. Print results were... as expected, I suppose? Component seems to have been added properly, necessary tags are there, the right fuel type is assigned... but the machine just doesn't want to take it. Is it possible that the container component is interfering somehow and getting prioritized as an action instead of adding fuel? Doesn't really make sense that it would only happen for Honey and not my custom fuel though, given that they can both be stored inside. [00:05:46]: [(KU_ZFa8MGsw) shinymoogle] ReceiveRemoteExecute(print(c_select().components.fuel == nil)) @(370.42, -114.55) [00:05:46]: Selected 115851 - honey [00:05:46]: false [00:06:11]: [(KU_ZFa8MGsw) shinymoogle] ReceiveRemoteExecute(print(c_select().components.fuel.fueltype)) @(370.62, -114.53) [00:06:11]: Selected 115851 - honey [00:06:11]: SWEETDREAM [00:06:34]: [(KU_ZFa8MGsw) shinymoogle] ReceiveRemoteExecute(print(c_select().components.fuel.fueltype)) @(369.95, -112.87) [00:06:34]: Selected 116009 - dreamfuel [00:06:34]: SWEETDREAM [00:07:35]: [(KU_ZFa8MGsw) shinymoogle] ReceiveRemoteExecute(print(c_select().components.fueled.fueltype)) @(368.89, -117.79) [00:07:35]: Selected 108929 - gummimaker [00:07:35]: SWEETDREAM [00:08:38]: [(KU_ZFa8MGsw) shinymoogle] ReceiveRemoteExecute(print(c_select():HasTag("SWEETDREAM_fuel"))) @(372.26, -116.00) [00:08:38]: Selected 116305 - honey [00:08:38]: true [00:09:44]: [(KU_ZFa8MGsw) shinymoogle] ReceiveRemoteExecute(print(c_select():HasTag("SWEETDREAM_fueled"))) @(369.27, -117.78) [00:09:44]: Selected 108929 - gummimaker [00:09:44]: true Edited October 20, 2019 by ShinyMoogle Spaced out the log for readability Link to comment Share on other sites More sharing options...
Serpens Posted October 20, 2019 Share Posted October 20, 2019 you can find all predefined consolecommands within consolecommands.lua in scripts folder of the game To make sure it is indeed caused by the componentactions you can add this to modmain: AddComponentAction("USEITEM", "fuel", function(inst, doer, target, actions) -- this wont overwrite anything, it is just an additional check if not (doer.replica.rider ~= nil and doer.replica.rider:IsRiding()) or (target.replica.inventoryitem ~= nil and target.replica.inventoryitem:IsGrandOwner(doer)) then if inst.prefab ~= "spoiled_food" and inst:HasTag("quagmire_stewable") and target:HasTag("quagmire_stewer") and target.replica.container ~= nil and target.replica.container:IsOpenedBy(doer) then print("is returning without checking FUEL",inst) return end for k, v in pairs(GLOBAL.FUELTYPE) do if inst:HasTag(v.."_fuel") then if target:HasTag(v.."_fueled") then table.insert(actions, inst:GetIsWet() and ACTIONS.ADDWETFUEL or ACTIONS.ADDFUEL) print("ADDFUEL action should was added",inst) end return end end end print("end of function",inst) end) you can add more prints if neccessary. In case the action is not added to the actions table and you can not fix it by changing your previous code, you can also use the code above to simply add the action yourself. So lets assume this is called "print("is returning without checking FUEL",inst)", then you could simply remove the first part of the code above, to only have the "for ... FUELTYPE..." function in it. This will then be executed after the checks written in componentactions.lua and will add your action. (so AddComponentAction is only adding, not overwriting) Link to comment Share on other sites More sharing options...
ShinyMoogle Posted October 25, 2019 Author Share Posted October 25, 2019 (edited) Alright, with that and a little further troubleshooting, I think I've managed to pinpoint the problem. The action does get added properly to the actions table... [00:01:02]: ADDFUEL action should was added 100968 - honey [00:01:04]: ADDFUEL action should was added 103455 - dreamfuel ...yet still doesn't show up when trying to use Honey on the machine. So I took the nuclear option and temporarily cut out all the container component functions from the machine and tested again, and now it will accept Honey as fuel. If that means what I think it means, the STORE action is somehow taking precedent over ADDFUEL and preventing that action. Checking in actions.lua, neither STORE nor ADDFUEL have a priority set, so maybe they're just randomly jostling for main actionable action. I don't understand why my custom fuel would work though, considering that it's also able to be stored in the container. Weird. Problem found! But... not solved. Since the machine is meant to automatically manufacture and deposit items in its storage compartment, I do want to keep that container component, which seems to be interfering with adding fuel. What's the best thing to do in this case? Should I (can I?) override the existing ACTIONS.ADDFUEL and ACTIONS.ADDWETFUEL to give them +1 priority? Is that likely to cause unintended consequences in the game or other mods? I'm not sure if setting exclusions on what the container can accept will work, since STORE is still a valid action for putting random junk in iceboxes. Edited October 25, 2019 by ShinyMoogle Link to comment Share on other sites More sharing options...
Serpens Posted October 25, 2019 Share Posted October 25, 2019 I have the nearly same problem here: https://github.com/Serpens66/DST-Evolving-Maxwell-Shadows (written in readme) There I have the problem with the Feedplayer and store action. And I decided against modifying original priorities, because who know whcih side effects this will have (the priority is a problem although feed action is rightclick and store action is leftclick! This may be considered a game bug) In my case the decision was to not allow storing nightmarefuel withing the container anymore, so feeding is working. Maybe this is also a valid solution for you? In case you also have left and right click and it still does not work we could try to file a bugreport about it and hope Klei fixes this, so actions with same priority but one with left and one with right click can work simultanously. Another way would be to design your own action. But both, store and addfuel have both alot of code you would need to copy... not sure which one might be the best choice. Other than that I dont have an idea currently =/ Link to comment Share on other sites More sharing options...
ShinyMoogle Posted October 25, 2019 Author Share Posted October 25, 2019 (edited) They're all left-click actions, I think. Though you'd think that with two different actions it would be possible to auto-map the second one to the secondary mouse button... Well, good to know it's not an isolated problem. Not allowing storing Honey in the container would work great. I didn't really intend it to be used as general storage, anyway. Did you handle that in container.itemtestfn, or somewhere else? Edited October 25, 2019 by ShinyMoogle Link to comment Share on other sites More sharing options...
Serpens Posted October 25, 2019 Share Posted October 25, 2019 yes, itemtestfn , I called it " ContainerShouldAcceptItem " here: https://github.com/Serpens66/DST-Evolving-Maxwell-Shadows/blob/master/scripts/BM_helpers.lua Link to comment Share on other sites More sharing options...
ShinyMoogle Posted October 27, 2019 Author Share Posted October 27, 2019 (edited) I gave creating a custom widget with a specific itemtestfn a try, but unfortunately that doesn't look like it's working. I think that the action is being assigned to the mouse button before the the container checks to see if it's valid, which means the STORE action is still taking precedence over adding fuel - it'll just reject the item when attempting to store it. It's starting to look like if I want to make it work as fuel, I'll need to tweak how the action selection happens... Hmm. Well, maybe I can try something different. I'll have the machine not accept direct fuel input at all, but instead check to see if eligible fuel is stored inside its container and then automatically consume fuel directly from storage while it's on. Might be an easier solution that doesn't require messing with base game functions. Edited October 27, 2019 by ShinyMoogle Link to comment Share on other sites More sharing options...
Serpens Posted October 27, 2019 Share Posted October 27, 2019 ah yes, I did not only used itemtstfn, sry , I also do: AddComponentAction("USEITEM", "inventoryitem", function(inst, doer, target, actions, right) if target.prefab=="shadowduelist" or helpers.isshadowworker(target.prefab) then for k, v in pairs(GLOBAL.FOODTYPE) do if inst:HasTag("edible_"..v) and target:HasTag(v.."_eater") then GLOBAL.RemoveByValue(actions, GLOBAL.ACTIONS.STORE) -- the items that are edible, will not be stored in container! end end end end) So everything my shadow prefab can eat, is not allowed to be stored inside of shadow, so I remove the STORE action from the actions list. If you still want to go the other way with consuming what is inside, I also have a nice function for this local function Findandconsume_prefab(inst,amount,prefab,onlyfind) -- tries to consume amount prefab from his container and returns the actual amount consumed local fuelconsumed = 0 local item = nil if amount>0 then for i = 1, inst.components.container:GetNumSlots() do item = inst.components.container:GetItemInSlot(i) if item~=nil and item:IsValid() and item.prefab==prefab then if onlyfind=="onlyfind" then return item end if item.components.stackable~=nil and item.components.stackable:IsStack() then -- is a stack if onlyfind==nil then while fuelconsumed<amount and item.components.stackable:StackSize() >= 1 and item:IsValid() do fuelconsumed = fuelconsumed + 1 if item.components.stackable:StackSize()==1 then inst.components.container:RemoveItem(item):Remove() -- remove the last one else item.components.stackable:SetStackSize(item.components.stackable:StackSize() - 1) -- reduce the stacksize end end elseif onlyfind=="findstackspace" and not item.components.stackable:IsFull() then return item -- find a stack that is not full already end elseif onlyfind==nil then -- is no stack fuelconsumed = fuelconsumed + 1 inst.components.container:RemoveItem(item):Remove() elseif item.components.stackable~=nil and onlyfind=="findstackspace" and not item.components.stackable:IsFull() then -- without "IsStack" because 1 cutgrass is no stack, but stackable return item -- find a stack that is not full already end end end end if onlyfind==nil then return fuelconsumed else return false end end Link to comment Share on other sites More sharing options...
ShinyMoogle Posted November 4, 2019 Author Share Posted November 4, 2019 Thanks for the sample code! I got things working (as far as I can tell), but actually ended up handling the fuel consumption a little bit differently due to a few specific considerations: 1: There are multiple valid fuel items, so I wanted the machine to be able to consume any valid fuel item when necessary. That meant using Fueled:TakeFuelItem with a direct reference to the fuel item to be consumed instead of just removing stuff from the container, and a custom search to check for a valid Fuel.fueltype instead of a specific prefab. 2: It turns out that Machine:CanInteract() does... absolutely nothing. It might have at some point in the game's development, but it's apparently not called anywhere in vanilla files outside of the Machine component, and the only thing that governs if a machine can be turned on or off is in componentactions.lua, which won't add the TURNON action if fuel has been depleted. Meaning that even if fuel is otherwise present in container storage, there's no way to get the machine to start consuming it without it already having fuel or modifying the componentaction. So for (1), I created a custom function for Fueled.depleted that will search the container for valid fuel items, then consumes the first one it finds using Fueled.TakeFuelItem. For (2), rather than modifying componentactions, I instead opted to just manually set an "empty" fuel value of 1 for any case where the machine needs to check if it's empty. I'm still not sure when the "fueldepleted" tag gets added, but regardless, this seemed to work well enough. local function HasFuel(inst) return inst.components.container:FindItem(function(item) return item ~= nil and item.components.fuel ~= nil and item.components.fuel.fueltype == FUELTYPE.SWEETDREAM end) ~= nil end -- Turn on machine and start consuming fuel -- Set periodic task to generate gummis local function TurnOn(inst, instant) -- A fuel value of 1 should be considered "empty" for confectionary station purposes -- Since 1 fuel is required to make the machine interactable if inst.components.fueled.currentfuel <= 1 and not HasFuel(inst) then inst.components.talker:Say("INSUFFICIENT SUGAR") inst:DoTaskInTime(0.1, function(inst) inst.components.machine:TurnOff() end) return end inst.machinestate = MACHINESTATES.ON inst.components.fueled:StartConsuming() inst.AnimState:PushAnimation("idle_on") inst.SoundEmitter:PlaySound("dontstarve_DLC001/common/firesupressor_on") inst.gummitask = inst:DoPeriodicTask(inst.craftrate, gummitaskfn) end local function TurnOff(inst, instant) inst.machinestate = MACHINESTATES.OFF inst.components.fueled:StopConsuming() inst.AnimState:PushAnimation("idle_off") inst.SoundEmitter:PlaySound("dontstarve_DLC001/common/firesupressor_off") if inst.gummitask ~= nil then inst.gummitask:Cancel() inst.gummitask = nil end -- Workaround to avoid needing to modify actions -- Machine needs to be fueled in order to be interactable if inst.components.fueled.currentfuel < 1 then inst.components.fueled.currentfuel = 1 end end local function OnFuelEmpty(inst) if HasFuel(inst) then local fuelitem = inst.components.container:FindItem(function(item) return item ~= nil and item.components.fuel ~= nil and item.components.fuel.fueltype == FUELTYPE.SWEETDREAM end) local singlefuel = inst.components.container:RemoveItem(fuelitem, false) inst.components.fueled:TakeFuelItem(singlefuel) else inst.components.machine:TurnOff() end end gummimaker.lua 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