zetake Posted July 12, 2019 Share Posted July 12, 2019 Hi, How can I add my own tag to local function Update in perishable.lua component? I tried adding AddClassPostConstruct function with doing my new local Update funcion, and calling it in new LongUpdate and new StartPerishing in AddClassPostConstruct, but it break the game whatever i try. But when I copy whole perishable.lua to my mod folder it works then, but I don't think I should do this like this. Link to comment Share on other sites More sharing options...
Ultroman Posted July 12, 2019 Share Posted July 12, 2019 2 hours ago, zetake said: But when I copy whole perishable.lua to my mod folder it works then, but I don't think I should do this like this. Nope. Bad practice. 2 hours ago, zetake said: How can I add my own tag to local function Update in perishable.lua component? You cannot change local variables or functions, unless you employ Upvalue Hacker, which should be a last resort. What is it you're trying to accomplish? Perhaps we can find a less intrusive way. Link to comment Share on other sites More sharing options...
zetake Posted July 12, 2019 Author Share Posted July 12, 2019 I want this to work in mainlua. Spoiler local function Update(inst, dt) if inst.components.perishable then local seasonmanager = GetSeasonManager() local modifier = 1 local owner = inst.components.inventoryitem and inst.components.inventoryitem.owner or nil if owner then if owner:HasTag("my_own_tag") then modifier = 200 -- my value | 200 for testing elseif owner:HasTag("fridge") then if inst:HasTag("frozen") and not owner:HasTag("nocool") and not owner:HasTag("lowcool") then modifier = TUNING.PERISH_COLD_FROZEN_MULT else modifier = TUNING.PERISH_FRIDGE_MULT end elseif owner:HasTag("spoiler") and owner:HasTag("poison") then modifier = TUNING.PERISH_POISON_MULT elseif owner:HasTag("spoiler") then modifier = TUNING.PERISH_GROUND_MULT end else modifier = TUNING.PERISH_GROUND_MULT end -- Cool off hot foods over time (faster if in a fridge) if inst.components.edible and inst.components.edible.temperaturedelta and inst.components.edible.temperaturedelta > 0 then if owner and owner:HasTag("fridge") then if not owner:HasTag("nocool") then inst.components.edible.temperatureduration = inst.components.edible.temperatureduration - 1 end elseif seasonmanager and seasonmanager:GetCurrentTemperature() < TUNING.OVERHEAT_TEMP - 5 then inst.components.edible.temperatureduration = inst.components.edible.temperatureduration - .25 end if inst.components.edible.temperatureduration < 0 then inst.components.edible.temperatureduration = 0 end end local mm = GetWorld().components.moisturemanager if mm:IsEntityWet(inst) then modifier = modifier * TUNING.PERISH_WET_MULT end if seasonmanager and seasonmanager:GetCurrentTemperature() < 0 then if inst:HasTag("frozen") and not inst.components.perishable.frozenfiremult then modifier = TUNING.PERISH_COLD_FROZEN_MULT else modifier = modifier * TUNING.PERISH_WINTER_MULT end end if inst.components.perishable.frozenfiremult then modifier = modifier * TUNING.PERISH_FROZEN_FIRE_MULT end if seasonmanager and seasonmanager:GetCurrentTemperature() > TUNING.OVERHEAT_TEMP then modifier = modifier * TUNING.PERISH_SUMMER_MULT end local aporkalypse = GetAporkalypse() if aporkalypse and aporkalypse:IsActive() then modifier = modifier * TUNING.PERISH_APORKALYPSE_MULT end modifier = modifier * TUNING.PERISH_GLOBAL_MULT local old_val = inst.components.perishable.perishremainingtime local delta = dt or (10 + math.random()*FRAMES*8) inst.components.perishable.perishremainingtime = inst.components.perishable.perishremainingtime - delta*modifier if math.floor(old_val*100) ~= math.floor(inst.components.perishable.perishremainingtime*100) then inst:PushEvent("perishchange", {percent = inst.components.perishable:GetPercent()}) end --trigger the next callback if inst.components.perishable.perishremainingtime <= 0 then inst.components.perishable:Perish() end end end AddClassPostConstruct("components/perishable", function( self, owner ) function self:LongUpdate(dt) if self.updatetask then Update(self.inst, dt or 0) end end function self:StartPerishing() if self.updatetask then self.updatetask:Cancel() self.updatetask = nil end local dt = 10 + math.random()*FRAMES*8--math.max( 4, math.min( self.perishtime / 100, 10)) + ( math.random()* FRAMES * 8) if dt > 0 then self.updatetask = self.inst:DoPeriodicTask(dt, Update, math.random()*2, dt) else Update(self.inst, 0) end end end) Or is there better way to change local function Update? Or is there other way to change perishing time of items in some container? Link to comment Share on other sites More sharing options...
Ultroman Posted July 12, 2019 Share Posted July 12, 2019 I think I understand what you're trying to do, but to be sure, could you explain what it is you're trying to do? How many items are we talking? Do you want it to be different depending on which container the item is in? I'd like to know exactly what you're trying to accomplish, without "thinking in code". Link to comment Share on other sites More sharing options...
zetake Posted July 12, 2019 Author Share Posted July 12, 2019 Simple thing. Custom container with custom perishable time. Like Ice Box or Insulated Pack, but with own time setting. Link to comment Share on other sites More sharing options...
Ultroman Posted July 12, 2019 Share Posted July 12, 2019 Wow. This is probably the first time I've seen something that needs the Upvalue Hacker. You need it to access the Update function, so you can extend it, and basically copy much of the existing code, in order to check whether there is an owner, and if that owner is your container prefab, then you do your special code, and if not, you run the original function. Link to comment Share on other sites More sharing options...
zetake Posted July 12, 2019 Author Share Posted July 12, 2019 Eh, my poor, poor, poor coding... Spoiler I forgot about: local FRAMES = GLOBAL.FRAMES local TUNING = GLOBAL.TUNING Didn't change GetSeasonManager(), GetWorld() and GetAporkalypse() to GLOBAL. And small typos in (self, owner), should be (self, inst). With this, it finally works. ;D In my excuse I'm modding only for a couple days with 0 lua knowledge... And I'm learning modding by klei code... not by tutorials, well I seems I don't need vanilla tutorials ;D Link to comment Share on other sites More sharing options...
Ultroman Posted July 13, 2019 Share Posted July 13, 2019 What? What code did you end up using? How did you end up doing this? Link to comment Share on other sites More sharing options...
zetake Posted July 13, 2019 Author Share Posted July 13, 2019 Didn't you read it in my previous post? How? By statements not global, but I guess thanks to your post a looked into log.txt. Because game didn't crash, but only froze and I couldn't see crash log from game. Spoiler local FRAMES = GLOBAL.FRAMES local TUNING = GLOBAL.TUNING local function Update(inst, dt) if inst.components.perishable then local seasonmanager = GLOBAL.GetSeasonManager() local modifier = 1 local owner = inst.components.inventoryitem and inst.components.inventoryitem.owner or nil if owner then if owner:HasTag("my_own_tag") then modifier = 200 -- my own modifer elseif owner:HasTag("fridge") then if inst:HasTag("frozen") and not owner:HasTag("nocool") and not owner:HasTag("lowcool") then modifier = TUNING.PERISH_COLD_FROZEN_MULT else modifier = TUNING.PERISH_FRIDGE_MULT end elseif owner:HasTag("spoiler") and owner:HasTag("poison") then modifier = TUNING.PERISH_POISON_MULT elseif owner:HasTag("spoiler") then modifier = TUNING.PERISH_GROUND_MULT end else modifier = TUNING.PERISH_GROUND_MULT end -- Cool off hot foods over time (faster if in a fridge) if inst.components.edible and inst.components.edible.temperaturedelta and inst.components.edible.temperaturedelta > 0 then if owner and owner:HasTag("fridge") then if not owner:HasTag("nocool") then inst.components.edible.temperatureduration = inst.components.edible.temperatureduration - 1 end elseif seasonmanager and seasonmanager:GetCurrentTemperature() < TUNING.OVERHEAT_TEMP - 5 then inst.components.edible.temperatureduration = inst.components.edible.temperatureduration - .25 end if inst.components.edible.temperatureduration < 0 then inst.components.edible.temperatureduration = 0 end end local mm = GLOBAL.GetWorld().components.moisturemanager if mm:IsEntityWet(inst) then modifier = modifier * TUNING.PERISH_WET_MULT end if seasonmanager and seasonmanager:GetCurrentTemperature() < 0 then if inst:HasTag("frozen") and not inst.components.perishable.frozenfiremult then modifier = TUNING.PERISH_COLD_FROZEN_MULT else modifier = modifier * TUNING.PERISH_WINTER_MULT end end if inst.components.perishable.frozenfiremult then modifier = modifier * TUNING.PERISH_FROZEN_FIRE_MULT end if seasonmanager and seasonmanager:GetCurrentTemperature() > TUNING.OVERHEAT_TEMP then modifier = modifier * TUNING.PERISH_SUMMER_MULT end local aporkalypse = GLOBAL.GetAporkalypse() if aporkalypse and aporkalypse:IsActive() then modifier = modifier * TUNING.PERISH_APORKALYPSE_MULT end modifier = modifier * TUNING.PERISH_GLOBAL_MULT local old_val = inst.components.perishable.perishremainingtime local delta = dt or (10 + math.random()*FRAMES*8) inst.components.perishable.perishremainingtime = inst.components.perishable.perishremainingtime - delta*modifier if math.floor(old_val*100) ~= math.floor(inst.components.perishable.perishremainingtime*100) then inst:PushEvent("perishchange", {percent = inst.components.perishable:GetPercent()}) end --trigger the next callback if inst.components.perishable.perishremainingtime <= 0 then inst.components.perishable:Perish() end end end AddClassPostConstruct("components/perishable", function(self, inst) function self:LongUpdate(dt) if self.updatetask then Update(self.inst, dt or 0) end end function self:StartPerishing() if self.updatetask then self.updatetask:Cancel() self.updatetask = nil end local dt = 10 + math.random()*FRAMES*8--math.max( 4, math.min( self.perishtime / 100, 10)) + ( math.random()* FRAMES * 8) if dt > 0 then self.updatetask = self.inst:DoPeriodicTask(dt, Update, math.random()*2, dt) else Update(self.inst, 0) end end end) And in container prefab. inst:AddTag("my_own_tag") Link to comment Share on other sites More sharing options...
Ultroman Posted July 13, 2019 Share Posted July 13, 2019 1 hour ago, zetake said: Didn't you read it in my previous post? I did, but I also stated earlier that you would have to employ Upvalue Hacker in order to get this to work properly, which is why I was curious as to how you got it to work so quickly. What you've done is essentially overwriting the LongUpdate and StartPerishing functions, which means that any changes made to those functions by any mod loaded before your mod, are completely overwritten. Since we're talking about perishables here, and people love to make changes to perishables, that's going to be a sizable amount of mods which your mod will be incompatible with (as in, your mod will make the other mod crash or not work properly). That's one thing. Another problem: Though I doubt many modders have employed the Upvalue Hacker to extend the local Update function, if they have, you are effectively side-stepping their changes, substituting their altered version of the function with your function. These things may not sound very problematic, but some of the content mods porting things from DS do use the Upvalue Hacker, in order to make the DST components able to handle the DS content. Since many of these contain perishables, it is likely that they have altered the Update function. And A LOT of people use these content mods, because, why not? More content. This is where the Upvalue Hacker would shine, since you can take the current version of the Update function and extend it, instead of completely overwriting it. (I am not 100% sure about this, since I haven't used the Upvalue Hacker, but I think it can do it). I won't tell you what to do with your mod. Just know that you may be in for a storm of bug reports from players, and they'll be confused, because DST will report the conflicting mods as the perpetrators, instead of yours. Link to comment Share on other sites More sharing options...
zetake Posted July 13, 2019 Author Share Posted July 13, 2019 It doesn't matter... One way or another... I mean my mod or other mod, some will have to overrite things... If I could and should do it other way without overriting, then someelse can do it too, and it will be just fine. EDIT: BUUUT wait, I think I can do it like you said... I can check if container is my own tag and then do changed update function, but I'm not sure if I'll be albe to get cointainer... I'll tried it later... Link to comment Share on other sites More sharing options...
Ultroman Posted July 13, 2019 Share Posted July 13, 2019 19 minutes ago, zetake said: It doesn't matter... One way or another... I mean my mod or other mod, some will have to overrite things... If I could and should do it other way without overriting, then someelse can do it too, and it will be just fine. Not true. If everyone extends instead of overwriting, then the chances of incompatibilities are kept at their absolute minimum, while if one person overwrites, the chances are quite high. Link to comment Share on other sites More sharing options...
zetake Posted July 13, 2019 Author Share Posted July 13, 2019 Well, I need function to check if container is custom.if so, call changed update. But, I can't get container or it can't be done from AddClassPostConstruct. EDIT: Well, I don't know why this work in local funtion Update, but not in the funcions directly... Spoiler AddClassPostConstruct("components/perishable", function(self, inst) local _l = self.LongUpdate function self:LongUpdate(dt) local custom = false if self.inst.components.perishable then local owner = self.inst.components.inventoryitem and self.inst.components.inventoryitem.owner or nil if owner then if owner:HasTag("my_own_tag") then custom = true if self.updatetask then Update(self.inst, dt or 0) end else custom = false end else custom = false end else custom = false end if not custom then _l(self, inst, dt) end end local _s = self.StartPerishing function self:StartPerishing() local custom = false if self.inst.components.perishable then local owner = self.inst.components.inventoryitem and self.inst.components.inventoryitem.owner or nil if owner then if owner:HasTag("my_own_tag") then custom = true if self.updatetask then self.updatetask:Cancel() self.updatetask = nil end local dt = 10 + math.random()*FRAMES*8--math.max( 4, math.min( self.perishtime / 100, 10)) + ( math.random()* FRAMES * 8) if dt > 0 then self.updatetask = self.inst:DoPeriodicTask(dt, Update, math.random()*2, dt) else Update(self.inst, 0) end else custom = false end else custom = false end else custom = false end if not custom then _s(self, inst) end end end) So, it's owner issue or AddClassPostConstruct? P.S: Script works, but it doesn't update in game or doesn't get owner, IDK. Link to comment Share on other sites More sharing options...
zetake Posted July 14, 2019 Author Share Posted July 14, 2019 Find alternative, but it requries modyfing local function too... (Almost non used function) So, I got idea how this can be done, but I don't know where to put this and how get container and item for this. Spoiler inst:ListenForEvent("containergotitem", function(inst, data) if data.item.components.perishable then data.item.components.perishable:StartCustomPerishing() end end) inst:ListenForEvent("itemlose", function(inst, data) if data.item.components.perishable then data.item.components.perishable:StartPerishing() end end) Tried this in container but it doesn't get item... Link to comment Share on other sites More sharing options...
Ultroman Posted July 14, 2019 Share Posted July 14, 2019 That is a great entry point you've found there. Both of those eventlisteners should just be put in your own container's fn() function. I, too, have an update...pun intended. I've found a way to use the original Update function for your code! You can retrieve the current Update() function from the updatetask variable on the perishable component. So, what you'll want to do, is make your StartCustomPerishing() function like this: if inst.components.perishable and inst.components.perishable.updatetask then local oldUpdateFunction = inst.components.perishable.updatetask.fn inst.components.perishable.updatetask.fn = function(inst, dt) dt = dt * your_modifier oldUpdateFunction(inst, dt) end end That way you're using the original (or modded) code, and the only thing you're affecting is the dt (deltaTime). The deltaTime directly controls how much the item perishes each frame, so if you apply a modifier to that, you can change it to your liking. The your_modifier variable could be 1.20, which would make all the food perish 20% faster, while 0.80 will make all the food perish 20% slower. Now, you still need to have your two event listeners, because when the "itemlose" listener is triggered, the original StartPerishing() function will restart the perishing with the original code, which is what you want. And your "containergotitem" event listener will correctly trigger your StartCustomPerishing() function. These things are all important, because many things call StartPerishing, e.g., the dryer component (drying rack) and the stewer component (Crockpot). They all need to work properly. We only want to affect things when they're in your container, and leave everything else alone. It is also important to check in your StartCustomPerishin() function whether there is an updatetask running, because if there isn't, then there's probably a reason why the item is not perishing, and so, your container should not make it start perishing. I think all of this should be possible for you to figure out. Link to comment Share on other sites More sharing options...
zetake Posted July 14, 2019 Author Share Posted July 14, 2019 I don't get what you writed. And I need to change whole update, because my container shouldn't be affected by weather or anything else, I need modifer to be edited just by my own value. Function doesn't need to be something else, custom StartPerishing() with calling own update is enough. Because it's stops perishing on start, then do own perishing, that's why there wasn't StopPerishing(). But I don't know how to get for these event listeners an item to change it. I know that this method can work, because this work. Spoiler local function OnPutInInventory(inst, owner) if owner.prefab == "my_own_container" then inst.components.perishable:StartCustomPerishing() end end local function OnRemoved(inst, owner) if owner.prefab == "my_own_container" then inst.components.perishable:StartPerishing() end end But it's only item function and it also shouldn't be overrided, even when it's rarely used. Link to comment Share on other sites More sharing options...
Ultroman Posted July 14, 2019 Share Posted July 14, 2019 Well, if you insist on having your own custom Update() function, I can't stop you. As long as you make sure to store your update task in the updatetask variable, so StartPerishing() automatically stops yours and starts the original, it should be fine. 2 minutes ago, zetake said: But I don't know how to get for these event listeners an item to change it. I think you're missing something here. You don't need to "get an item to change it". The perishable component is on the item, and StartPerishing() is called when the item is created. Your event listeners are triggered whenever any item is put into the container, and that item is passed to your event listener function as data.item. With your listeners and your StartCustomPerishing(), all you need to do, is to make sure that your StartCustomPerishing() is called properly, and thus, it has to be made available. The way you're calling it now, requires you to add that function to all perishable components, which you can do like this (in your modmain): GLOBAL.require "components/perishable" Perishable:StartCustomPerishing() -- Your code end You can also just put the function in your own container prefab as a local function, like this: local function StartCustomPerishing(self) -- your code end And then call it like this: inst:ListenForEvent("containergotitem", function(inst, data) if data.item.components.perishable then StartCustomPerishing(data.item.components.perishable) end end) Link to comment Share on other sites More sharing options...
zetake Posted July 14, 2019 Author Share Posted July 14, 2019 I used your listenforevent code and: attempt to index field 'item' (a nil value) And my StartCustomPerish is in components/perishable as a new function: Spoiler AddClassPostConstruct("components/perishable", function(self, inst) function self:StartCustomPerishing() if self.updatetask then self.updatetask:Cancel() self.updatetask = nil end local dt = 10 + math.random()*FRAMES*8--math.max( 4, math.min( self.perishtime / 100, 10)) + ( math.random()* FRAMES * 8) if dt > 0 then self.updatetask = self.inst:DoPeriodicTask(dt, Update, math.random()*2, dt) else Update(self.inst, 0) end end end) Link to comment Share on other sites More sharing options...
Ultroman Posted July 15, 2019 Share Posted July 15, 2019 Where is you custom Update function? And where did you put the event listener code? And did you check it after copy/pasting it? Please post the whole log. The stacktrace is important, but in this case, what's even more important is that I can see the code you've written, otherwise I don't have a chance. Link to comment Share on other sites More sharing options...
zetake Posted July 15, 2019 Author Share Posted July 15, 2019 Custom Update functon is in modmain and StartCustomPerish is there too... I put listener in local function fn(Sim) of my custom container prefab. Well, I didn't have crash this time, but when I exit game it's sucks all of my ram... -.- Perishing doesn't work, here's a log.txt. Spoiler inst:ListenForEvent("containergotitem", function(inst, data) if data.item.components.perishable then data.item.components.perishable:StartCustomPerishing() end end) P.S: Maybe I should just add tag fridge and frozen to container to disable perishing? Because I need much slower perishing that shouldn't be noticeable in decaded, which means turning it off is ok, but I wanted to do it in don't starve style and do only less spoiling than fridge. But my custom container will be fueled, so it's not much different, only small thing. Link to comment Share on other sites More sharing options...
Ultroman Posted July 16, 2019 Share Posted July 16, 2019 I can't give feedback if I don't see the whole code. Link to comment Share on other sites More sharing options...
zetake Posted July 16, 2019 Author Share Posted July 16, 2019 OK. Desktop.zip Link to comment Share on other sites More sharing options...
Ultroman Posted July 16, 2019 Share Posted July 16, 2019 I can't see anything wrong. It's difficult to help without being able to debug the mod. I can't simulate this code in my head. If you just want lower perishing than the original fridge, using the original function and modifying the incoming deltatime is the easiest way to go. I know you don't want moisture etc. to be influencing the perishing, but sometimes you just gotta take what you can get, unless you're ok with spending a lot of time getting something else to work. Link to comment Share on other sites More sharing options...
zetake Posted July 17, 2019 Author Share Posted July 17, 2019 I was doing bar thing, decided to try with ListenForEvent, and with frustration idk how it works I used print. Turnout itemget triger when container gets item. SOOOOO I MADE THIS WORK LUUUUUUL inst:ListenForEvent("itemget", function(inst, data) local item = data and data.item if item.components.perishable then item.components.perishable:StartISRPerishing() end end) BUUUUTTTT it doesn't change back after removing item from container.... Tried inst:ListenForEvent("itemlose"... That's good, but it gives only slot. >.< I know that I can get item by slot by components.container:GetItemInSlot(slot). But I can't get this component with inst or anything else... Link to comment Share on other sites More sharing options...
Ultroman Posted July 17, 2019 Share Posted July 17, 2019 35 minutes ago, zetake said: That's good, but it gives only slot. >.< I know that I can get item by slot by components.container:GetItemInSlot(slot). But I can't get this component with inst or anything else... The DropItem() function in the inventory component pushes the "dropitem" event, and DropItem() is called when an item is dropped for whatever reason, and I think this is also the case when having an item in the mouse and dropping it on the ground. It's called in many places, so you might have to use it somehow as a way to make sure that if an item is removed, you call StartPerishing() on it. The "dropitem" event always passes along the item being dropped. The "itemlose" event is pushed by both RemoveItem() (called when an item is removed, e.g. consumed, but in very, very many different cases, though not when the item is put into the mouse or subsequently dropped) and SelectActiveItemFromSlot() (when you click an item in your inventory to put it in the mouse). You always get the item in the data passed along with the event, in addition to EITHER a bool called "activeitem", saying whether the item being removed was the active item (item in the mouse) OR you get a "slot" variable telling you which slot the item came from, but you always get the item variable. For reference, these are the ways in which the event is pushed in the code, and one of these are pushed in three places in the inventory component code. self.inst:PushEvent("itemlose", {activeitem = true, item = item}) self.inst:PushEvent("itemlose", {slot = k, item = item}) You have a lot of cases to cover here. I wish you the best of luck trying to find the best combination of checks and events to make this work. Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.
Please be aware that the content of this thread may be outdated and no longer applicable.