[forge-mc1.18-2.3.0] Infinite loop still happening when selecting rotten flesh in the hotbar
TigerWalts opened this issue ยท 6 comments
Previous issue - #153
Confirmed in Visual VM that it's still getting stuck in the getEstimatedHealthIncrement(int, float, float)
method.
I also decompiled the class file to make sure it had the previous fix applied.
Triggered by a stack of 2 minecraft:rotten_flesh
just as before.
Values in the Player Data file:
- foodExhaustionLevel
1.401881
- foodLevel
17
- foodSaturationLevel
0.2000003
- foodTickTimer
0
- Health
17
Modlist
absentbydesign-1.18.1-1.6.1.jar
angelring-1.18-1.5.0.jar
animal_feeding_trough-1.0.3+1.18.1-forge.jar
appleskin-forge-mc1.18-2.3.0.jar
architectury-3.7.31.jar
artifacts-1.18.1-4.0.3.jar
balm-2.4.3+0.jar
BetterDungeons-Forge-1.18.1-1.0.1.jar
bonsaitrees3-3.0.4.jar
caelus-forge-1.18.1-3.0.0.2.jar
Clumps-forge-1.18.1-8.0.0+5.jar
collective-1.18.1-4.7.jar
ColossalChests-1.18.1-1.8.2.jar
configured-1.5.3-1.18.1.jar
connectedglass-1.1.1-mc1.18.jar
Controlling-forge-1.18.1-9.0+15.jar
create-mc1.18.1_v0.4d.jar
curioofundying-forge-1.18-5.3.0.0.jar
curios-forge-1.18.1-5.0.6.2.jar
curiouselytra-forge-1.18.1-5.0.1.0.jar
CyclopsCore-1.18.1-1.13.0.jar
DoggyTalents-1.18.1-2.4.2.jar
doubledoors_1.18.1-3.2.jar
DrawersTooltip-1.18.1-forge-4.1.0.jar
EasierSleeping-1.18.1-2.1.0.jar
elevatorid-1.18-1.8.3.jar
EnchantingInfuser-v3.1.1-1.18.1-Forge.jar
EnchantmentDescriptions-Forge-1.18.1-9.0.11.jar
expandability-5.0.0-forge.jar
ExplorersCompass-1.18.1-1.1.2-forge.jar
fixedanvilrepaircost_1.18.1-1.7.jar
flatbedrock-1.4.1-build.8+mc1.18.1.jar
flywheel-forge-1.18-0.6.0.jar
forgivingvoid-forge-1.18.1-6.0.1.jar
forgottenrecipes-forge-1.18.1-1.0.0.jar
ftb-chunks-forge-1801.3.4-build.127.jar
ftb-library-forge-1801.3.5-build.109.jar
ftb-teams-forge-1801.2.5-build.48.jar
ftb-ultimine-forge-1801.3.2-build.52.jar
furniture-7.0.0-pre28-1.18.1.jar
gravestone-1.18.1-1.0.2.jar
harvest-1.18.1-1.1.jar
inventorysorter-1.18-19.0.0.jar
itemcollectors-1.1.4-mc1.18.jar
jei-1.18.1-9.2.1.69.jar
justmobheads_1.18.1-5.3.jar
libnonymous-2.0.5.jar
lootr-1.18-0.1.15.50.jar
mcw-paintings-1.0.2-mc1.18.1.jar
minicoal-1.18.1-1.0.0.jar
MouseTweaks-forge-mc1.18-2.21.jar
OreTree-1.18.1-0.2.5.jar
pitg-1.18.1-2.0.2.jar
PuzzlesLib-v3.2.1-1.18.1-Forge.jar
RapidLeafDecay-1.18.1-2.0.0.jar
ShulkerTooltip-1.10.jar
shutupexperimentalsettings-1.0.4-1.18+.jar
SimpleStorageNetwork-1.18.1-1.5.4.jar
simplylight-1.18.1-1.4.0-build.26.jar
Snad-1.18.1-1.21.12.11a.jar
StorageDrawers-1.18.1-10.1.1.jar
supermartijn642configlib-1.0.9-mc1.18.jar
supermartijn642corelib-1.0.16b-mc1.18.jar
theoneprobe-1.18-5.0.4.jar
time-in-a-bottle-2.1.0-mc1.18.1.jar
torchmaster-18.0.3-beta.jar
upgradedcore-1.18.1-3.1.0.0-release.jar
upgradednetherite-1.18.1-4.1.0.0-release.jar
vanillaplustools-1.18-1.0.jar
VisualWorkbench-v3.1.0-1.18.1-Forge.jar
voicechat-forge-1.18.1-2.2.26.jar
waystones-forge-1.18.1-9.0.4.jar
weirdinggadget-1.18.1-2.2.11.jar
YungsApi-1.18.1-Forge-24.jar
Thanks for all the info, really need to get this one figured out.
EDIT: More info:
2x rotten_flesh stack has the following FoodValues:
hunger = 4
saturationModifier = 0.1
getSaturationIncrement = 0.8
Which means with the player data in the OP, I believe getEstimatedHealthIncrement(int, float, float)
is being called with:
foodLevel = Math.min(17 + 4, 20) = 20
saturationLevel = Math.min(0.2000003 + 0.8, 20) = 1.0000003
exhaustionLevel = 1.401881
Okay, I think I've figured out the problem:
Inside this conditional, we increment exhaustionLevel
by limitedSaturationLevel
:
AppleSkin/java/squeek/appleskin/helpers/FoodHelper.java
Lines 128 to 134 in 01f4cea
It's possible, though, for limitedSaturationLevel
to be extremely small, i.e. 1.4E-45
, and, due to how floating point works, that can be small enough that exhaustionLevel
doesn't actually change representation from the increment (exhaustionLevel + limitedSaturationLevel == exhaustionLevel
). Therefore, we enter an infinite loop since exhaustionLevel
is no longer changing at all.
Vanilla Minecraft doesn't run into this problem because it just does 1 'iteration' of our getEstimatedHealthIncrement
in its FoodStats.update
function, so if exhaustion isn't incremented in a given update
it's not a problem (future player actions will change saturation/exhaustion which changes how update
works).
I believe we can fix this by treating close-to-zero exhaustion/saturation levels as zero, or otherwise ensuring that we handle close-to-zero values in a safer way.
I think limitedSaturationLevel because it's too small that the number of loops has become very bigger(pseudo-infinite loops)
I think limitedSaturationLevel because it's too small that the number of loops has become very bigger(pseudo-infinite loops)
It's a real infinite loop. Here's a test case that reproduces it:
@Test
public void testEstimatedHealth() {
int foodLevel = 20;
float saturationLevel = Float.intBitsToFloat(0x0000001);
float exhaustionLevel = Float.intBitsToFloat(0x1000000);
float healthIncrement = FoodHelper.getEstimatedHealthIncrement(foodLevel, saturationLevel, exhaustionLevel);
}
If saturationLevel is 1000 times smaller than exhaustionForRegen, there will be no obvious variant of recovered health. We can ignore it
Will be fixed by c44304e (Fabric) and b563b91 (Forge)
Testing this also made me realize that there's the potential for a massive improvement in the worst-case performance of this function. The worst case number of iterations of the main loop of the function has gone from millions down to around 18.
Thanks again for the detailed report of this bug @TigerWalts!