Well, I have little to no idea about the technical application, but I would like to suggest a form of damage tracking for individual blocks.
Eventually the game will end up with some sort of collateral damage to the environment (i.e. EXPLOSIONS!) or more directed violence against blocks, which prompts the problem of how we keep track of how damaged a block is and how resistant a block is against a source of damage. To give an example: Throwing a stick of dynamite at a dirtwall will produce a hole, throwing it at a steel wall will only produce a smudge.
Now I see two ways of doing this:
1.) We track each blocks individual "hit points" which depend on the block type.
I figure this is memory intensive and in most cases redundant, as most blocks will be at perfect health most of the time, but it allows for smooth tracking.
2.) We assign a "hardness" value to each block type. Now everytime the block is under attack the damage is compared to the "hardness" of the block type: If the hardness is overcome, the block is exchanged for its "damaged" counterpart otherwise the block perseveres undaunted. We can then continue this chain (also by bleeding over excessive damage) until there are no more damaged variants available at which point the block simply vanishes and joins his fallen brethren in Blockhalla.
This frees us from assigning individual memory space to each block in the world, but makes the damage process a somewhat rougher "all-or-nothing" deal and we will need to use multiple slots for one block type and its damaged variants (unless there is a better solution for storing the damaged versions); however, most blocks won't actually need to have a damaged variant (like sand or dirt), yet the ability to have them will allow us to do some additional shenanigans, like having a damaged steam pipe fog up the environment, or weakened wooden floors that collapse under the weight of a creature.
If we would go with solution number 2 we could also implement a way to temporarely track smaller damage increments to a block that fail to individually overcome a blocks hardness, but combined can damage it; effectively when a block is attacked it generates an entry that tracks the total damage of all attacks against it that stays with it until either the total damage overcomes the hardness of the block, the block is removed, the block is unloaded from memory (typically by having the player leave the area) or when a certain amount of time has passed.
I'm thinking here of situations like felling a tree with an axe or shooting a stone pillar with a machine gun.
Of course the hardness idea can also be combined with the first variant.
Regarding water/liquids:
Is it technically feasible to treat bodies of liquids as individual enitities? By which I mean that instead of putting a bunch of individual water type blocks in the same area and calling it a lake we actually have a lake entity that determines how much blocks around it are filled with water and to what height?
To elaborate:
First we determine if an area can hold a liquid (e.g. a hole in the ground).
Now we generate a "liquid" entity associated with a central empty block at the lowest z-level of the hole.
This entity contains all the necessary information required for the liquid, like type of content or volume.
From this block onward we determine how many empty blocks are in "reach" on this z-level. All these blocks are stored within the liquid entity as the first z-layer.
The total amounts of blocks in this layer determine the total amount of volume this entity can store.
Now as long as there is water left in the entity, all blocks of this layer will be filled with water.
If water is added in excess of this capacity, the water level rises, at which point the game will check if the next z-layer above the current filled one can hold a liquid. If "no" all the excess water is lost (assumed to have drained into the environment), if "yes" the next layer is added to the entity.
Should this higher layer connect to more empty blocks in lower z-layers, these are added to the lower layers in the entity, creating new ones as necessary (it would probably be prudent to number the z-layers in relation to the worlds z-layers and not its own starting layer to prevent negative values).
This new layer now has its own volume, which is added to the total volume of the entity.
Now whenever the total volume of the entity is filled to a certain threshold (like 50%) of the volume of the next unfilled layer, this layer is also filled with water blocks and these blocks are removed again, when the water level falls below that threshold.
Should a block within this liquid body be filled with a solid block, the block is simply removed from the list of the entity and the volumes adjusted accordingly. If this was the block associated with the entity, simply associate the entity with the next viable block in the liquid body; should no viable block remain, the entity is removed.
Everytime a solid block is removed that is in vicinity of the liquid body at the same z-layer, the layer is recalculated. Should this cause a layer to be open to an area that cannot contain a liquid (i.e. the space would be too vast), it will start to drain out at a rate determined by the amount of open spaces it can drain out of (might even do water pressure calculations for that) unless the leak is sealed again. If a layer is completely drained in this manner, it is removed from the entity. If it was the last layer, the entity is removed.
The entities can have additional values, like how fast they regenerate or lose their supply, or how much surface area they have (for determining gain through rainfall) and also if they are connected to another entity (like a river or a pump).
This system would allow us to control bodies of water on a volume basis, without doing constant recalculations and individual tracking of blocks.
We can also fracture the z-layers into smaller sections to allow "smoother" filling of blocks (like DF).
Also we can use similar systems for rivers and oceans (with oceans being infinite and limited in layers).
Eventually the game will end up with some sort of collateral damage to the environment (i.e. EXPLOSIONS!) or more directed violence against blocks, which prompts the problem of how we keep track of how damaged a block is and how resistant a block is against a source of damage. To give an example: Throwing a stick of dynamite at a dirtwall will produce a hole, throwing it at a steel wall will only produce a smudge.
Now I see two ways of doing this:
1.) We track each blocks individual "hit points" which depend on the block type.
I figure this is memory intensive and in most cases redundant, as most blocks will be at perfect health most of the time, but it allows for smooth tracking.
2.) We assign a "hardness" value to each block type. Now everytime the block is under attack the damage is compared to the "hardness" of the block type: If the hardness is overcome, the block is exchanged for its "damaged" counterpart otherwise the block perseveres undaunted. We can then continue this chain (also by bleeding over excessive damage) until there are no more damaged variants available at which point the block simply vanishes and joins his fallen brethren in Blockhalla.
This frees us from assigning individual memory space to each block in the world, but makes the damage process a somewhat rougher "all-or-nothing" deal and we will need to use multiple slots for one block type and its damaged variants (unless there is a better solution for storing the damaged versions); however, most blocks won't actually need to have a damaged variant (like sand or dirt), yet the ability to have them will allow us to do some additional shenanigans, like having a damaged steam pipe fog up the environment, or weakened wooden floors that collapse under the weight of a creature.
If we would go with solution number 2 we could also implement a way to temporarely track smaller damage increments to a block that fail to individually overcome a blocks hardness, but combined can damage it; effectively when a block is attacked it generates an entry that tracks the total damage of all attacks against it that stays with it until either the total damage overcomes the hardness of the block, the block is removed, the block is unloaded from memory (typically by having the player leave the area) or when a certain amount of time has passed.
I'm thinking here of situations like felling a tree with an axe or shooting a stone pillar with a machine gun.
Of course the hardness idea can also be combined with the first variant.
Regarding water/liquids:
Is it technically feasible to treat bodies of liquids as individual enitities? By which I mean that instead of putting a bunch of individual water type blocks in the same area and calling it a lake we actually have a lake entity that determines how much blocks around it are filled with water and to what height?
To elaborate:
First we determine if an area can hold a liquid (e.g. a hole in the ground).
Now we generate a "liquid" entity associated with a central empty block at the lowest z-level of the hole.
This entity contains all the necessary information required for the liquid, like type of content or volume.
From this block onward we determine how many empty blocks are in "reach" on this z-level. All these blocks are stored within the liquid entity as the first z-layer.
The total amounts of blocks in this layer determine the total amount of volume this entity can store.
Now as long as there is water left in the entity, all blocks of this layer will be filled with water.
If water is added in excess of this capacity, the water level rises, at which point the game will check if the next z-layer above the current filled one can hold a liquid. If "no" all the excess water is lost (assumed to have drained into the environment), if "yes" the next layer is added to the entity.
Should this higher layer connect to more empty blocks in lower z-layers, these are added to the lower layers in the entity, creating new ones as necessary (it would probably be prudent to number the z-layers in relation to the worlds z-layers and not its own starting layer to prevent negative values).
This new layer now has its own volume, which is added to the total volume of the entity.
Now whenever the total volume of the entity is filled to a certain threshold (like 50%) of the volume of the next unfilled layer, this layer is also filled with water blocks and these blocks are removed again, when the water level falls below that threshold.
Should a block within this liquid body be filled with a solid block, the block is simply removed from the list of the entity and the volumes adjusted accordingly. If this was the block associated with the entity, simply associate the entity with the next viable block in the liquid body; should no viable block remain, the entity is removed.
Everytime a solid block is removed that is in vicinity of the liquid body at the same z-layer, the layer is recalculated. Should this cause a layer to be open to an area that cannot contain a liquid (i.e. the space would be too vast), it will start to drain out at a rate determined by the amount of open spaces it can drain out of (might even do water pressure calculations for that) unless the leak is sealed again. If a layer is completely drained in this manner, it is removed from the entity. If it was the last layer, the entity is removed.
The entities can have additional values, like how fast they regenerate or lose their supply, or how much surface area they have (for determining gain through rainfall) and also if they are connected to another entity (like a river or a pump).
This system would allow us to control bodies of water on a volume basis, without doing constant recalculations and individual tracking of blocks.
We can also fracture the z-layers into smaller sections to allow "smoother" filling of blocks (like DF).
Also we can use similar systems for rivers and oceans (with oceans being infinite and limited in layers).