public class ExtendedBlockStorage
{
/** Contains the bottom-most Y block represented by this ExtendedBlockStorage. Typically a multiple of 16. */
private int yBase;
/** A total count of the number of non-air blocks in this block storage's Chunk. */
private int blockRefCount;
/**
* Contains the number of blocks in this block storage's parent chunk that require random ticking. Used to cull the
* Chunk from random tick updates for performance reasons.
*/
private int tickRefCount;
private char[] data;
/** The NibbleArray containing a block of Block-light data. */
private NibbleArray blocklightArray;
/** The NibbleArray containing a block of Sky-light data. */
private NibbleArray skylightArray;
public ExtendedBlockStorage(int y, boolean storeSkylight)
{
= y;
= new char[4096];
= new NibbleArray();
if (storeSkylight)
{
= new NibbleArray();
}
}
public IBlockState get(int x, int y, int z)
{
IBlockState iblockstate = (IBlockState)Block.BLOCK_STATE_IDS.getByValue([y << 8 | z << 4 | x]);
return iblockstate != null ? iblockstate : ();
}
public void set(int x, int y, int z, IBlockState state)
{
if (state instanceof )
state = (() state).getClean();
IBlockState iblockstate1 = (x, y, z);
Block block = ();
Block block1 = ();
if (block != )
{
--;
if (())
{
--;
}
}
if (block1 != )
{
++;
if (())
{
++;
}
}
[y << 8 | z << 4 | x] = (char)Block.BLOCK_STATE_IDS.get(state);
}
/**
* Returns the block for a location in a chunk, with the extended ID merged from a byte array and a NibbleArray to
* form a full 12-bit block ID.
*/
public Block getBlockByExtId(int x, int y, int z)
{
return (x, y, z).getBlock();
}
/**
* Returns the metadata associated with the block at the given coordinates in this ExtendedBlockStorage.
*/
public int getExtBlockMetadata(int x, int y, int z)
{
IBlockState iblockstate = (x, y, z);
return ().getMetaFromState(iblockstate);
}
/**
* Returns whether or not this block storage's Chunk is fully empty, based on its internal reference count.
*/
public boolean isEmpty()
{
return == 0;
}
/**
* Returns whether or not this block storage's Chunk will require random ticking, used to avoid looping through
* random block ticks when there are no blocks that would randomly tick.
*/
public boolean getNeedsRandomTick()
{
return > 0;
}
/**
* Returns the Y location of this ExtendedBlockStorage.
*/
public int getYLocation()
{
return ;
}
/**
* Sets the saved Sky-light value in the extended block storage structure.
*/
public void setExtSkylightValue(int x, int y, int z, int value)
{
(x, y, z, value);
}
/**
* Gets the saved Sky-light value in the extended block storage structure.
*/
public int getExtSkylightValue(int x, int y, int z)
{
return (x, y, z);
}
/**
* Sets the saved Block-light value in the extended block storage structure.
*/
public void setExtBlocklightValue(int x, int y, int z, int value)
{
(x, y, z, value);
}
/**
* Gets the saved Block-light value in the extended block storage structure.
*/
public int getExtBlocklightValue(int x, int y, int z)
{
return (x, y, z);
}
public void removeInvalidBlocks()
{
= 0;
= 0;
for (int i = 0; i < 16; ++i)
{
for (int j = 0; j < 16; ++j)
{
for (int k = 0; k < 16; ++k)
{
Block block = (i, j, k);
if (block != )
{
++;
if (())
{
++;
}
}
}
}
}
}
public char[] getData()
{
return ;
}
public void setData(char[] dataArray)
{
= dataArray;
}
/**
* Returns the NibbleArray instance containing Block-light data.
*/
public NibbleArray getBlocklightArray()
{
return ;
}
/**
* Returns the NibbleArray instance containing Sky-light data.
*/
public NibbleArray getSkylightArray()
{
return ;
}
/**
* Sets the NibbleArray instance used for Block-light values in this particular storage block.
*/
public void setBlocklightArray(NibbleArray newBlocklightArray)
{
= newBlocklightArray;
}
/**
* Sets the NibbleArray instance used for Sky-light values in this particular storage block.
*/
public void setSkylightArray(NibbleArray newSkylightArray)
{
= newSkylightArray;
}
}
卸载对应的函数是
/**
* Called when this Chunk is unloaded by the ChunkProvider
*/
public void onChunkUnload()
{
= false;
Iterator iterator = ().iterator();
while (())
{
TileEntity tileentity = (TileEntity)();
(tileentity);
}
for (int i = 0; i < ; ++i)
{
([i]);
}
MinecraftForge.EVENT_BUS.post(new (this));
}
初次生成世界,需要预先加载一部分的块,对应的是Minecraft Server的
protected void initialWorldChunkLoad()
{
boolean flag = true;
boolean flag1 = true;
boolean flag2 = true;
boolean flag3 = true;
int i = 0;
("");
byte b0 = 0;
("Preparing start region for level " + b0);
WorldServer worldserver = (b0);
BlockPos blockpos = ();
long j = getCurrentTimeMillis();
for (int k = -192; k <= 192 && (); k += 16)
{
for (int l = -192; l <= 192 && (); l += 16)
{
long i1 = getCurrentTimeMillis();
if (i1 - j > 1000L)
{
("Preparing spawn area", i * 100 / 625);
j = i1;
}
++i;
(() + k >> 4, () + l >> 4);
}
}
();
}
对应PlayerInstance中的
public void addPlayer(EntityPlayerMP playerMP)
{
if ((playerMP))
{
("Failed to add player. {} already is in chunk {}, {}", new Object[] {playerMP, (), ()});
}
else
{
if (())
{
= ();
}
(playerMP);
Runnable playerRunnable = null;
if ()
{
();
}
else
{
final EntityPlayerMP tmp = playerMP;
playerRunnable = new Runnable()
{
public void run()
{
();
}
};
().(, , playerRunnable);
}
(playerMP, playerRunnable);
}
Chunk加载对应的回调函数
/**
* Called when this Chunk is loaded by the ChunkProvider
*/
public void onChunkLoad()
{
= true;
(());
for (int i = 0; i < ; ++i)
{
Iterator iterator = [i].iterator();
while (())
{
Entity entity = (Entity)();
();
}
(([i]));
}
MinecraftForge.EVENT_BUS.post(new (this));
}