The Meaning of Life, the Universe, and Everything.
Join Date:
7/6/2017
Posts:
51
Member Details
Due to how light levels work in Minecraft, we currently can not use dark areas in Survival buildings safely due to hostile mobs spawing. However, this is intended to change that.
The basic idea is to add a radius to all light sources, double the light source’s light radius, which prevents hostile mobs from spawing. What this would mean is that the effective radius of say a Sea Lantern goes from 8 (as even though it has a light level of 14, mobs spawn in light level 7 or less) to 28.
This could revolutionise how light sources are used in building, no longer do we have to litter our builds with torches in an attempt to prevent spawning. We can now use dark areas for ambience without worrying about them spawning mobs. We can use less light source blocks and save on resources.
This would be a lag-free way of reducing hostile mob spawning in player builds as it would not change light levels. It would also not reduce hostile mob spawning in the world in general, only where a light source has been placed down. I realise that this could reduce hostile mobs in the Nether; to combat this, Nether mobs could ignore the ‘no hostile mob spawn’ radius of fire, lava and glowstone. This would allow the player to still build safely in the Nether but without reducing how many hostile mobs spawn.
Edit: To make it clear, the area inside the radius would be marked as non-spawnable for hostile mobs, the same way blocks like glass are considered non-spawnable by the game.
I do not see how this can be implemented without causing lag - currently to check for the light level the game simply has to read the saved light value from the chunk data, a simple operation; with your suggestion they would have to check every single block within a 30 block radius, a volume of 34279 blocks (29 blocks by taxicab from the center block).
Likewise, they could add a new data layer (in addition to light) that indicates whether a mob can spawn but it would still cause issues when placing/removing light sources as again a volume of up to 34279 blocks needs to be updated (for comparison, a light level of 15 only needs to update a volume of 4089 blocks). You'd need to be able to update about 9 times faster to offset the impact of updating spawnable areas and I doubt that the "lighting engine rewrite" they did in 1.14 even offsets the performance degradations due to poor programming practices since 1.6.4 (my own rewrite is about 3-4 times faster than vanilla 1.6.4, which still means a 2-3x drop in performance).
Another solution could be to make a list of all light sources and compare the distances to each one but this has its own issues, especially when there are many light sources, since checking a huge list would take a long time (my worlds have an average of around 1500 torches within the area mobs can spawn in due to torches placed while caving; worst case the entire list would need to be checked).
Of course, this all assumes the current spawning mechanics, where the game makes up to 3600 attempts to spawn a mob per tick per player (a pack of 4 mobs in each chunk within a 15x15 chunk area around each player, for each of 4 categories of mobs, with passive only once every 400 ticks), which is really far in excess of what is needed, even 1/10 that rate (for non-passive mobs) would likely not be noticeable in normal situations (of course this would enrage most of the playerbase as they rely on mob farms which would run at 1/10 the throughput. I do not consider building massive automated mob farms to be a legit way of playing though). This is still far too high considering that 34279 * 360 = 12340440 checks (for perspective, I measured the cost of allocating and reading from a BlockPos object at 100 nanoseconds, not including any of the other code that reads from a chunk, or garbage collection - that's 1.23 seconds per tick which is only supposed to take 0.05 seconds. If they would get rid of code like BlockPos the game would run much better - allocating and passing in/reading 3 ints only took 2 nanoseconds - but even that still adds up to nearly half the allowed tick time, and again, without any of the other code the game needs to access and read data from a chunk).
While i do not think this would work, at all, i like the idea of having a dark room with no spawning in it. I fixed this by slabbing the entire floor, but it would be nice with something new. Maybe a special block that prevents spawning in a, for example, 50 block radius like the beacon?
If so, maybe just add a new "enchantment" to the beacon that prevents mobspawning alltogether within its range? Just a thought.
The Meaning of Life, the Universe, and Everything.
Join Date:
7/6/2017
Posts:
51
Member Details
@TheMasterCaver It would simply state that the blocks in that radius are non-spawnable, so when the game attempted to spawn mobs in a chunk, it would read any blocks in that area as non-spawnable for hostile mobs, much in the same way glass is non-spawnable.
The Meaning of Life, the Universe, and Everything.
Join Date:
7/6/2017
Posts:
51
Member Details
@Kris_Eike That is an idea i’ve heard thrown about before but that would mean having to have these ghastly beams of light everywhere i wanted to use dark spaces. The whole idea would be to create an ambiance, a huge beam of light would ruin that. It could be useful if beacons didn’t need sky access but it would still be a clunky way of doing it.
@TheMasterCaver It would simply state that the blocks in that radius are non-spawnable, so when the game attempted to spawn mobs in a chunk, it would read any blocks in that area as non-spawnable for hostile mobs, much in the same way glass is non-spawnable.
And how exactly would the game know if the blocks are non-spawnable? It needs some way to either find a light-emitting block or mark all blocks within the range with a special data tag (like light level), which in turn requires marking/unmarking the blocks within range when they are placed/removed. Glass is simply nonspawnable as a simple property of the block itself - the game only needs to check the block right below the point chosen for spawning, nothing else.
Also, I have actual experience with writing the sort of code that would be needed to find light sources as my mod's cave maps work by searching for a light level of 6 or more above a non-air block, then searching for a torch within 8 blocks by taxicab distance (it would be better to search for valid blocks around torches instead but the way maps update means that you can only update the current column):
torchCheck:
while (y > 0)
{
// Checks air and torch blocks with a light level of 6 or more (max of 8 blocks from a torch)
int block = (ebs[y >> 4] != null ? ebs[y >> 4].getExtBlockAndLightByIndex((y & 15) << 8 | z << 4 | x) : 0);
// block stores the blockID + blocklight * 256
if ((block >> 8) >= 6 && ((block & 255) == 0 || (block & 255) == Block.torchWood.blockID))
{
// Block must be above a non-air, non-torch block
block = (ebs[(y - 1) >> 4] != null ? ebs[(y - 1) >> 4].getExtBlockStateByIndex(((y - 1) & 15) << 8 | z << 4 | x) : 0);
if ((block & 255) != 0 && (block & 255) != Block.torchWood.blockID)
{
// Stores a map of visited points
for (int px = 0; px < 4768; ++px)
{
pointMap[px] = false;
++px;
pointMap[px] = false;
++px;
pointMap[px] = false;
++px;
pointMap[px] = false;
}
pointMap[4768] = false;
int index = 1;
queue[0] = 8456; // is (8 * 1024) + (8 * 32) + 8 (center of area)
while (index > 0)
{
int coords = queue[--index];
int tx = coords & 31;
int ty = coords >> 5 & 31;
int tz = coords >> 10 & 31;
int cx = var2216 + x + tx - 8;
int cy = y + ty - 8;
int cz = var23 + z + tz - 8;
if (cy > 0)
{
int blockID = chunkCache[(cx >> 4) - playerX][(cz >> 4) - playerZ].getBlockID(cx & 15, cy, cz & 15);
if (blockID == Block.torchWood.blockID)
{
// assignMetadataColors is used to enable assigning colors to blocks based on their data value;
// returns a block ID with the corresponding color
var34 = CustomMapColors.assignMetadataColors(block, var25.getBiomeGenForCoords(x, z).getMapColorType());
if (y > 0 && var34 != 0 && Block.blocksList[var34].blockMaterial.isLiquid() && !Block.isWaterPlant(var34))
{
int var36 = y - 1;
int var43;
do
{
var43 = var25.getBlockID(x, var36, z);
--var36;
++var28;
}
while (var36 > 0 && var43 != 0 && Block.blocksList[var43].blockMaterial.isLiquid());
}
break torchCheck;
}
if (!Block.opaqueCubeLookup[blockID] && (tx < 8 ? 8 - tx : tx - 8) + (ty < 8 ? 8 - ty : ty - 8) + (tz < 8 ? 8 - tz : tz - 8) < 8)
{
int pmi = tx * 289 + ty * 17 + tz;
tz = tz << 10 | ty << 5 | tx;
if (!pointMap[pmi - 289])
{
pointMap[pmi - 289] = true;
queue[index++] = (short)(tz - 1);
}
if (!pointMap[pmi + 289])
{
pointMap[pmi + 289] = true;
queue[index++] = (short)(tz + 1);
}
if (!pointMap[pmi - 17])
{
pointMap[pmi - 17] = true;
queue[index++] = (short)(tz - 32);
}
if (!pointMap[pmi + 17])
{
pointMap[pmi + 17] = true;
queue[index++] = (short)(tz + 32);
}
if (!pointMap[pmi - 1])
{
pointMap[pmi - 1] = true;
queue[index++] = (short)(tz - 1024);
}
if (!pointMap[pmi + 1])
{
pointMap[pmi + 1] = true;
queue[index++] = (short)(tz + 1024);
}
}
}
}
}
}
--y;
}
This also shows what I had to do to maximize performance so it was acceptable enough to update a 32 block radius with 1/16 of columns updated per tick (this means that only about 200 points are checked per tick, and again, the radius required for light sources to be detected up to 30 blocks away means that a much larger volume needs to be checked per point; either that, or light sources themselves would need to "light" blocks to mark them as unspawnable - at the very least, this would have to be limited to special light sources, not just anything). I don't know if there is a better algorithm other than the one I used, which is a "breadth-first search", the same thing that the lighting engine uses and is generally recommended for this purpose for its efficiency, with the additional complication that I need to store a map of visited points (which is otherwise the light data set by the lighting engine).
You could use a simpler and much faster algorithm that simply checks blocks without propagating outwards if you decide to ignore walls but you are still checking or changing a lot of blocks and it would be harder to control which areas can spawn mobs (e.g. no placing torches on the roof of a darkroom spawner), and again, code changes in 1.8+ greatly reduce the efficiency of the game (for example, you can't just handle a numerical block ID as a primitive int directly read from the chunk storage arrays* (or a packed block ID + light level or block ID + metadata which is read in a single operation) but as "IBlockState" objects which also need far more memory to store).
*This gives you an idea of just how complicated they have made the code in 1.8+:
How block IDs are stored/accessed in 1.6.4:
private byte[] blockLSBArray;
public int getExtBlockID(int par1, int par2, int par3)
{
int var4 = this.blockLSBArray[par2 << 8 | par3 << 4 | par1] & 255;
return this.blockMSBArray != null ? this.blockMSBArray.get(par1, par2, par3) << 8 | var4 : var4;
}
In TMCW it is just this; I removed the "blockMSBArray", which provides support for block IDs above 255 (which require modifications to work anyway) as metadata already gives you 4080 (minus "air") blocks to work with (I've added hundreds of new "blocks" yet still have around 70 IDs left; code changes have also let me define properties such as light levels according to metadata, while vanilla defines it as a property of the block, so a single block ID can be used for blocks like redstone ore, freeing up such vanilla block IDs, same for properties like hardness and mining level):
public int getExtBlockID(int posX, int posY, int posZ)
{
return this.blockLSBArray[posY << 8 | posZ << 4 | posX] & 255;
}
This allows me to use a single method call to get a combined block state plus metadata (the overhead of combining/extracting them is more than offset by the reduction in method calls and chunk lookups); I also directly access the data stored in "NibbleArray" for the fastest possible speed (they conveniently made the data field public so I didn't have to modify the class):
// Returns the block state (ID + meta * 256)
public int getExtBlockState(int posX, int posY, int posZ)
{
int index = posY << 8 | posZ << 4 | posX;
return (((index & 1) == 0 ? this.blockMetadataArrayData[index >> 1] & 15 : this.blockMetadataArrayData[index >> 1] >> 4 & 15) << 8) | (this.blockLSBArray[index] & 255);
}
Even better yet, passing in a pre-computed index to minimize redundant calculations in methods that reference the same block locations multiple times (all of this has been benchmarked (in a real scenario, i.e. in the game) so the actual impacts on performance are known. Sure, some of these changes only affect performance by like 5% but in my opinion every bit counts as it all adds up; this is why despite being more complex world generation in TMCW is 1.5 times faster than 1.6.4 - and 10 times faster than 1.13, same for things like game startup and average server tick time. Even chunk rendering speed is faster than Optifine + vanilla due to the fact that it heavily accesses chunk data, especially with smooth lighting (Optifine doesn't even make any optimizations to actual block rendering or chunk data access, just controls how chunk updates are scheduled and how render data is sent to the GPU):
For comparison, here is code for 1.12 that I found online, starting from the same class (ExtendedBlockStorage):
// In ExtendedBlockStorage
private final BlockStateContainer data;
public IBlockState get(int x, int y, int z)
{
return this.data.get(x, y, z);
}
// In BlockStateContainer
protected IBlockStatePalette palette;
public IBlockState get(int x, int y, int z)
{
return this.get(getIndex(x, y, z));
}
private static int getIndex(int x, int y, int z)
{
return y << 8 | z << 4 | x;
}
protected IBlockState get(int index)
{
IBlockState iblockstate = this.palette.getBlockState(this.storage.getAt(index));
return iblockstate == null ? AIR_BLOCK_STATE : iblockstate;
}
// In BlockStatePaletteRegistry
public IBlockState getBlockState(int indexKey)
{
IBlockState iblockstate = Block.BLOCK_STATE_IDS.getByValue(indexKey);
return iblockstate == null ? Blocks.AIR.getDefaultState() : iblockstate;
}
// In Block
public static final ObjectIntIdentityMap<IBlockState> BLOCK_STATE_IDS = new ObjectIntIdentityMap<IBlockState>();
// In ObjectIntIdentityMap
private final List<T> objectList;
public final T getByValue(int value)
{
return (T)(value >= 0 && value < this.objectList.size() ? this.objectList.get(value) : null);
}
There is absolutely no way that code will ever reach the same level of performance (or readability) - and examples like this are everywhere in 1.8+.
Also of note, in 1.8 Mojang made it so that mobs would check for exploding creepers - a change which was reverted in the very next patch (1.8.1) due to the lag it caused, which is not much different from checking a list of block positions for light-emitting blocks (all entities are stored in a list so it only has to go through it and compare the distance to each one, not do some sort of block-by-block search). Similarly, mob spawning would cause lag when the player was more than 128 blocks above a spawnable surface since they would spawn and instantly despawn at a very high rate (up to 3600 times per tick over an ocean - this may also explain why mob spawning is so different in Bedrock - the Java spawning algorithm wastes huge amounts of resources in trying to spawn mobs at such extreme rates (Bedrock only does one spawn cycle per chunk every 200 ticks (presumably staggered out, not all chunks in one tick), which still means one pack spawn attempt per chunk every 10 seconds; Bedrock also searches down from the highest block for spawnable surfaces, not just chooses some random point which is not even valid most of the time, so the effective spawn rate is much higher; on Java only 1/256 attempts will succeed for a max-height chunk, 1/63 at sea level. Of course, as mentioned before this is why it is useless to try building mob farms on Bedrock).
The Meaning of Life, the Universe, and Everything.
Join Date:
7/6/2017
Posts:
51
Member Details
@TheMasterCaver Now i don’t know how to write code so forgive me for using layman’s terms. Could there not simply be a code that states ‘set block property spawnable false’ on all blocks in the radius? Or essentially ‘set light level 14’ on a block (though there would not actually be any visible light to avoid lighting updates). Either of these would prevent hostile mobs spawning and, if the block property can be changed, surely this would mean there is very little lag?
Adding a greater variety of nonspawnable blocks (including those onto which one could place redstone dust/components etc) would be another way of approaching the issue. [That MS/Mj seems to be (finally) listening to the calls for a greater variety of slabs/stairs/walls suggests this has the potential to be viable… hopefully without a multiyear wait.]
RE marking blocks as nonspwanable:
Without getting technical [TMC has made a strong explanation from that angle], the minimum required to implement this would be for the game to check each block each tick not only for what the block is and the current light level (both already occur) but also an additional check/calculation for whether the block has been marked as non-spawnable.
Current beacon effects all act on players (the number of which is comparatively 'small').
Perhaps it would be possible to use modifying 'things' to change block properties to prevent spawning via something akin to the way guardians are restricted to ocean monuments with the 'thing' creating a volume in which only No_Mobs could spawn. (No_Mobs would be place holders that had no collision box, could not move, and automatically despawned. )
[Insufficient knowledge of the code to predict how dificult this would be or the potential performance hit.]
Rollback Post to RevisionRollBack
"Why does everything have to be so stoopid?" Harvey Pekar (from American Splendor)
WARNING: I have an extemely "grindy" playstyle; YMMV — if this doesn't seem fun to you, mine what you can from it & bin the rest.
@TheMasterCaver Now i don’t know how to write code so forgive me for using layman’s terms. Could there not simply be a code that states ‘set block property spawnable false’ on all blocks in the radius? Or essentially ‘set light level 14’ on a block (though there would not actually be any visible light to avoid lighting updates). Either of these would prevent hostile mobs spawning and, if the block property can be changed, surely this would mean there is very little lag?
This is essentially the same thing as lighting; the game stores light data per-block by using an additional data layer which is essentially a property of the block (note that blocks cannot actually store anything in themselves unless they are tile entities; otherwise, you either have different blocks (all blocks in 1.13+, which already has more than 8000 blocks; note that "unlimited" blocks does not mean that in practice since as the block list gets longer it uses more resources and slows down the game; for comparison, 1.12 only had around 250 blocks with all variations either using metadata or determined at render time. Light is still stored entirely separate from blocks in 1.13 since otherwise you'd need 256 times as many block states to store skylight and block light). You'd still need to perform the updates when placing/removing light sources, ideally in a way that respects obstacles, hence using the same algorithm that light uses (otherwise, it is a much simpler matter of iterating over a taxicab volume matching the radius of the light source, but this would ignore walls).
The Meaning of Life, the Universe, and Everything.
Join Date:
7/6/2017
Posts:
51
Member Details
@TheMasterCaver Ah i see, i assumed that it would be a relatively simple and lag-less process.
Though, from what you’ve explained to me, it seems like it would be possible to have a light source block that changed the light level in an area (though a far smaller area than i previously stated). Instead though, the light level would be set at 8 constistently thoughout the area rather than decaying the further from the source it was. So the entire area is ‘lit up’, above the level mobs can spawn at, though there would be no visiual indicator for the light.
In this way, the amount of ‘Dark Lights’ are limited and every light source block does not have an increased radius. Would this work in terms of coding and reducing potential lag?
Due to how light levels work in Minecraft, we currently can not use dark areas in Survival buildings safely due to hostile mobs spawing. However, this is intended to change that.
The basic idea is to add a radius to all light sources, double the light source’s light radius, which prevents hostile mobs from spawing. What this would mean is that the effective radius of say a Sea Lantern goes from 8 (as even though it has a light level of 14, mobs spawn in light level 7 or less) to 28.
This could revolutionise how light sources are used in building, no longer do we have to litter our builds with torches in an attempt to prevent spawning. We can now use dark areas for ambience without worrying about them spawning mobs. We can use less light source blocks and save on resources.
This would be a lag-free way of reducing hostile mob spawning in player builds as it would not change light levels. It would also not reduce hostile mob spawning in the world in general, only where a light source has been placed down. I realise that this could reduce hostile mobs in the Nether; to combat this, Nether mobs could ignore the ‘no hostile mob spawn’ radius of fire, lava and glowstone. This would allow the player to still build safely in the Nether but without reducing how many hostile mobs spawn.
Edit: To make it clear, the area inside the radius would be marked as non-spawnable for hostile mobs, the same way blocks like glass are considered non-spawnable by the game.
Sounds good.
Thank you, i got this idea from hearing about the new Lantern that is being added, it reminded me about how difficult it is to use dark spaces safely.
I do not see how this can be implemented without causing lag - currently to check for the light level the game simply has to read the saved light value from the chunk data, a simple operation; with your suggestion they would have to check every single block within a 30 block radius, a volume of 34279 blocks (29 blocks by taxicab from the center block).
Likewise, they could add a new data layer (in addition to light) that indicates whether a mob can spawn but it would still cause issues when placing/removing light sources as again a volume of up to 34279 blocks needs to be updated (for comparison, a light level of 15 only needs to update a volume of 4089 blocks). You'd need to be able to update about 9 times faster to offset the impact of updating spawnable areas and I doubt that the "lighting engine rewrite" they did in 1.14 even offsets the performance degradations due to poor programming practices since 1.6.4 (my own rewrite is about 3-4 times faster than vanilla 1.6.4, which still means a 2-3x drop in performance).
Another solution could be to make a list of all light sources and compare the distances to each one but this has its own issues, especially when there are many light sources, since checking a huge list would take a long time (my worlds have an average of around 1500 torches within the area mobs can spawn in due to torches placed while caving; worst case the entire list would need to be checked).
Of course, this all assumes the current spawning mechanics, where the game makes up to 3600 attempts to spawn a mob per tick per player (a pack of 4 mobs in each chunk within a 15x15 chunk area around each player, for each of 4 categories of mobs, with passive only once every 400 ticks), which is really far in excess of what is needed, even 1/10 that rate (for non-passive mobs) would likely not be noticeable in normal situations (of course this would enrage most of the playerbase as they rely on mob farms which would run at 1/10 the throughput. I do not consider building massive automated mob farms to be a legit way of playing though). This is still far too high considering that 34279 * 360 = 12340440 checks (for perspective, I measured the cost of allocating and reading from a BlockPos object at 100 nanoseconds, not including any of the other code that reads from a chunk, or garbage collection - that's 1.23 seconds per tick which is only supposed to take 0.05 seconds. If they would get rid of code like BlockPos the game would run much better - allocating and passing in/reading 3 ints only took 2 nanoseconds - but even that still adds up to nearly half the allowed tick time, and again, without any of the other code the game needs to access and read data from a chunk).
TheMasterCaver's First World - possibly the most caved-out world in Minecraft history - includes world download.
TheMasterCaver's World - my own version of Minecraft largely based on my views of how the game should have evolved since 1.6.4.
Why do I still play in 1.6.4?
While i do not think this would work, at all, i like the idea of having a dark room with no spawning in it. I fixed this by slabbing the entire floor, but it would be nice with something new. Maybe a special block that prevents spawning in a, for example, 50 block radius like the beacon?
If so, maybe just add a new "enchantment" to the beacon that prevents mobspawning alltogether within its range? Just a thought.
@TheMasterCaver It would simply state that the blocks in that radius are non-spawnable, so when the game attempted to spawn mobs in a chunk, it would read any blocks in that area as non-spawnable for hostile mobs, much in the same way glass is non-spawnable.
@Kris_Eike That is an idea i’ve heard thrown about before but that would mean having to have these ghastly beams of light everywhere i wanted to use dark spaces. The whole idea would be to create an ambiance, a huge beam of light would ruin that. It could be useful if beacons didn’t need sky access but it would still be a clunky way of doing it.
And how exactly would the game know if the blocks are non-spawnable? It needs some way to either find a light-emitting block or mark all blocks within the range with a special data tag (like light level), which in turn requires marking/unmarking the blocks within range when they are placed/removed. Glass is simply nonspawnable as a simple property of the block itself - the game only needs to check the block right below the point chosen for spawning, nothing else.
Also, I have actual experience with writing the sort of code that would be needed to find light sources as my mod's cave maps work by searching for a light level of 6 or more above a non-air block, then searching for a torch within 8 blocks by taxicab distance (it would be better to search for valid blocks around torches instead but the way maps update means that you can only update the current column):
This also shows what I had to do to maximize performance so it was acceptable enough to update a 32 block radius with 1/16 of columns updated per tick (this means that only about 200 points are checked per tick, and again, the radius required for light sources to be detected up to 30 blocks away means that a much larger volume needs to be checked per point; either that, or light sources themselves would need to "light" blocks to mark them as unspawnable - at the very least, this would have to be limited to special light sources, not just anything). I don't know if there is a better algorithm other than the one I used, which is a "breadth-first search", the same thing that the lighting engine uses and is generally recommended for this purpose for its efficiency, with the additional complication that I need to store a map of visited points (which is otherwise the light data set by the lighting engine).
You could use a simpler and much faster algorithm that simply checks blocks without propagating outwards if you decide to ignore walls but you are still checking or changing a lot of blocks and it would be harder to control which areas can spawn mobs (e.g. no placing torches on the roof of a darkroom spawner), and again, code changes in 1.8+ greatly reduce the efficiency of the game (for example, you can't just handle a numerical block ID as a primitive int directly read from the chunk storage arrays* (or a packed block ID + light level or block ID + metadata which is read in a single operation) but as "IBlockState" objects which also need far more memory to store).
*This gives you an idea of just how complicated they have made the code in 1.8+:
How block IDs are stored/accessed in 1.6.4:
In TMCW it is just this; I removed the "blockMSBArray", which provides support for block IDs above 255 (which require modifications to work anyway) as metadata already gives you 4080 (minus "air") blocks to work with (I've added hundreds of new "blocks" yet still have around 70 IDs left; code changes have also let me define properties such as light levels according to metadata, while vanilla defines it as a property of the block, so a single block ID can be used for blocks like redstone ore, freeing up such vanilla block IDs, same for properties like hardness and mining level):
This allows me to use a single method call to get a combined block state plus metadata (the overhead of combining/extracting them is more than offset by the reduction in method calls and chunk lookups); I also directly access the data stored in "NibbleArray" for the fastest possible speed (they conveniently made the data field public so I didn't have to modify the class):
Even better yet, passing in a pre-computed index to minimize redundant calculations in methods that reference the same block locations multiple times (all of this has been benchmarked (in a real scenario, i.e. in the game) so the actual impacts on performance are known. Sure, some of these changes only affect performance by like 5% but in my opinion every bit counts as it all adds up; this is why despite being more complex world generation in TMCW is 1.5 times faster than 1.6.4 - and 10 times faster than 1.13, same for things like game startup and average server tick time. Even chunk rendering speed is faster than Optifine + vanilla due to the fact that it heavily accesses chunk data, especially with smooth lighting (Optifine doesn't even make any optimizations to actual block rendering or chunk data access, just controls how chunk updates are scheduled and how render data is sent to the GPU):
For comparison, here is code for 1.12 that I found online, starting from the same class (ExtendedBlockStorage):
There is absolutely no way that code will ever reach the same level of performance (or readability) - and examples like this are everywhere in 1.8+.
Also of note, in 1.8 Mojang made it so that mobs would check for exploding creepers - a change which was reverted in the very next patch (1.8.1) due to the lag it caused, which is not much different from checking a list of block positions for light-emitting blocks (all entities are stored in a list so it only has to go through it and compare the distance to each one, not do some sort of block-by-block search). Similarly, mob spawning would cause lag when the player was more than 128 blocks above a spawnable surface since they would spawn and instantly despawn at a very high rate (up to 3600 times per tick over an ocean - this may also explain why mob spawning is so different in Bedrock - the Java spawning algorithm wastes huge amounts of resources in trying to spawn mobs at such extreme rates (Bedrock only does one spawn cycle per chunk every 200 ticks (presumably staggered out, not all chunks in one tick), which still means one pack spawn attempt per chunk every 10 seconds; Bedrock also searches down from the highest block for spawnable surfaces, not just chooses some random point which is not even valid most of the time, so the effective spawn rate is much higher; on Java only 1/256 attempts will succeed for a max-height chunk, 1/63 at sea level. Of course, as mentioned before this is why it is useless to try building mob farms on Bedrock).
TheMasterCaver's First World - possibly the most caved-out world in Minecraft history - includes world download.
TheMasterCaver's World - my own version of Minecraft largely based on my views of how the game should have evolved since 1.6.4.
Why do I still play in 1.6.4?
@TheMasterCaver Now i don’t know how to write code so forgive me for using layman’s terms. Could there not simply be a code that states ‘set block property spawnable false’ on all blocks in the radius? Or essentially ‘set light level 14’ on a block (though there would not actually be any visible light to avoid lighting updates). Either of these would prevent hostile mobs spawning and, if the block property can be changed, surely this would mean there is very little lag?
Adding a greater variety of nonspawnable blocks (including those onto which one could place redstone dust/components etc) would be another way of approaching the issue. [That MS/Mj seems to be (finally) listening to the calls for a greater variety of slabs/stairs/walls suggests this has the potential to be viable… hopefully without a multiyear wait.]
RE marking blocks as nonspwanable:
Without getting technical [TMC has made a strong explanation from that angle], the minimum required to implement this would be for the game to check each block each tick not only for what the block is and the current light level (both already occur) but also an additional check/calculation for whether the block has been marked as non-spawnable.
Current beacon effects all act on players (the number of which is comparatively 'small').
Perhaps it would be possible to use modifying 'things' to change block properties to prevent spawning via something akin to the way guardians are restricted to ocean monuments with the 'thing' creating a volume in which only No_Mobs could spawn. (No_Mobs would be place holders that had no collision box, could not move, and automatically despawned. )
[Insufficient knowledge of the code to predict how dificult this would be or the potential performance hit.]
This is essentially the same thing as lighting; the game stores light data per-block by using an additional data layer which is essentially a property of the block (note that blocks cannot actually store anything in themselves unless they are tile entities; otherwise, you either have different blocks (all blocks in 1.13+, which already has more than 8000 blocks; note that "unlimited" blocks does not mean that in practice since as the block list gets longer it uses more resources and slows down the game; for comparison, 1.12 only had around 250 blocks with all variations either using metadata or determined at render time. Light is still stored entirely separate from blocks in 1.13 since otherwise you'd need 256 times as many block states to store skylight and block light). You'd still need to perform the updates when placing/removing light sources, ideally in a way that respects obstacles, hence using the same algorithm that light uses (otherwise, it is a much simpler matter of iterating over a taxicab volume matching the radius of the light source, but this would ignore walls).
TheMasterCaver's First World - possibly the most caved-out world in Minecraft history - includes world download.
TheMasterCaver's World - my own version of Minecraft largely based on my views of how the game should have evolved since 1.6.4.
Why do I still play in 1.6.4?
@TheMasterCaver Ah i see, i assumed that it would be a relatively simple and lag-less process.
Though, from what you’ve explained to me, it seems like it would be possible to have a light source block that changed the light level in an area (though a far smaller area than i previously stated). Instead though, the light level would be set at 8 constistently thoughout the area rather than decaying the further from the source it was. So the entire area is ‘lit up’, above the level mobs can spawn at, though there would be no visiual indicator for the light.
In this way, the amount of ‘Dark Lights’ are limited and every light source block does not have an increased radius. Would this work in terms of coding and reducing potential lag?