2010-12-27 02:13:03 +00:00
package org.bukkit.craftbukkit ;
2018-08-29 07:44:36 +10:00
import com.google.common.base.Preconditions ;
2020-06-25 10:00:00 +10:00
import com.google.common.base.Predicates ;
2021-11-22 09:00:00 +11:00
import com.mojang.serialization.Codec ;
2012-03-01 13:54:59 -06:00
import java.util.Arrays ;
2019-07-08 12:14:16 +10:00
import java.util.Collection ;
2021-09-01 18:55:18 +10:00
import java.util.Objects ;
2021-11-01 18:54:44 +11:00
import java.util.concurrent.locks.LockSupport ;
import java.util.function.BooleanSupplier ;
2020-06-25 10:00:00 +10:00
import java.util.function.Predicate ;
2021-03-16 09:00:00 +11:00
import net.minecraft.core.BlockPosition ;
2022-03-01 02:00:00 +11:00
import net.minecraft.core.Holder ;
2021-03-16 09:00:00 +11:00
import net.minecraft.core.IRegistry ;
import net.minecraft.core.SectionPosition ;
2022-12-08 03:00:00 +11:00
import net.minecraft.core.registries.Registries ;
2021-11-22 09:00:00 +11:00
import net.minecraft.nbt.DynamicOpsNBT ;
2021-03-16 09:00:00 +11:00
import net.minecraft.nbt.NBTTagCompound ;
import net.minecraft.server.level.WorldServer ;
2021-11-01 18:54:44 +11:00
import net.minecraft.util.thread.ThreadedMailbox ;
2021-03-16 09:00:00 +11:00
import net.minecraft.world.level.ChunkCoordIntPair ;
import net.minecraft.world.level.EnumSkyBlock ;
2021-11-22 09:00:00 +11:00
import net.minecraft.world.level.biome.BiomeBase ;
import net.minecraft.world.level.biome.Biomes ;
2021-03-16 09:00:00 +11:00
import net.minecraft.world.level.block.Blocks ;
import net.minecraft.world.level.block.state.IBlockData ;
import net.minecraft.world.level.chunk.ChunkSection ;
import net.minecraft.world.level.chunk.DataPaletteBlock ;
2021-06-11 15:00:00 +10:00
import net.minecraft.world.level.chunk.IChunkAccess ;
2021-03-16 09:00:00 +11:00
import net.minecraft.world.level.chunk.NibbleArray ;
2022-06-08 02:00:00 +10:00
import net.minecraft.world.level.chunk.PalettedContainerRO ;
2023-04-09 05:24:52 +02:00
import net.minecraft.world.level.chunk.ProtoChunkExtension ;
2024-04-24 01:15:00 +10:00
import net.minecraft.world.level.chunk.status.ChunkStatus ;
2021-11-22 09:00:00 +11:00
import net.minecraft.world.level.chunk.storage.ChunkRegionLoader ;
2021-11-01 18:54:44 +11:00
import net.minecraft.world.level.chunk.storage.EntityStorage ;
2021-09-01 18:55:18 +10:00
import net.minecraft.world.level.entity.PersistentEntitySectionManager ;
2021-03-16 09:00:00 +11:00
import net.minecraft.world.level.levelgen.HeightMap ;
import net.minecraft.world.level.levelgen.SeededRandom ;
2023-06-08 01:30:00 +10:00
import net.minecraft.world.level.lighting.LevelLightEngine ;
2010-12-27 02:13:03 +00:00
import org.bukkit.Chunk ;
2019-04-23 14:54:36 +10:00
import org.bukkit.ChunkSnapshot ;
2011-01-04 14:17:05 +00:00
import org.bukkit.World ;
2023-01-28 11:49:46 +11:00
import org.bukkit.block.Biome ;
2011-02-01 23:49:28 +01:00
import org.bukkit.block.Block ;
2011-03-07 13:48:35 -05:00
import org.bukkit.block.BlockState ;
2019-09-08 11:39:08 +10:00
import org.bukkit.block.data.BlockData ;
2023-09-22 03:02:16 +10:00
import org.bukkit.craftbukkit.block.CraftBiome ;
2011-02-01 23:49:28 +01:00
import org.bukkit.craftbukkit.block.CraftBlock ;
2019-09-08 11:39:08 +10:00
import org.bukkit.craftbukkit.block.data.CraftBlockData ;
2019-04-23 14:54:36 +10:00
import org.bukkit.entity.Entity ;
2024-02-04 10:04:35 +11:00
import org.bukkit.generator.structure.GeneratedStructure ;
import org.bukkit.generator.structure.Structure ;
2020-10-17 17:37:49 +11:00
import org.bukkit.persistence.PersistentDataContainer ;
2019-07-08 12:14:16 +10:00
import org.bukkit.plugin.Plugin ;
2010-12-27 02:13:03 +00:00
public class CraftChunk implements Chunk {
2012-09-09 23:19:28 -05:00
private final WorldServer worldServer ;
private final int x ;
private final int z ;
2022-06-08 02:00:00 +10:00
private static final DataPaletteBlock < IBlockData > emptyBlockIDs = new DataPaletteBlock < > ( net . minecraft . world . level . block . Block . BLOCK_STATE_REGISTRY , Blocks . AIR . defaultBlockState ( ) , DataPaletteBlock . d . SECTION_STATES ) ;
2023-10-15 20:20:30 +11:00
private static final byte [ ] FULL_LIGHT = new byte [ 2048 ] ;
private static final byte [ ] EMPTY_LIGHT = new byte [ 2048 ] ;
2011-04-20 19:05:14 +02:00
2021-03-16 09:00:00 +11:00
public CraftChunk ( net . minecraft . world . level . chunk . Chunk chunk ) {
2023-04-02 13:06:59 +10:00
worldServer = chunk . level ;
x = chunk . getPos ( ) . x ;
z = chunk . getPos ( ) . z ;
2010-12-27 02:13:03 +00:00
}
2021-09-01 18:55:18 +10:00
public CraftChunk ( WorldServer worldServer , int x , int z ) {
this . worldServer = worldServer ;
this . x = x ;
this . z = z ;
}
2019-04-28 11:38:01 +10:00
@Override
2011-01-04 14:17:05 +00:00
public World getWorld ( ) {
2011-02-20 23:22:28 +01:00
return worldServer . getWorld ( ) ;
2011-02-01 23:49:28 +01:00
}
2011-12-08 00:33:59 -05:00
public CraftWorld getCraftWorld ( ) {
return ( CraftWorld ) getWorld ( ) ;
}
2023-04-02 13:06:59 +10:00
public IChunkAccess getHandle ( ChunkStatus chunkStatus ) {
2023-04-09 05:24:52 +02:00
IChunkAccess chunkAccess = worldServer . getChunk ( x , z , chunkStatus ) ;
// SPIGOT-7332: Get unwrapped extension
if ( chunkAccess instanceof ProtoChunkExtension extension ) {
return extension . getWrapped ( ) ;
}
return chunkAccess ;
2011-05-14 16:29:42 +02:00
}
2011-03-11 19:39:09 +00:00
2019-04-28 11:38:01 +10:00
@Override
2010-12-27 02:13:03 +00:00
public int getX ( ) {
2011-02-20 23:22:28 +01:00
return x ;
2010-12-27 02:13:03 +00:00
}
2019-04-28 11:38:01 +10:00
@Override
2010-12-27 02:13:03 +00:00
public int getZ ( ) {
2011-02-20 23:22:28 +01:00
return z ;
2010-12-27 02:13:03 +00:00
}
2010-12-29 00:29:18 +00:00
@Override
public String toString ( ) {
2011-02-01 23:49:28 +01:00
return " CraftChunk{ " + " x= " + getX ( ) + " z= " + getZ ( ) + '}' ;
}
2019-04-28 11:38:01 +10:00
@Override
2011-02-01 23:49:28 +01:00
public Block getBlock ( int x , int y , int z ) {
2023-04-02 13:06:59 +10:00
validateChunkCoordinates ( worldServer . getMinBuildHeight ( ) , worldServer . getMaxBuildHeight ( ) , x , y , z ) ;
2018-08-29 07:44:36 +10:00
2018-07-15 10:00:00 +10:00
return new CraftBlock ( worldServer , new BlockPosition ( ( this . x < < 4 ) | x , y , ( this . z < < 4 ) | z ) ) ;
2010-12-29 00:29:18 +00:00
}
2011-03-07 13:48:35 -05:00
2021-09-06 18:51:39 +10:00
@Override
public boolean isEntitiesLoaded ( ) {
2021-11-22 09:00:00 +11:00
return getCraftWorld ( ) . getHandle ( ) . entityManager . areEntitiesLoaded ( ChunkCoordIntPair . asLong ( x , z ) ) ;
2021-09-06 18:51:39 +10:00
}
2019-04-28 11:38:01 +10:00
@Override
2011-03-07 13:48:35 -05:00
public Entity [ ] getEntities ( ) {
2019-05-16 01:11:20 +02:00
if ( ! isLoaded ( ) ) {
getWorld ( ) . getChunkAt ( x , z ) ; // Transient load for this tick
}
2011-04-02 17:56:06 +02:00
2021-09-01 18:55:18 +10:00
PersistentEntitySectionManager < net . minecraft . world . entity . Entity > entityManager = getCraftWorld ( ) . getHandle ( ) . entityManager ;
2021-11-22 09:00:00 +11:00
long pair = ChunkCoordIntPair . asLong ( x , z ) ;
2021-09-01 18:55:18 +10:00
2021-11-22 09:00:00 +11:00
if ( entityManager . areEntitiesLoaded ( pair ) ) {
2021-09-01 18:55:18 +10:00
return entityManager . getEntities ( new ChunkCoordIntPair ( x , z ) ) . stream ( )
. map ( net . minecraft . world . entity . Entity : : getBukkitEntity )
. filter ( Objects : : nonNull ) . toArray ( Entity [ ] : : new ) ;
}
2021-11-22 09:00:00 +11:00
entityManager . ensureChunkQueuedForLoad ( pair ) ; // Start entity loading
2021-09-01 18:55:18 +10:00
2021-11-01 18:54:44 +11:00
// SPIGOT-6772: Use entity mailbox and re-schedule entities if they get unloaded
ThreadedMailbox < Runnable > mailbox = ( ( EntityStorage ) entityManager . permanentStorage ) . entityDeserializerQueue ;
BooleanSupplier supplier = ( ) - > {
2021-09-01 18:55:18 +10:00
// only execute inbox if our entities are not present
2021-11-22 09:00:00 +11:00
if ( entityManager . areEntitiesLoaded ( pair ) ) {
2021-09-01 18:55:18 +10:00
return true ;
}
2021-11-01 18:54:44 +11:00
if ( ! entityManager . isPending ( pair ) ) {
// Our entities got unloaded, this should normally not happen.
2021-11-22 09:00:00 +11:00
entityManager . ensureChunkQueuedForLoad ( pair ) ; // Re-start entity loading
2021-11-01 18:54:44 +11:00
}
2021-09-01 18:55:18 +10:00
// tick loading inbox, which loads the created entities to the world
// (if present)
entityManager . tick ( ) ;
// check if our entities are loaded
2021-11-22 09:00:00 +11:00
return entityManager . areEntitiesLoaded ( pair ) ;
2021-11-01 18:54:44 +11:00
} ;
// now we wait until the entities are loaded,
// the converting from NBT to entity object is done on the main Thread which is why we wait
while ( ! supplier . getAsBoolean ( ) ) {
2021-11-22 09:00:00 +11:00
if ( mailbox . size ( ) ! = 0 ) {
2021-11-01 18:54:44 +11:00
mailbox . run ( ) ;
} else {
Thread . yield ( ) ;
LockSupport . parkNanos ( " waiting for entity loading " , 100000L ) ;
}
}
2021-09-01 18:55:18 +10:00
return entityManager . getEntities ( new ChunkCoordIntPair ( x , z ) ) . stream ( )
. map ( net . minecraft . world . entity . Entity : : getBukkitEntity )
. filter ( Objects : : nonNull ) . toArray ( Entity [ ] : : new ) ;
2011-03-07 13:48:35 -05:00
}
2019-04-28 11:38:01 +10:00
@Override
2011-03-07 13:48:35 -05:00
public BlockState [ ] getTileEntities ( ) {
2019-05-16 01:11:20 +02:00
if ( ! isLoaded ( ) ) {
getWorld ( ) . getChunkAt ( x , z ) ; // Transient load for this tick
}
2011-03-07 13:48:35 -05:00
int index = 0 ;
2023-04-02 13:06:59 +10:00
IChunkAccess chunk = getHandle ( ChunkStatus . FULL ) ;
2014-11-26 08:32:16 +11:00
2021-06-11 15:00:00 +10:00
BlockState [ ] entities = new BlockState [ chunk . blockEntities . size ( ) ] ;
2012-03-01 13:54:59 -06:00
2023-04-02 13:06:59 +10:00
for ( BlockPosition position : chunk . blockEntities . keySet ( ) ) {
2014-11-30 12:15:56 +00:00
entities [ index + + ] = worldServer . getWorld ( ) . getBlockAt ( position . getX ( ) , position . getY ( ) , position . getZ ( ) ) . getState ( ) ;
2011-03-07 13:48:35 -05:00
}
2015-02-26 22:41:06 +00:00
2011-03-07 13:48:35 -05:00
return entities ;
}
2011-02-20 23:22:28 +01:00
2023-04-02 13:06:59 +10:00
@Override
public boolean isGenerated ( ) {
IChunkAccess chunk = getHandle ( ChunkStatus . EMPTY ) ;
return chunk . getStatus ( ) . isOrAfter ( ChunkStatus . FULL ) ;
}
2019-04-28 11:38:01 +10:00
@Override
2011-09-08 02:54:45 +08:00
public boolean isLoaded ( ) {
2011-07-28 00:32:58 -04:00
return getWorld ( ) . isChunkLoaded ( this ) ;
}
2019-04-28 11:38:01 +10:00
@Override
2011-07-28 00:32:58 -04:00
public boolean load ( ) {
return getWorld ( ) . loadChunk ( getX ( ) , getZ ( ) , true ) ;
}
2019-04-28 11:38:01 +10:00
@Override
2011-07-28 00:32:58 -04:00
public boolean load ( boolean generate ) {
return getWorld ( ) . loadChunk ( getX ( ) , getZ ( ) , generate ) ;
}
2019-04-28 11:38:01 +10:00
@Override
2011-07-28 00:32:58 -04:00
public boolean unload ( ) {
return getWorld ( ) . unloadChunk ( getX ( ) , getZ ( ) ) ;
}
2017-03-23 12:42:01 -04:00
@Override
public boolean isSlimeChunk ( ) {
// 987234911L is deterimined in EntitySlime when seeing if a slime can spawn in a chunk
2021-11-22 09:00:00 +11:00
return SeededRandom . seedSlimeChunk ( getX ( ) , getZ ( ) , getWorld ( ) . getSeed ( ) , 987234911L ) . nextInt ( 10 ) = = 0 ;
2017-03-23 12:42:01 -04:00
}
2019-04-28 11:38:01 +10:00
@Override
2011-07-28 00:32:58 -04:00
public boolean unload ( boolean save ) {
return getWorld ( ) . unloadChunk ( getX ( ) , getZ ( ) , save ) ;
}
2018-12-27 12:44:50 +11:00
@Override
public boolean isForceLoaded ( ) {
return getWorld ( ) . isChunkForceLoaded ( getX ( ) , getZ ( ) ) ;
}
@Override
public void setForceLoaded ( boolean forced ) {
getWorld ( ) . setChunkForceLoaded ( getX ( ) , getZ ( ) , forced ) ;
}
2019-07-08 12:14:16 +10:00
@Override
public boolean addPluginChunkTicket ( Plugin plugin ) {
return getWorld ( ) . addPluginChunkTicket ( getX ( ) , getZ ( ) , plugin ) ;
}
@Override
public boolean removePluginChunkTicket ( Plugin plugin ) {
return getWorld ( ) . removePluginChunkTicket ( getX ( ) , getZ ( ) , plugin ) ;
}
@Override
public Collection < Plugin > getPluginChunkTickets ( ) {
return getWorld ( ) . getPluginChunkTickets ( getX ( ) , getZ ( ) ) ;
}
2019-09-07 16:48:30 +10:00
@Override
public long getInhabitedTime ( ) {
2023-04-02 13:06:59 +10:00
return getHandle ( ChunkStatus . EMPTY ) . getInhabitedTime ( ) ;
2019-09-07 16:48:30 +10:00
}
@Override
public void setInhabitedTime ( long ticks ) {
Preconditions . checkArgument ( ticks > = 0 , " ticks cannot be negative " ) ;
2023-04-02 13:06:59 +10:00
getHandle ( ChunkStatus . STRUCTURE_STARTS ) . setInhabitedTime ( ticks ) ;
2019-09-07 16:48:30 +10:00
}
2019-09-08 11:39:08 +10:00
@Override
public boolean contains ( BlockData block ) {
Preconditions . checkArgument ( block ! = null , " Block cannot be null " ) ;
2020-06-25 10:00:00 +10:00
Predicate < IBlockData > nms = Predicates . equalTo ( ( ( CraftBlockData ) block ) . getState ( ) ) ;
2023-04-02 13:06:59 +10:00
for ( ChunkSection section : getHandle ( ChunkStatus . FULL ) . getSections ( ) ) {
2021-11-22 09:00:00 +11:00
if ( section ! = null & & section . getStates ( ) . maybeHas ( nms ) ) {
2019-09-08 11:39:08 +10:00
return true ;
}
}
return false ;
}
2023-01-28 11:49:46 +11:00
@Override
public boolean contains ( Biome biome ) {
Preconditions . checkArgument ( biome ! = null , " Biome cannot be null " ) ;
2023-04-02 13:06:59 +10:00
IChunkAccess chunk = getHandle ( ChunkStatus . BIOMES ) ;
2023-09-22 03:02:16 +10:00
Predicate < Holder < BiomeBase > > nms = Predicates . equalTo ( CraftBiome . bukkitToMinecraftHolder ( biome ) ) ;
2023-04-02 13:06:59 +10:00
for ( ChunkSection section : chunk . getSections ( ) ) {
2023-01-28 11:49:46 +11:00
if ( section ! = null & & section . getBiomes ( ) . maybeHas ( nms ) ) {
return true ;
}
}
return false ;
}
2019-04-28 11:38:01 +10:00
@Override
2011-06-07 03:34:23 -04:00
public ChunkSnapshot getChunkSnapshot ( ) {
2011-06-17 09:23:19 -04:00
return getChunkSnapshot ( true , false , false ) ;
}
2019-04-28 11:38:01 +10:00
@Override
2012-03-01 13:54:59 -06:00
public ChunkSnapshot getChunkSnapshot ( boolean includeMaxBlockY , boolean includeBiome , boolean includeBiomeTempRain ) {
2023-04-02 13:06:59 +10:00
IChunkAccess chunk = getHandle ( ChunkStatus . FULL ) ;
2011-06-17 09:23:19 -04:00
2014-06-26 13:05:08 -05:00
ChunkSection [ ] cs = chunk . getSections ( ) ;
2018-07-15 10:00:00 +10:00
DataPaletteBlock [ ] sectionBlockIDs = new DataPaletteBlock [ cs . length ] ;
2012-03-01 13:54:59 -06:00
byte [ ] [ ] sectionSkyLights = new byte [ cs . length ] [ ] ;
byte [ ] [ ] sectionEmitLights = new byte [ cs . length ] [ ] ;
boolean [ ] sectionEmpty = new boolean [ cs . length ] ;
2022-06-08 02:00:00 +10:00
PalettedContainerRO < Holder < BiomeBase > > [ ] biome = ( includeBiome | | includeBiomeTempRain ) ? new DataPaletteBlock [ cs . length ] : null ;
2021-11-22 09:00:00 +11:00
2022-12-08 03:00:00 +11:00
IRegistry < BiomeBase > iregistry = worldServer . registryAccess ( ) . registryOrThrow ( Registries . BIOME ) ;
2022-06-08 02:00:00 +10:00
Codec < PalettedContainerRO < Holder < BiomeBase > > > biomeCodec = DataPaletteBlock . codecRO ( iregistry . asHolderIdMap ( ) , iregistry . holderByNameCodec ( ) , DataPaletteBlock . d . SECTION_BIOMES , iregistry . getHolderOrThrow ( Biomes . PLAINS ) ) ;
2012-03-01 13:54:59 -06:00
for ( int i = 0 ; i < cs . length ; i + + ) {
2021-11-22 09:00:00 +11:00
NBTTagCompound data = new NBTTagCompound ( ) ;
2024-04-24 01:15:00 +10:00
data . put ( " block_states " , ChunkRegionLoader . BLOCK_STATE_CODEC . encodeStart ( DynamicOpsNBT . INSTANCE , cs [ i ] . getStates ( ) ) . getOrThrow ( ) ) ;
sectionBlockIDs [ i ] = ChunkRegionLoader . BLOCK_STATE_CODEC . parse ( DynamicOpsNBT . INSTANCE , data . getCompound ( " block_states " ) ) . getOrThrow ( ChunkRegionLoader . a : : new ) ;
2024-05-23 21:14:56 +10:00
sectionEmpty [ i ] = cs [ i ] . hasOnlyAir ( ) ;
2021-11-22 09:00:00 +11:00
2023-06-08 01:30:00 +10:00
LevelLightEngine lightengine = worldServer . getLightEngine ( ) ;
2023-10-05 13:12:41 +02:00
NibbleArray skyLightArray = lightengine . getLayerListener ( EnumSkyBlock . SKY ) . getDataLayerData ( SectionPosition . of ( x , chunk . getSectionYFromSectionIndex ( i ) , z ) ) ; // SPIGOT-7498: Convert section index
2021-11-22 09:00:00 +11:00
if ( skyLightArray = = null ) {
2023-10-15 20:20:30 +11:00
sectionSkyLights [ i ] = worldServer . dimensionType ( ) . hasSkyLight ( ) ? FULL_LIGHT : EMPTY_LIGHT ;
2021-11-22 09:00:00 +11:00
} else {
sectionSkyLights [ i ] = new byte [ 2048 ] ;
System . arraycopy ( skyLightArray . getData ( ) , 0 , sectionSkyLights [ i ] , 0 , 2048 ) ;
}
2023-10-05 13:12:41 +02:00
NibbleArray emitLightArray = lightengine . getLayerListener ( EnumSkyBlock . BLOCK ) . getDataLayerData ( SectionPosition . of ( x , chunk . getSectionYFromSectionIndex ( i ) , z ) ) ; // SPIGOT-7498: Convert section index
2021-11-22 09:00:00 +11:00
if ( emitLightArray = = null ) {
2023-10-15 20:20:30 +11:00
sectionEmitLights [ i ] = EMPTY_LIGHT ;
2021-11-22 09:00:00 +11:00
} else {
sectionEmitLights [ i ] = new byte [ 2048 ] ;
System . arraycopy ( emitLightArray . getData ( ) , 0 , sectionEmitLights [ i ] , 0 , 2048 ) ;
}
if ( biome ! = null ) {
2024-04-24 01:15:00 +10:00
data . put ( " biomes " , biomeCodec . encodeStart ( DynamicOpsNBT . INSTANCE , cs [ i ] . getBiomes ( ) ) . getOrThrow ( ) ) ;
biome [ i ] = biomeCodec . parse ( DynamicOpsNBT . INSTANCE , data . getCompound ( " biomes " ) ) . getOrThrow ( ChunkRegionLoader . a : : new ) ;
2012-03-01 13:54:59 -06:00
}
}
2018-07-15 10:00:00 +10:00
HeightMap hmap = null ;
2012-03-01 13:54:59 -06:00
if ( includeMaxBlockY ) {
2021-06-11 15:00:00 +10:00
hmap = new HeightMap ( chunk , HeightMap . Type . MOTION_BLOCKING ) ;
2021-11-22 09:00:00 +11:00
hmap . setRawData ( chunk , HeightMap . Type . MOTION_BLOCKING , chunk . heightmaps . get ( HeightMap . Type . MOTION_BLOCKING ) . getRawData ( ) ) ;
2011-06-17 09:23:19 -04:00
}
2012-03-01 13:54:59 -06:00
World world = getWorld ( ) ;
2022-03-01 02:00:00 +11:00
return new CraftChunkSnapshot ( getX ( ) , getZ ( ) , chunk . getMinBuildHeight ( ) , chunk . getMaxBuildHeight ( ) , world . getName ( ) , world . getFullTime ( ) , sectionBlockIDs , sectionSkyLights , sectionEmitLights , sectionEmpty , hmap , iregistry , biome ) ;
2011-06-07 03:34:23 -04:00
}
2020-10-17 17:37:49 +11:00
@Override
public PersistentDataContainer getPersistentDataContainer ( ) {
2023-04-02 13:06:59 +10:00
return getHandle ( ChunkStatus . STRUCTURE_STARTS ) . persistentDataContainer ;
}
2023-04-29 17:37:52 +10:00
@Override
public LoadLevel getLoadLevel ( ) {
net . minecraft . world . level . chunk . Chunk chunk = worldServer . getChunkIfLoaded ( getX ( ) , getZ ( ) ) ;
if ( chunk = = null ) {
return LoadLevel . UNLOADED ;
}
return LoadLevel . values ( ) [ chunk . getFullStatus ( ) . ordinal ( ) ] ;
}
2024-02-04 10:04:35 +11:00
@Override
public Collection < GeneratedStructure > getStructures ( ) {
return getCraftWorld ( ) . getStructures ( getX ( ) , getZ ( ) ) ;
}
@Override
public Collection < GeneratedStructure > getStructures ( Structure structure ) {
return getCraftWorld ( ) . getStructures ( getX ( ) , getZ ( ) , structure ) ;
}
2023-04-02 13:06:59 +10:00
@Override
public boolean equals ( Object o ) {
if ( this = = o ) return true ;
if ( o = = null | | getClass ( ) ! = o . getClass ( ) ) return false ;
CraftChunk that = ( CraftChunk ) o ;
if ( x ! = that . x ) return false ;
if ( z ! = that . z ) return false ;
return worldServer . equals ( that . worldServer ) ;
}
@Override
public int hashCode ( ) {
int result = worldServer . hashCode ( ) ;
result = 31 * result + x ;
result = 31 * result + z ;
return result ;
2020-10-17 17:37:49 +11:00
}
2011-06-27 00:25:01 +02:00
public static ChunkSnapshot getEmptyChunkSnapshot ( int x , int z , CraftWorld world , boolean includeBiome , boolean includeBiomeTempRain ) {
2022-08-30 21:50:52 +10:00
IChunkAccess actual = world . getHandle ( ) . getChunk ( x , z , ( includeBiome | | includeBiomeTempRain ) ? ChunkStatus . BIOMES : ChunkStatus . EMPTY ) ;
2012-03-01 13:54:59 -06:00
/* Fill with empty data */
2021-06-11 15:00:00 +10:00
int hSection = actual . getSectionsCount ( ) ;
2018-07-15 10:00:00 +10:00
DataPaletteBlock [ ] blockIDs = new DataPaletteBlock [ hSection ] ;
2012-03-01 13:54:59 -06:00
byte [ ] [ ] skyLight = new byte [ hSection ] [ ] ;
byte [ ] [ ] emitLight = new byte [ hSection ] [ ] ;
boolean [ ] empty = new boolean [ hSection ] ;
2022-12-08 03:00:00 +11:00
IRegistry < BiomeBase > iregistry = world . getHandle ( ) . registryAccess ( ) . registryOrThrow ( Registries . BIOME ) ;
2022-03-01 02:00:00 +11:00
DataPaletteBlock < Holder < BiomeBase > > [ ] biome = ( includeBiome | | includeBiomeTempRain ) ? new DataPaletteBlock [ hSection ] : null ;
2022-08-30 21:50:52 +10:00
Codec < PalettedContainerRO < Holder < BiomeBase > > > biomeCodec = DataPaletteBlock . codecRO ( iregistry . asHolderIdMap ( ) , iregistry . holderByNameCodec ( ) , DataPaletteBlock . d . SECTION_BIOMES , iregistry . getHolderOrThrow ( Biomes . PLAINS ) ) ;
2012-03-01 13:54:59 -06:00
for ( int i = 0 ; i < hSection ; i + + ) {
blockIDs [ i ] = emptyBlockIDs ;
2023-10-15 20:20:30 +11:00
skyLight [ i ] = world . getHandle ( ) . dimensionType ( ) . hasSkyLight ( ) ? FULL_LIGHT : EMPTY_LIGHT ;
emitLight [ i ] = EMPTY_LIGHT ;
2012-03-01 13:54:59 -06:00
empty [ i ] = true ;
2021-11-22 09:00:00 +11:00
if ( biome ! = null ) {
2024-04-24 01:15:00 +10:00
biome [ i ] = ( DataPaletteBlock < Holder < BiomeBase > > ) biomeCodec . parse ( DynamicOpsNBT . INSTANCE , biomeCodec . encodeStart ( DynamicOpsNBT . INSTANCE , actual . getSection ( i ) . getBiomes ( ) ) . getOrThrow ( ) ) . getOrThrow ( ChunkRegionLoader . a : : new ) ;
2021-11-22 09:00:00 +11:00
}
2012-03-01 13:54:59 -06:00
}
2022-03-01 02:00:00 +11:00
return new CraftChunkSnapshot ( x , z , world . getMinHeight ( ) , world . getMaxHeight ( ) , world . getName ( ) , world . getFullTime ( ) , blockIDs , skyLight , emitLight , empty , new HeightMap ( actual , HeightMap . Type . MOTION_BLOCKING ) , iregistry , biome ) ;
2013-11-04 07:07:38 -06:00
}
2021-06-11 15:00:00 +10:00
static void validateChunkCoordinates ( int minY , int maxY , int x , int y , int z ) {
2018-08-29 07:44:36 +10:00
Preconditions . checkArgument ( 0 < = x & & x < = 15 , " x out of range (expected 0-15, got %s) " , x ) ;
2021-06-11 15:00:00 +10:00
Preconditions . checkArgument ( minY < = y & & y < = maxY , " y out of range (expected %s-%s, got %s) " , minY , maxY , y ) ;
2018-08-29 07:44:36 +10:00
Preconditions . checkArgument ( 0 < = z & & z < = 15 , " z out of range (expected 0-15, got %s) " , z ) ;
}
2012-03-01 13:54:59 -06:00
static {
2023-10-15 20:20:30 +11:00
Arrays . fill ( FULL_LIGHT , ( byte ) 0xFF ) ;
2011-06-17 09:23:19 -04:00
}
2011-07-28 00:32:58 -04:00
}