Thank you! It seems there hasn't been any official word on it then, other than redram confirming that iron blooms can have too few voxels. Which I can confirm by reading the code (in fact it was while reading the code that I realized it could lead to this issue, haven't encountered it myself yet).
I don't know about that, but I guess I'll share a bit of my findings in case it might be useful to anyone searching for information in the future (including future-me!), or for those that might be interested to know a bit more about it. And hopefully someone more knowledgeable could chime in. As I mentioned in my previous message they don't seem to fully match the observed in-game results, but I think the overall idea is pretty close.
The microvoxels that you work on the anvil are generated in ItemIronBloom.CreateVoxelsFromIronBloom and goes through the following process:
Generate full ingot. An ingot is a rectangular cuboid of 7x3x2 (LxWxH, or x,z,y) metal (micro)voxels.
Loop through each voxel in a 9x6x5 grid, with the ingot in the 'center'. This means it loops through an extra slice of voxels on each side of the ingot on the x-axis (length), one extra slice of voxels on one side and two extra slices of voxels on the opposite side on the z-axis (width) and 3 extra slices (or 'layers') of voxels on the y-axis (height). This basically allows for enough room for the ingot to 'grow' into iron bloom.
If the voxel is a metal voxel of the initial ingot on the bottom layer, don't do anything. This ensures that the bottom layer stays intact, which guarantees the presence of 21 metal voxels.
For any other voxel in the grid, continue with these steps:
Calculate the (Manhattan) distance from the center 3x3x2 area of the ingot. For example, looking top-down at the second (top) layer it results in these values (dashed line indicates voxels that are part of initial ingot):
Generate a random number (uniformly distributed) in interval [0,0.99999999999999978], but let's just say [0,1) If this number is smaller than
rand.NextDouble() < dist / 3f - 0.4f + (y - 1.5f) / 4f
the distance of the voxel as calculated in step 4 / 3 - 0.4 + (y-coordinate of the voxel in the grid - 1.5) / 4, skip this voxel and continue to the next one. I'm not sure what the significance is these numbers, but for example for the second layer I calculated the following probabilities of the random number being smaller, thus skipping:
If not skipped, generate another random number in [0,1). If it's greater than
rand.NextDouble() > dist / 2f
half the voxel's distance value as calculated in step 4, set the voxel to metal. If not, set it to slag. For the example of the second layer I calculated the following probabilities of the voxel ending up being metal, taking into account the probabilities to skip in step 5:
And the probabilities of the voxel being set to slag for the second layer:
The metal/slag probabilities of the voxels in the initial ingot add up to 1, because they start out as metal and will either stay metal or change to slag, whereas for other voxels it doesn't add up to 1 (the upper corners for example add up to 0) because they may be left empty.
This guarantees another 9 metal voxels, for a total of 30 guaranteed metal voxels out of the 42 required for an ingot.
These calculations appear to be not entirely correct though, as I have observed metal voxels in places where the probability of getting metal is supposed to be 0. I have been unable to find the problem yet though, and it at least gives an idea of how iron blooms are generated. I'm far from skilled in math, but based on these results (of all 5 layers), I added up all of the probabilities to generate metal voxels in the locations where they are not guaranteed, which resulted in '14.0875', which I think would mean that on average 14.0875 metal voxels would be generated. We still needed 12 on top of the 30 that were guaranteed, so on average this should be more than enough. However, because we're dealing with randomness and probabilities it's perfectly possible to have more or less of them in an individual iron bloom. In-game I've observed there to be more than 2 extra metal voxels on average, which would be consistent with my earlier observation of metal voxels where they shouldn't be according to my calculated values, but the point still stands.
The way this is set up also leads me to believe that the possibility of not having enough metal voxels to create an ingot is intentional and not a bug, because the generation algorithm appears to be pretty closely tuned to generate enough metal voxels most of the time, implying some thought has been put into it. Or the programmer just hoped for the best and didn't run into any issues during testing, who knows. Whether it's a fun design decision *if it's intentional* is subjective of course; I don't like it too much so with my mod I hope to make changes that will always guarantee enough metal voxels to finish an ingot, or perhaps add the ability to add more material (and recover the metal you are forced to remove that way).