This mod is not a fork of Spice of Life, but the content is similar. Instead of a policy of rewarding and encouraging eating, which is common, it encourages eating by debuffing.
Overview
This mod increases the difficulty of managing food in Minecraft by introducing mechanics that decrease food recovery values the more you consume the same item. It adds both short-term and long-term food debuffs, making food choices more strategic. Also, add a basket that can carry more than one food item.
Short-Term Food Debuff
If you eat the same food within the last 5 meals, the following debuffs will occur:
- 1st time: 100% recovery (normal)
- 2nd time: 90% recovery
- 3rd time: 75% recovery
- 4th time: 50% recovery
- 5th time: 05% recovery
This is considered the short-term debuff.
Long-Term Food Debuff
Over time, the more you consume a specific food, its recovery will decrease by 1% per consumption, up to a history of 100 meals. This simulates a long-term debuff.
Items added
Baskets should contain multiple food items. It can be opened by right-clicking.
Basket:It can hold 9 stacks of food.

Large Basket:It can hold 9 stacks of food. Right click to eat the food inside. Compatible with AppleSkin.

Configurable Settings
All debuff values, as well as the number of meals tracked for the history, are configurable through the config file. These settings are world-specific, so you can adjust them per save file.
Mod Compatibility
- AppleSkin: This mod is fully compatible with AppleSkin. Changes to the food recovery will be reflected in the HUD. It also displays the amount of Wicker Basket recovery.
- Farmer's Delight: While tested and working with Farmer's Delight, full compatibility is not guaranteed.
Feedback and Usage
This is my first mod, so I would love to hear any suggestions or improvements you have!
- You are welcome to include this mod in modpacks.
- Feel free to showcase it in videos.
- No notification is required, but I would be delighted to hear about it if you do!
Prior to the change, the name was "FoodVariation".
All Versions
+ Add Version| Name | Game version | Platforms | Published | Downloads | Actions |
|---|---|---|---|---|---|
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 6mo ago | 1 | ||||
| 6mo ago | 1 | ||||
| 6mo ago | 1 | ||||
| 6mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| 8mo ago | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 |
- Added Chinese (zh_cn) localization. Thanks to [@pyf6trb](https://github.com/pyf6trb) (#53).
- Added a
basketBlacklistconfig option listing food items that cannot be put into the Basket or the Wicker Basket. Items already inside a basket are never deleted — they can still be taken out, and the Wicker Basket simply skips them when picking the most nutritious food to eat. This is separate fromfoodBlacklist, which excludes items from decay tracking. Requested in #52.
### Changed
- Food history now caches per-item consumption counts in a
Map<Item, Integer>alongside theItemStackqueue, socountFoodEaten()(used by the long-term decay calculation) is O(1) instead of scanning the whole history. Thanks to [@DaPlumer](https://github.com/DaPlumer) (#55).
### Fixed
- Cake now loses hunger recovery like any other food.
CakeBlock.eat()callsFoodData.eat(int, float)directly instead of going throughPlayer.eat(Level, ItemStack), so thePlayerMixinredirect never fired and eating cake was neither decayed nor recorded in the food history. AddedCakeBlockMixinon both platforms. Cake is the only vanilla food block that takes this path — candle cakes go through the sameCakeBlock.eat(). Reported in #3. - Fixed a
NullPointerExceptioninFoodEventHandlerForge.countFoodEatenRecent()that dereferenced.consumedItemsbefore the null check. Running/resetfoodhistoryremoves the map entry without re-syncing, so the next meal crashed on Forge. - Restored the defensive copy in
FoodHistoryComponentFabric.setFood()and added a self-assignment guard. Without it, callingsetFood()with the component's own history wouldclear()it and wipe the player's food history. FoodHistoryno longer throwsIllegalStateExceptionwhen the queue and the count cache disagree. It now logs the inconsistency and rebuilds the cache instead of crashing insidePlayer.eat().- Fixed
FoodHistory.toString()using the%bformat specifier, which printedtrueinstead of the actual contents in diagnostic logs. - Fixed a
NullPointerExceptionin the Fabric config loader when an array key is missing from an existingsolclassic-server.toml.TomlTable#getArrayreturnsnullfor an absent key, and the previous code called.toList()on it before the null check, so adding any new array key would have broken every existing config file on load.
- Added Chinese (zh_cn) localization. Thanks to [@pyf6trb](https://github.com/pyf6trb) (#53).
- Added a
basketBlacklistconfig option listing food items that cannot be put into the Basket or the Wicker Basket. Items already inside a basket are never deleted — they can still be taken out, and the Wicker Basket simply skips them when picking the most nutritious food to eat. This is separate fromfoodBlacklist, which excludes items from decay tracking. Requested in #52.
### Changed
- Food history now caches per-item consumption counts in a
Map<Item, Integer>alongside theItemStackqueue, socountFoodEaten()(used by the long-term decay calculation) is O(1) instead of scanning the whole history. Thanks to [@DaPlumer](https://github.com/DaPlumer) (#55).
### Fixed
- Cake now loses hunger recovery like any other food.
CakeBlock.eat()callsFoodData.eat(int, float)directly instead of going throughPlayer.eat(Level, ItemStack), so thePlayerMixinredirect never fired and eating cake was neither decayed nor recorded in the food history. AddedCakeBlockMixinon both platforms. Cake is the only vanilla food block that takes this path — candle cakes go through the sameCakeBlock.eat(). Reported in #3. - Fixed a
NullPointerExceptioninFoodEventHandlerForge.countFoodEatenRecent()that dereferenced.consumedItemsbefore the null check. Running/resetfoodhistoryremoves the map entry without re-syncing, so the next meal crashed on Forge. - Restored the defensive copy in
FoodHistoryComponentFabric.setFood()and added a self-assignment guard. Without it, callingsetFood()with the component's own history wouldclear()it and wipe the player's food history. FoodHistoryno longer throwsIllegalStateExceptionwhen the queue and the count cache disagree. It now logs the inconsistency and rebuilds the cache instead of crashing insidePlayer.eat().- Fixed
FoodHistory.toString()using the%bformat specifier, which printedtrueinstead of the actual contents in diagnostic logs. - Fixed a
NullPointerExceptionin the Fabric config loader when an array key is missing from an existingsolclassic-server.toml.TomlTable#getArrayreturnsnullfor an absent key, and the previous code called.toList()on it before the null check, so adding any new array key would have broken every existing config file on load.
- Ported the
basketBlacklistsetting from the 1.20.1 branch. Food items listed here cannot be put into the Basket or the Wicker Basket, and are skipped by the Wicker Basket's automatic food selection. This is a separate setting fromfoodBlacklist, which excludes items from decay tracking. The check is only applied on the paths that put *new* items in (FoodSlot.mayPlace(),FoodContainer.canPlaceItem()/addItem()/canAddItem()), never onFoodContainer.setItem(), so items already inside a basket can still be taken out after an item is added to the blacklist. On NeoForge the value is declared withdefineListAllowEmptyrather thandefineList, becausedefineListbinds aNON_EMPTY(>= 1) size range that does not fit a setting whose default is an empty list. Requested in #52. - Ported the Chinese (
zh_cn) localization from the 1.20.1 branch.
### Fixed
- Fixed cake not being subject to food decay and not being recorded in the food history.
CakeBlock.eat()does not go throughPlayer.eat(Level, ItemStack, FoodProperties); it callsFoodData.eat(int, float)directly, soPlayerMixin's@Redirectnever fired. AddedCakeBlockMixinon both platforms with the shared logic inCakeEatHandler. Candle cakes go through the sameCakeBlock.eat()and are covered as well. Reported in #3. - Fixed items disappearing from a Basket after roughly three stacks were inserted. The menu was opened with the vanilla
MenuType.GENERIC_9x1, so the client built a vanillaChestMenu+SimpleContainerwith no food validation while the server usedFoodChestMenu+FoodContainer+FoodSlot. The mismatch desynced slot contents. Registered a customMenuType(solclassic:food_chest) via Architectury'sMenuRegistry.ofExtended()so both sides build the same menu, and added the missingFoodContainer.canPlaceItem()override. Reported in #51.
### Changed
- Ported the consumption-count cache from the 1.20.1 branch. Food history is now held in a
FoodHistoryobject that keeps aMap<Item, Integer>counter alongside the queue, making the total-count lookup used by long-term decay O(1) instead of a linear scan of up to 300 entries.IFoodEventHandlernow passesFoodHistoryinstead ofLinkedList<ItemStack>.
- Ported the
basketBlacklistsetting from the 1.20.1 branch. Food items listed here cannot be put into the Basket or the Wicker Basket, and are skipped by the Wicker Basket's automatic food selection. This is a separate setting fromfoodBlacklist, which excludes items from decay tracking. The check is only applied on the paths that put *new* items in (FoodSlot.mayPlace(),FoodContainer.canPlaceItem()/addItem()/canAddItem()), never onFoodContainer.setItem(), so items already inside a basket can still be taken out after an item is added to the blacklist. On NeoForge the value is declared withdefineListAllowEmptyrather thandefineList, becausedefineListbinds aNON_EMPTY(>= 1) size range that does not fit a setting whose default is an empty list. Requested in #52. - Ported the Chinese (
zh_cn) localization from the 1.20.1 branch.
### Fixed
- Fixed cake not being subject to food decay and not being recorded in the food history.
CakeBlock.eat()does not go throughPlayer.eat(Level, ItemStack, FoodProperties); it callsFoodData.eat(int, float)directly, soPlayerMixin's@Redirectnever fired. AddedCakeBlockMixinon both platforms with the shared logic inCakeEatHandler. Candle cakes go through the sameCakeBlock.eat()and are covered as well. Reported in #3. - Fixed items disappearing from a Basket after roughly three stacks were inserted. The menu was opened with the vanilla
MenuType.GENERIC_9x1, so the client built a vanillaChestMenu+SimpleContainerwith no food validation while the server usedFoodChestMenu+FoodContainer+FoodSlot. The mismatch desynced slot contents. Registered a customMenuType(solclassic:food_chest) via Architectury'sMenuRegistry.ofExtended()so both sides build the same menu, and added the missingFoodContainer.canPlaceItem()override. Reported in #51.
### Changed
- Ported the consumption-count cache from the 1.20.1 branch. Food history is now held in a
FoodHistoryobject that keeps aMap<Item, Integer>counter alongside the queue, making the total-count lookup used by long-term decay O(1) instead of a linear scan of up to 300 entries.IFoodEventHandlernow passesFoodHistoryinstead ofLinkedList<ItemStack>.
- Fixed Fabric server config not taking effect on dedicated servers. The config path was resolved as a relative path, which could point to a different location depending on the working directory of the startup script. Now resolved to an absolute path via
toAbsolutePath(). Config file location remains<world>/serverconfig/solclassic-server.toml. - Fixed potential NullPointerException in config array parsing (
shortFoodDecayModifiers,foodBlacklist) that could silently prevent all config values from being applied. - Config values are now applied in the correct order: scalar values are written before array values, so scalar settings are always applied even if array parsing fails.
- Fixed Fabric server config not taking effect on dedicated servers. The config path was resolved as a relative path, which could point to a different location depending on the working directory of the startup script. Now resolved to an absolute path via
toAbsolutePath(). Config file location remains<world>/serverconfig/solclassic-server.toml. - Fixed potential NullPointerException in config array parsing (
shortFoodDecayModifiers,foodBlacklist) that could silently prevent all config values from being applied. - Config values are now applied in the correct order: scalar values are written before array values, so scalar settings are always applied even if array parsing fails.
- Fixed a crash on dedicated Fabric servers caused by
NetworkManager.registerS2C()being annotated@Environment(EnvType.CLIENT). Following Architectury 13.0.8's documented pattern: server-side init now callsregisterS2CPayloadType(type registration only), while client-side init continues to callregisterReceiverwith the packet handler.
- Fixed a crash on dedicated Fabric servers caused by
NetworkManager.registerS2C()being annotated@Environment(EnvType.CLIENT). Following Architectury 13.0.8's documented pattern: server-side init now callsregisterS2CPayloadType(type registration only), while client-side init continues to callregisterReceiverwith the packet handler.
- Fixed Wicker Basket / Lunch Basket slot desync bug where placing food items would cause other items to be displaced or lost after approximately 3 items. The root cause was using vanilla
MenuType.GENERIC_9x1, which caused the client to create a vanillaChestMenu+SimpleContainer(no food validation) while the server usedFoodChestMenu+FoodContainer+FoodSlot(with food validation). This client-server mismatch led to slot synchronization failures during item placement. Registered a customMenuTypevia Architectury'sMenuRegistry.ofExtended()so both client and server useFoodChestMenuwith consistentFoodSlot+FoodContainervalidation. - Added
canPlaceItem()override toFoodContaineras an additional safety net for food-only validation at the container level (defense-in-depth alongsideFoodSlot.mayPlace()).
- Fixed Wicker Basket / Lunch Basket slot desync bug where placing food items would cause other items to be displaced or lost after approximately 3 items. The root cause was using vanilla
MenuType.GENERIC_9x1, which caused the client to create a vanillaChestMenu+SimpleContainer(no food validation) while the server usedFoodChestMenu+FoodContainer+FoodSlot(with food validation). This client-server mismatch led to slot synchronization failures during item placement. Registered a customMenuTypevia Architectury'sMenuRegistry.ofExtended()so both client and server useFoodChestMenuwith consistentFoodSlot+FoodContainervalidation. - Added
canPlaceItem()override toFoodContaineras an additional safety net for food-only validation at the container level (defense-in-depth alongsideFoodSlot.mayPlace()).
- Added compatibility with Sophisticated Backpacks' Feeding Upgrade (auto-feeding feature). SoL Classic now directly integrates with SB's FeedingUpgradeWrapper via conditional Mixin.
- Food with 0% recovery rate (fully decayed) is now skipped by SB's auto-feeding, preventing wasteful consumption.
- When a Wicker Basket is in an SB backpack, the Feeding Upgrade will prioritize eating from the Wicker Basket, selecting the most nutritious food inside (with decay considered).
- SB compatibility Mixin is conditionally loaded only when SophisticatedCore is present on the classpath, preventing crashes when SB is not installed.
- Added compatibility with Sophisticated Backpacks' Feeding Upgrade (auto-feeding feature). SoL Classic now directly integrates with SB's FeedingUpgradeWrapper via conditional Mixin.
- Food with 0% recovery rate (fully decayed) is now skipped by SB's auto-feeding, preventing wasteful consumption.
- When a Wicker Basket is in an SB backpack, the Feeding Upgrade will prioritize eating from the Wicker Basket, selecting the most nutritious food inside (with decay considered).
- SB compatibility Mixin is conditionally loaded only when SophisticatedCore is present on the classpath, preventing crashes when SB is not installed.
- Added Sophisticated Backpacks (SophisticatedCore) Feeding Upgrade compatibility. SoL Classic's food decay is now correctly applied when SB's Feeding Upgrade auto-feeds the player.
- Foods with 0% decay recovery are excluded from Feeding Upgrade's auto-feeding.
- Wicker Basket in SB backpacks now correctly feeds from the basket's inventory instead of being consumed as an item.
- Conditional Mixin loading via
SBCompatMixinPlugin: SB compatibility mixins are only loaded when SophisticatedCore is present, preventing crashes when SB is not installed.
- Added Sophisticated Backpacks (SophisticatedCore) Feeding Upgrade compatibility. SoL Classic's food decay is now correctly applied when SB's Feeding Upgrade auto-feeds the player.
- Foods with 0% decay recovery are excluded from Feeding Upgrade's auto-feeding.
- Wicker Basket in SB backpacks now correctly feeds from the basket's inventory instead of being consumed as an item.
- Conditional Mixin loading via
SBCompatMixinPlugin: SB compatibility mixins are only loaded when SophisticatedCore is present, preventing crashes when SB is not installed.
- Fixed basket (Lunch Basket) slot bug where placing a 4th item would overwrite the item in the first slot. When replacing Slots with FoodSlot/LockedSlot via
this.slots.set()in FoodChestMenu, theslot.indexfield (menu slot position ID) was not set, defaulting to 0 for all replaced slots. This caused incorrect slot identification during item placement. Reported on Mohist (Bukkit+Forge hybrid) servers.
- Fixed basket (Lunch Basket) slot bug where placing a 4th item would overwrite the item in the first slot. When replacing Slots with FoodSlot/LockedSlot via
this.slots.set()in FoodChestMenu, theslot.indexfield (menu slot position ID) was not set, defaulting to 0 for all replaced slots. This caused incorrect slot identification during item placement. Reported on Mohist (Bukkit+Forge hybrid) servers.
- Fixed a bug in FoodChestMenu where replacing slots via
this.slots.set()did not setSlot.index(menu slot position ID), leaving it at the default value of 0. This caused slot identification to break, resulting in items in slot 0 being overwritten when inserting a 4th item into the basket, particularly in Bukkit bridge environments such as Mohist.
- Fixed a bug in FoodChestMenu where replacing slots via
this.slots.set()did not setSlot.index(menu slot position ID), leaving it at the default value of 0. This caused slot identification to break, resulting in items in slot 0 being overwritten when inserting a 4th item into the basket, particularly in Bukkit bridge environments such as Mohist.
- Added
enableTooltipconfig option (default: true): controls whether the food decay tooltip ("Hunger recovery reduced by X%") is shown on food items. - Added
enableItemDescriptionconfig option (default: true): controls whether description tooltips are shown on mod items (Wicker Basket, Food History Book).
- Added
enableTooltipconfig option (default: true): controls whether the food decay tooltip ("Hunger recovery reduced by X%") is shown on food items. - Added
enableItemDescriptionconfig option (default: true): controls whether description tooltips are shown on mod items (Wicker Basket, Food History Book).
- Added
enableTooltipconfig option to toggle the food decay tooltip on food items. When set to false, the decay percentage tooltip will not be displayed. Default is true. - Added
enableItemDescriptionconfig option to toggle the description tooltip on mod items (Wicker Basket, Food History Book, etc.). When set to false, item descriptions will not be displayed. Default is true.
- Added
enableTooltipconfig option to toggle the food decay tooltip on food items. When set to false, the decay percentage tooltip will not be displayed. Default is true. - Added
enableItemDescriptionconfig option to toggle the description tooltip on mod items (Wicker Basket, Food History Book, etc.). When set to false, item descriptions will not be displayed. Default is true.
- Added
enableTooltipconfig option (default: true): controls whether the food decay tooltip ("Hunger recovery reduced by X%") is shown on food items. - Added
enableItemDescriptionconfig option (default: true): controls whether description tooltips are shown on mod items (Wicker Basket, Food History Book).
- Added
enableTooltipconfig option (default: true): controls whether the food decay tooltip ("Hunger recovery reduced by X%") is shown on food items. - Added
enableItemDescriptionconfig option (default: true): controls whether description tooltips are shown on mod items (Wicker Basket, Food History Book).
- Added compatibility with Quality Food mod. SoL Classic's food decay now correctly applies to quality-modified nutrition values instead of base values. Food history treats items of different quality as the same food.
### Fixed
- Fixed dedicated server crash caused by FoodHistoryBookItem directly referencing client-only classes (Screen, Minecraft). Replaced client references with a Consumer<Player> callback pattern, registering the screen opener only on the client side via ClientTooltipHandler.init().
- Added compatibility with Quality Food mod. SoL Classic's food decay now correctly applies to quality-modified nutrition values instead of base values. Food history treats items of different quality as the same food.
### Fixed
- Fixed dedicated server crash caused by FoodHistoryBookItem directly referencing client-only classes (Screen, Minecraft). Replaced client references with a Consumer<Player> callback pattern, registering the screen opener only on the client side via ClientTooltipHandler.init().
- Fixed dedicated server crash caused by FoodHistoryBookItem importing client-only classes (FoodHistoryBookScreen, Minecraft). Refactored to use a Consumer<Player> callback pattern, with the screen opener registered from ClientTooltipHandler.init() on the client side only.
- Fixed dedicated server crash caused by FoodHistoryBookItem importing client-only classes (FoodHistoryBookScreen, Minecraft). Refactored to use a Consumer<Player> callback pattern, with the screen opener registered from ClientTooltipHandler.init() on the client side only.
- Added compatibility with Quality Food mod. SoL Classic's food decay now correctly applies to quality-modified nutrition values instead of base values. Food history treats items of different quality as the same food.
- Added compatibility with Quality Food mod. SoL Classic's food decay now correctly applies to quality-modified nutrition values instead of base values. Food history treats items of different quality as the same food.