[Bug] Crab Disappearing After Eating Monster Meat


Recommended Posts

The health penalty from monster meat may have killed it? Crab have 50 Health, monster meat reduce Health by 20. So 3 MM is enough to kill it.

That's what I thought, but if it killed it it should have dropped something, shouldnt it? If its not a bug and actually a feature than I'm sorry haha

Link to comment
Share on other sites

That's what I thought, but if it killed it it should have dropped something, shouldnt it? If its not a bug and actually a feature than I'm sorry haha

May be it should add a fish morsel into your inventory?

Link to comment
Share on other sites

The health penalty from monster meat may have killed it?

This is precisely the problem. Before Crabs and Wobsters came along, nothing you could feed in your inventory accepted meat items, so there was never--hold it, does this work with Red Caps on Butterflies in RoG too?.. Huh, yes it does. This bug has apparently been around for quite a while. There's no code in the scripts for handling this situation, but of course we can add such code. We can always add such code.

 

I considered various solutions to this problem, and I've settled on the one that I believe is the most all-encompassing so we don't run into anything similar in the future. Here's what I have in mind: if something in inventory should drop some loot on the ground when it dies, it will instead drop the loot in its owner's inventory. A simple concept, right?

 

The correct way to fix this is to modify scripts/components/lootdropper.lua so it always drops loot in an owner's inventory where applicable, but that's kind of a lot of code, so I'm going to post a lazy fix. What I am about to show you is something we in the software development industry refer to as "staggeringly stupid." It's called a "hack", where a patch is made to code in such a way that it technically functions as desired, but the means by which it accomplishes this relies so heavily on the particular implementation (tight coupling) that should anything ever be changed somewhere down the line, the hack will break and cause new problems all over again. Never do this in a production build. This is just a temporary stopgap.

 

That out of the way, I noticed that the global function MakeFeedablePet()--defined in scripts/standardcomponents.lua and used on everything that can starve in your inventory--already has the code needed to handle dropping loot into an owner's inventory, which makes this hack very simple. All we need to do is determine when an entity dies, check whether it's currently in something's inventory, then pretend it starved there instead of got killed...

 

... See what I mean? Staggeringly stupid. Devs, please turn back now. UPDATE: Or turn your attention to this post.

 

The only way an entity can outright die is if it has health and its health drops to zero. This is handled in the Health component, not surprisingly defined in the file scripts/components/health.lua. Way down in Health:SetVal(), circa line 263, we have the following:

if old_percent > 0 and new_percent <= 0 or self:GetMaxHealth() <= 0 then    self.inst:PushEvent("death", {cause=cause})    GetWorld():PushEvent("entity_death", {inst = self.inst, cause=cause} )    if not self.nofadeout then        self.inst:AddTag("NOCLICK")        self.inst.persists = false        self.inst:DoTaskInTime(self.destroytime or 2, destroy)    endend

When something dies, it fires off a couple events and, if configured to do so, automatically fizzles out a couple seconds later. Loot dropping is generally handled by the entity's stategraph, but it won't actually produce any loot if the entity is in inventory, and I didn't bother looking into why... I know, staggeringly stupid of me. We still need those death events to fire off, though, so certain things like Abigail's Flower still function properly.

 

The hack shall hereby be applied beginning at line 268:

if self.inst.components.inventoryitem and self.inst.components.inventoryitem.owner then    if not self.inst.components.perishable then        MakeFeedablePet(self.inst, 0)    end    self.inst.components.perishable:Perish()elseif not self.nofadeout then    self.inst:AddTag("NOCLICK")    self.inst.persists = false    self.inst:DoTaskInTime(self.destroytime or 2, destroy)end

This checks to see whether an entity is currently in somebody's inventory when it dies. If it is, it ensures it's a feedable pet, then promptly forces it to starve to death. Otherwise, if the entity was not in inventory when it died, then it does its usual death mechanic.

Link to comment
Share on other sites

This is precisely the problem. Before Crabs and Wobsters came along, nothing you could feed in your inventory accepted meat items, so there was never--hold it, does this work with Red Caps on Butterflies in RoG too?.. Huh, yes it does. This bug has apparently been around for quite a while. There's no code in the scripts for handling this situation, but of course we can add such code. We can always add such code.

 

I considered various solutions to this problem, and I've settled on the one that I believe is the most all-encompassing so we don't run into anything similar in the future. Here's what I have in mind: if something in inventory should drop some loot on the ground when it dies, it will instead drop the loot in its owner's inventory. A simple concept, right?

 

