chraft/c-raft — Issue #149: Skylight bug when placing a block
Author: Smjert
Created: 2011-11-30 10:23:30+00:00
State: open

The skylight recalculation doens't work right when placing a block that reduces light, so something like placing the last block to close our shelter. The skylight of the inner air blocks should be 0, but it's higher.

The idea behind the skylight recalculation is this: skylight come from the top, down to the ground, it doesn't reduce its value vertically (unless an opaque block is encountered) but it does horizontally by one from the highest skylight value found on its neighbour on the same plane.
So the algorithm now works like this: it starts from the block removed/placed, if it's placed so that the new height in that coords is higher than the old one, all the blocks under it, down to the old heightmap value, are set to 0 since they don't receive skylight vertically anymore.
Otherwise if the new height is lower than the old one, all the blocks under the old one are set to 15.
Then for both cases the recursive spreadkylightfromblock function is called. What this function does is checking all the neighbour blocks skylight and taking the highest one (comparing it even with the current block value), then if this value is different from the old one the new value is reduced by one if it was taken from a block on the same y, otherwise not and reduced by its opacity value, then is set and the function proceeds.
Then it reduces again the value set by one, this will be the highest value a neighbour block can receive (not vertically actually), so if the neighbour block value is lower than this one the spreadskylightfromblock function is called onto this. If this block it's on another chunk, the call is queued with a ChunkLightUpdate object, to avoid too deep recursion calls.
So this two stop conditions works when the light should be increased, it's also worth to say that the first one, stop if the set skylight isn't different from the old one, is skipped if the block we called the function on is the "first" one in the chain of recursive calls.
The problem comes when the light has to be reduced: the idea was to retrieve also the neighbour heightmap values and to call the recursive function onto blocks that had their skylight value higher than the one that it should be set to them (currentblock skylight - 1) and if their heightmap is higher than the current one (meaning that you should select only air blocks under the various neighbour blocks, the one that should receive a skylight decrease).
But the algorithm "stabilizes" to higher values when it has to set all to zero (that's because blocks retains the old skylight value that they receive from the source blocks that are directly in the sunlight).
I won't go deeper in the matter since it's a long one, better to ask me something directly.