The correct way to fix this is to modify scripts/components/lootdropper.lua so it always drops loot in an owner's inventory where applicable, but that's kind of a lot of code, so I'm going to post a lazy fix. What I am about to show you is something we in the software development industry refer to as "staggeringly stupid." It's called a "hack", where a patch is made to code in such a way that it technically functions as desired, but the means by which it accomplishes this relies so heavily on the particular implementation (tight coupling) that should anything ever be changed somewhere down the line, the hack will break and cause new problems all over again. Never do this in a production build. This is just a temporary stopgap.

 

That out of the way, I noticed that the global function MakeFeedablePet()--defined in scripts/standardcomponents.lua and used on everything that can starve in your inventory--already has the code needed to handle dropping loot into an owner's inventory, which makes this hack very simple. All we need to do is determine when an entity dies, check whether it's currently in something's inventory, then pretend it starved there instead of got killed...

 

... See what I mean? Staggeringly stupid. Devs, please turn back now.

 

The only way an entity can outright die is if it has health and its health drops to zero. This is handled in the Health component, not surprisingly defined in the file scripts/components/health.lua. Way down in Health:SetVal(), circa line 263, we have the following:

if old_percent > 0 and new_percent <= 0 or self:GetMaxHealth() <= 0 then    self.inst:PushEvent("death", {cause=cause})    GetWorld():PushEvent("entity_death", {inst = self.inst, cause=cause} )    if not self.nofadeout then        self.inst:AddTag("NOCLICK")        self.inst.persists = false        self.inst:DoTaskInTime(self.destroytime or 2, destroy)    endend

When something dies, it fires off a couple events and, if configured to do so, automatically fizzles out a couple seconds later. Loot dropping is generally handled by the entity's stategraph, but it won't actually produce any loot if the entity is in inventory, and I didn't bother looking into why... I know, staggeringly stupid of me. We still need those death events to fire off, though, so certain things like Abigail's Flower still function properly.

 

The hack shall hereby be applied beginning at line 268:

if self.inst.components.inventoryitem and self.inst.components.inventoryitem.owner then    if not self.inst.components.perishable then        MakeFeedablePet(self.inst, 0)    end    self.inst.components.perishable:Perish()elseif not self.nofadeout then    self.inst:AddTag("NOCLICK")    self.inst.persists = false    self.inst:DoTaskInTime(self.destroytime or 2, destroy)end

This checks to see whether an entity is currently in somebody's inventory when it dies. If it is, it ensures it's a feedable pet, then promptly forces it to starve to death. Otherwise, if the entity was not in inventory when it died, then it does its usual death mechanic.

I cant believe I just saw your response. 

I love the way you constantly find out what's the issue. 

Link to comment
Share on other sites

I cant believe I just saw your response. 

I love the way you constantly find out what's the issue.

 

By all means, direct your friends and family to my other thread! (-:

__________

I took the time to solve this bug properly, but like I said, it's kind of a lot of code. I added a new method to LootDropper that will drop its loot into an owner's inventory instead of on the ground, then tweaked Health to call that method when something dies while in inventory.

 

scripts/components/lootdropper.lua, line 213:

-- Fix for critters in inventory being killed by harmful foodsfunction LootDropper:DropLootIntoInventory()    -- Determine this item's owner, if any    local owner = self.inst.components.inventoryitem and         self.inst.components.inventoryitem.owner or nil    if not owner then return end -- No owner    -- Resolve the type of inventory the owner has    if owner.components.inventory then        owner = owner.components.inventory    elseif owner.components.container then        owner = owner.components.container    else        return -- Then how was it holding this item?    end    -- Remove this item from its owner    self.inst.components.inventoryitem:RemoveFromOwner(true)    -- Determine the number of loot rolls to make    local stacksize = 1    if self.inst.components.stackable then        stacksize = self.inst.components.stackable.stacksize    end    -- Drop loot for each item in the stack    for i = 1, stacksize do        local loots = self:GenerateLoot()        -- Add each loot to the owner's inventory        for k, v in pairs(loots) do            owner:GiveItem(SpawnPrefab(v))        end -- loots    end -- iend
scripts/components/health.lua, line 268:

                -- Entity died while in inventory                if self.inst.components.inventoryitem and                   self.inst.components.inventoryitem.owner then                    -- Drop any loot into the owner's inventory                    if self.inst.components.lootdropper then                        self.inst.components.lootdropper:DropLootIntoInventory()                    end                    -- Delete the entity here                    self.inst:Remove()                -- Entity was not in inventory when it died                elseif not self.nofadeout then                    self.inst:AddTag("NOCLICK")                    self.inst.persists = false                    self.inst:DoTaskInTime(self.destroytime or 2, destroy)                end
Link to comment
Share on other sites

 

By all means, direct your friends and family to my other thread! (-:

__________

I took the time to solve this bug properly, but like I said, it's kind of a lot of code. I added a new method to LootDropper that will drop its loot into an owner's inventory instead of on the ground, then tweaked Health to call that method when something dies while in inventory.

 

scripts/components/lootdropper.lua, line 213:

-- Fix for critters in inventory being killed by harmful foodsfunction LootDropper:DropLootIntoInventory()    -- Determine this item's owner, if any    local owner = self.inst.components.inventoryitem and         self.inst.components.inventoryitem.owner or nil    if not owner then return end -- No owner    -- Resolve the type of inventory the owner has    if owner.components.inventory then        owner = owner.components.inventory    elseif owner.components.container then        owner = owner.components.container    else        return -- Then how was it holding this item?    end    -- Remove this item from its owner    self.inst.components.inventoryitem:RemoveFromOwner(true)    -- Determine the number of loot rolls to make    local stacksize = 1    if self.inst.components.stackable then        stacksize = self.inst.components.stackable.stacksize    end    -- Drop loot for each item in the stack    for i = 1, stacksize do        local loots = self:GenerateLoot()        -- Add each loot to the owner's inventory        for k, v in pairs(loots) do            owner:GiveItem(SpawnPrefab(v))        end -- loots    end -- iend
scripts/components/health.lua, line 268:

                -- Entity died while in inventory                if self.inst.components.inventoryitem and                   self.inst.components.inventoryitem.owner then                    -- Drop any loot into the owner's inventory                    if self.inst.components.lootdropper then                        self.inst.components.lootdropper:DropLootIntoInventory()                    end                    -- Delete the entity here                    self.inst:Remove()                -- Entity was not in inventory when it died                elseif not self.nofadeout then                    self.inst:AddTag("NOCLICK")                    self.inst.persists = false                    self.inst:DoTaskInTime(self.destroytime or 2, destroy)                end

Any chance you can post it on the workshop?

Becuase well...I don't trust myself to put this code correctly without destroying something in my game haha. 

Link to comment
Share on other sites

Eh, not crazy about posting a whole Workshop mod just for a bug fix that will be gone in the next game update, but I'll gladly attach such a mod to this post! It's a .zip file. Just extract it to its own subdirectory in your mods/ folder and it will be available in-game.

 

The only configuration is to disable this bug fix, which is enabled by default. Why bother, you ask, since you can just disable the mod? This is part of a larger bug-fixing mod, of course!

post-331005-0-54290400-1452292031_thumb.

post-331005-0-16388800-1452292035_thumb.

deathbyfood.zip

Link to comment
Share on other sites

Eh, not crazy about posting a whole Workshop mod just for a bug fix that will be gone in the next game update, but I'll gladly attach such a mod to this post! It's a .zip file. Just extract it to its own subdirectory in your mods/ folder and it will be available in-game.

 

The only configuration is to disable this bug fix, which is enabled by default. Why bother, you ask, since you can just disable the mod? This is part of a larger bug-fixing mod, of course!

Once again, thank you.

 

(also that description is gold)

Link to comment
Share on other sites

Eh, not crazy about posting a whole Workshop mod just for a bug fix that will be gone in the next game update, but I'll gladly attach such a mod to this post! It's a .zip file. Just extract it to its own subdirectory in your mods/ folder and it will be available in-game.

 

The only configuration is to disable this bug fix, which is enabled by default. Why bother, you ask, since you can just disable the mod? This is part of a larger bug-fixing mod, of course!

Also, playing in a shipwrecked file with this mod(or that it wasnt a mod exclusive issue, i cant remember haha)...makes corpses never disappear. I am still surrounded by spider corpses for a good amount of days.

Link to comment
Share on other sites

Yup, sorry about that. It's a bug introduced by the bug fix. (-:
 
The way I implemented it was that I injected the new code on top of the old code at runtime, and Health:SetVal() has a call to local function destroy, which of course isn't accessible outside of health.lua, which is why corpses don't disappear.
 
I've corrected that particular issue in the finished mod, which fixes every bug I've documented so far. Give that one a try and it should be better.

Link to comment
Share on other sites

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.